執行 npm run dev 命令后 , 入口配置為 package.json , 代碼片段如下 :
{ ... "script":{ "dev": "vue-cli-service serve", ... }, ... }
根據package.json中的內容 , 執行./node_modules/.bin/vue-cli-service , 里面代碼片段如下 :
node "%~dp0\..\@vue\cli-service\bin\vue-cli-service.js"
上面代碼片段中 , 可以看到執行了 node命令運行 vue-cli-service.js , 找到 ./node_modules/@vue/cli-service/bin/vue-cli-service.js 這個node入口, 代碼片段如下
const Service = require('../lib/Service') const service = new Service(process.env.VUE_CLI_CONTEXT || process.cwd()) //... ... ... // 執行service方法傳入:'serve'、agrs、['serve','--open',...] service.run(command, args, rawArgv).catch(err => { error(err) process.exit(1) })
上面代碼實例化了 Service類並執行run方法 ; 其中 Service類來自 node_modules\@vue\cli-service\lib\Service.js , 代碼片段如下
// ... ... module.exports = class Service { //構造函數 , 初始化配置 constructor(context, { plugins, pkg, inlineOptions, useBuiltIn } = {}) { ... // 獲取package.json中的依賴 this.pkg = this.resolvePkg(pkg) //初始化相關插件。相關插件包括:內聯插件、package.json中的cli-plugin-*插件。內聯插件包含serve、build、inspect等。 // 如果有內聯插件,不使用package.json中找到的插件 // 最終得到的plugins為內置插件+@vue/cli-plugin-* // {id: 'xxx',apply: require('xxx')} this.plugins = this.resolvePlugins(plugins, useBuiltIn) // 解析每個命令使用的默認模式 //{ serve: 'development', // build: 'production', // inspect: 'development' } this.modes = this.plugins.reduce((modes, { apply: { defaultModes }}) => { return Object.assign(modes, defaultModes) }, {}) } resolvePkg (inlinePkg, context = this.context) {...} init (mode = process.env.VUE_CLI_MODE) {...} loadEnv (mode){...} setPluginsToSkip (args) {...} resolvePlugins (inlinePlugins, useBuiltIn){...} async run (name, args = {}, rawArgv = []){ ... //name=serve ; 執行 /node_modules/@vue/cli-service/lib/commands/serve.js let command = this.commands[name] ... const { fn } = command return fn(args, rawArgv) } resolveChainableWebpackConfig () {...} resolveWebpackConfig (chainableConfig = this.resolveChainableWebpackConfig()){...} //加載用戶配置。讀取vue.config.js文件內部的配置 loadUserOptions () { const possibleConfigPaths = [ process.env.VUE_CLI_SERVICE_CONFIG_PATH, './vue.config.js', './vue.config.cjs' ] ... } }
最終執行的node_modules/@vue/cli-service/lib/commands/serve.js 內注冊serve時傳遞的方法。
webpack獲取到配置之后,實例化Compiler 傳遞給webpackDevServer,通過webpackDevServer實現自動編譯和熱更新。
// serve.js serve函數 async function serve (args) { //創建webpack編譯器 const compiler = webpack(webpackConfig) // compiler.run()即可完成一次編譯打包 // 創建本地服務 const server = new WebpackDevServer(compiler, Object.assign({ clientLogLevel: 'none', historyApiFallback: { disableDotRule: true, rewrites: [ { from: /./, to: path.posix.join(options.baseUrl, 'index.html') } ] }, contentBase: api.resolve('public'), watchContentBase: !isProduction, hot: !isProduction, quiet: true, compress: isProduction, publicPath: options.baseUrl, overlay: isProduction // TODO disable this ? false : { warnings: false, errors: true } }, projectDevServerOptions, { https: useHttps, proxy: proxySettings, })) return new Promise((resolve, reject) => { compiler.hooks.done.tap('vue-cli-service serve', stats => { // ... }) // ... server.listen(port, host, err => { if (err) { reject(err) } }) }) }