前言
Service
的run函數其實很簡單,但是第一次看會有點懵
代碼很簡單,主要做了幾件事:
- 確定命令的運行模式
const mode = args.mode || (name === 'build' && args.watch ? 'development' : this.modes[name])
- 設置可忽略的插件
this.setPluginsToSkip(args)
- 初始化
this.init(mode)
- 獲取到命令行實體
let command = this.commands[name]
- 運行命令行
...
return fn(args, rawArgv)
主要比較懵的是第四點和第五點 這就要涉及到另外一個類\@vue\cli-service\lib\PluginAPI.js
PluginAPI.js
PluginAPI其實可以理解成為插件的基類,它主要是定義了插件加載時候可用的函數。
在init
代碼中有這么一段:
// apply plugins.
this.plugins.forEach(({ id, apply }) => {
if (this.pluginsToSkip.has(id)) return
apply(new PluginAPI(id, this), this.projectOptions)
})
我們在構造函數中整理了plugins列表后,真正把pluginsId轉換為command的其實是上面的代碼
以serve指令為例
我們可以看到serve的export代碼:
//serve,js
module.exports = (api, options) => {
api.registerCommand(
...
)
}
實際上其他指令
build
,help
,inspect
的exports都是一樣帶有兩個參數的函數
接下來我們看看PluginAPI
的registerCommand
方法
registerCommand (name, opts, fn) {
if (typeof opts === 'function') {
fn = opts
opts = null
}
this.service.commands[name] = { fn, opts: opts || {}}
}
所以第四點和第五點的commands
和fn
就是通過這個函數來的。
接下來我們看看serve
的fn
具體做了什么:
- 對一些值進行初始化(http協議的選擇,url的組成,proxy等等)
...
// resolve server options
const useHttps = args.https || projectDevServerOptions.https || defaults.https
const protocol = useHttps ? 'https' : 'http'
const host = args.host || process.env.HOST || projectDevServerOptions.host || defaults.host
portfinder.basePort = args.port || process.env.PORT || projectDevServerOptions.port || defaults.port
const port = await portfinder.getPortPromise()
const rawPublicUrl = args.public || projectDevServerOptions.public
...
- 創建一個webpack的compiler
- 初始化webpack-dev-server
webpack-dev-server一個小型的nodejs靜態文件服務器,它可以在compiler生成資源文件后提供Web服務
- 把通過webpack生成的目錄文件通過webpack-dev-server發布,並監聽變化。
以上就是npm run server
的主要流程。
從上面可以看到核心是在webpack compiler
和webpack-dev-server
所以接下來會進行研究webpack。