代碼地址:vue2.5.0
參考資料:
- Vue源碼探祕系列
- Vue.js 技術揭祕
Flow
在 Vue.js
的主目錄下有 .flowconfig
文件, 它是 flow
的配置文件。其中的[libs]
用來描述包含指定庫定義的目錄,這裏指向的是項目根目錄下的flow
文件夾。打開此目錄,可以發現文件結構如下:
flow
├── compiler.js # 編譯相關
├── component.js # 組件數據結構
├── global-api.js # Global API 結構
├── modules.js # 第三方庫定義
├── options.js # 選項相關
├── ssr.js # 服務端渲染相關
├── vnode.js # 虛擬 node 相關
Vue源碼目錄設計
-
complier
├── compiler # 模板解析相關 ├── codegen # 代碼生成,把 AST(抽象語法樹)轉換爲 render 函數 ├── directives # 轉換爲 render 函數前要執行的指令 ├── parser # 把模板解析爲 AST
-
core
├── core # Vue 核心代碼 ├── components # 全局通用組件 Keep-Alive ├── global-api # 全局 api,即 Vue 對象上的方法,如 extend,mixin,use 等 ├── instance # Vue 實例化相關代碼,如初始化,事件,渲染,生命週期等 ├── observer # 響應式數據修改代碼 ├── util # 工具函數 ├── vdom # 虛擬 DOM 相關代碼
-
platforms
├── platforms # 平臺相關代碼 ├── web # web 平臺 ├── compiler # 編譯時相關 ├── runtime # 運行時相關 ├── server # 服務端渲染相關 ├── util # 工具函數 ├── weex # 配合 weex 運行在 native 平臺
Rollup構建Vue
Webpack
功能相比 Rollup
更加強大,它可以將各種靜態資源(包括 css
,js
,圖片
等)通通打包成一個或多個 bundle
,並按需加載;同時正因爲 Webpack
功能強大,打包出來的文件體積也較大。因此 Webpack
更適用於應用的開發。而 Rollup
相對於 Webpack
更加輕量,它只處理 js
文件而不處理其他靜態資源文件,打包出來的文件體積也更小,因此 Rollup
更適用於像類庫這種只有 js
代碼的項目構建。所以大部分類庫例如 Vue
,React
,Angular
等都採用 Rollup
來打包。
打包vue的命令在package.json
的script
下:
{
"build": "node scripts/build.js",
"build:ssr": "npm run build -- web-runtime-cjs,web-server-renderer",
"build:weex": "npm run build -- weex",
}
build
構建 web 平臺相關build:ssr
構建服務端渲染相關build:weex
構建的是weex
平臺相關。
接下來學習build.js
文件:
// scripts/build.js
// 引入所需模塊
const fs = require('fs')
const path = require('path')
const zlib = require('zlib')
const rollup = require('rollup')
const terser = require('terser')
// 檢查是否存在dist目錄,不存在則創建dist目錄
if (!fs.existsSync('dist')) {
fs.mkdirSync('dist')
}
[1]
let builds = require('./config').getAllBuilds()
[2]
// filter builds via command line arg
if (process.argv[2]) {
const filters = process.argv[2].split(',')
builds = builds.filter(b => {
return filters.some(f => b.output.file.indexOf(f) > -1 || b._name.indexOf(f) > -1)
})
} else {
// filter out weex builds by default
builds = builds.filter(b => {
return b.output.file.indexOf('weex') === -1
})
}
build(builds)
// build函數聲明
function build (builds) {
}
// scripts/config.js
if (process.env.TARGET) {
module.exports = genConfig(process.env.TARGET)
} else {
exports.getBuild = genConfig
exports.getAllBuilds = () => Object.keys(builds).map(genConfig)
}
[1] 這裏 getAllBuilds
函數的處理是取出 builds
對象的所有屬性組成的數組在 genConfig
函數處理後返回。即把builds裏面的配置對象轉換爲一個Rollup對應需要的配置項並返。
[2] 通過判斷是否有額外的命令參數判斷是那條命令,並對builds數組做對應的過濾處理,把不需要Rollup配置項過濾掉。
最後build
函數其實就是讓 builds
數組每一項都執行 buildEntry
這個函數,這裏 buildEntry
函數調用了 rollup.rollup
進行編譯,最終得到一個結果 output
,然後判斷這個 output
是否是生產版本來決定是否壓縮,然後調用 write
函數。write
函數的作用就是調用 fs.writeFile
生成對應的 js
文件放在 dist
目錄下。
總結
學習了flow,vue源碼的編寫依靠flow來進行類型斷言,確保了編譯的嚴謹性;因爲Rollup比webpack輕量,專門打包js,所以vue、react等框架都使用了Rollup;在vue中,通過運行build.js文件,將各個函數處理成rollup對應需要的配置項,且根據不同環境判斷是否要壓縮。