學(xué)習(xí)目標(biāo):
一绳慎、理解Runtime + Compiler vs. Runtime-only
二姨蝴、如何設(shè)置Runtime + Compiler 和Runtime-only環(huán)境
三鱼喉、理解源碼實現(xiàn)原理
理解Runtime + Compiler vs. Runtime-only
一虐秋、如果你需要在客戶端編譯模板 (比如傳入一個字符串給 template 選項窍帝,或掛載到一個元素上并以其 DOM 內(nèi)部的 HTML 作為模板)努潘,就將需要加上編譯器
// 需要編譯器
new Vue({
template: '<div>{{ hi }}</div>'
})
二、vue-loader 或 vueify 的時候盯桦,*.vue 文件內(nèi)部的模板會在構(gòu)建時預(yù)編譯成 JavaScript慈俯,則不需要編譯器
// 不需要編譯器
new Vue({
render (h) {
return h('div', this.hi)
}
})
環(huán)境設(shè)置
環(huán)境默認是 Runtime-only,vue指向的是'vue/dist/vue.runtime.esm.js'
如果想要用有編譯器的模式的話拥峦,操作如下:
1.在根目錄下增加一個vue.config.js
2.vue.config.js的內(nèi)容是:
module.exports = {
runtimeCompiler:true
}
問題(理解源碼實現(xiàn)原理)
1.vue.config.js 為什么是這個文件名贴膘?
2.runtimeCompiler:true這個開關(guān)屬性是如何控制用編譯器文件的?
問題1:vue.config.js 為什么是這個文件名略号?
查看Service.js文件:
. 這里的loadUserOptions函數(shù)就是用來處理vue.config.js的對象屬性的
. 可以看到這個文件中用到vue.config.js或vue.config.cjs這個名字
loadUserOptions () {
// vue.config.c?js
let fileConfig, pkgConfig, resolved, resolvedFrom
const esm = this.pkg.type && this.pkg.type === 'module'
const possibleConfigPaths = [
process.env.VUE_CLI_SERVICE_CONFIG_PATH,
'./vue.config.js',
'./vue.config.cjs'
]
let fileConfigPath
for (const p of possibleConfigPaths) {
const resolvedPath = p && path.resolve(this.context, p)
if (resolvedPath && fs.existsSync(resolvedPath)) {
fileConfigPath = resolvedPath
break
}
}
......
return resolved
}
上面的return resolved的最后結(jié)果顯示為:
{runtimeCompiler:true}
問題2.runtimeCompiler:true這個開關(guān)屬性是如何控制用編譯器文件的刑峡?
打開文件base.js
webpackConfig.resolve
.alias
.set(
'vue$',
options.runtimeCompiler
? 'vue/dist/vue.esm.js'
: 'vue/dist/vue.runtime.esm.js'
)
上面代碼可以看到options.runtimeCompiler如果為true,則用到的是有編輯器的文件'vue/dist/vue.esm.js'玄柠,否則用到的是runtime即'vue/dist/vue.runtime.esm.js'
問題
現(xiàn)在問題是如何確定options.runtimeCompiler中的options對象中的runtimeCompiler就是vue.config.js文件中的runtimeCompiler
1.查看Service.js
init (mode = process.env.VUE_CLI_MODE) {
......
// load user config
const userOptions = this.loadUserOptions()
this.projectOptions = defaultsDeep(userOptions, defaults())
......
// apply plugins.
this.plugins.forEach(({ id, apply }) => {
if (this.pluginsToSkip.has(id)) return
apply(new PluginAPI(id, this), this.projectOptions)
})
}
上面代碼我們知道loadUserOptions函數(shù)最后返回的就是vue.config.js中的對象
const { defaults, validate } = require('./options')
defaults得到的是./options中的返回對象值
this.projectOptions = defaultsDeep(userOptions, defaults())
this.projectOptions就是把vue.config.js+(./options.js的default)合并到一起的對象即是:
{
runtimeCompiler: true,
publicPath: '/',
outputDir: 'dist',
assetsDir: '',
indexPath: 'index.html',
filenameHashing: true,
transpileDependencies: [],
productionSourceMap: true,
parallel: true,
pages: undefined,
crossorigin: undefined,
integrity: false,
css: {},
lintOnSave: 'default',
devServer: {}
}
// apply plugins.
this.plugins.forEach(({ id, apply }) => {
if (this.pluginsToSkip.has(id)) return
apply(new PluginAPI(id, this), this.projectOptions)
})
其中apply(new PluginAPI(id, this), this.projectOptions)表示執(zhí)行this.plugins的函數(shù)突梦,其中就包含base.js的文件,參數(shù)一個是api,一個是options
module.exports = (api, options) => {
......
webpackConfig.resolve
.alias
.set(
'vue$',
options.runtimeCompiler
? 'vue/dist/vue.esm.js'
: 'vue/dist/vue.runtime.esm.js'
)
.......
}
this.projectOptions也就是合并到一起的對象故這里的options.runtimeCompiler中的runtimeCompiler屬性也就是vue.config.js中的runtimeCompiler