Vue編譯器解析compile源碼解析
引言
在上篇文章 Vue編譯器源碼分析compileToFunctions作用中我們介紹到了,在 compileToFunctions 方法中:
// compile var compiled = compile(template, options);
而真正的編譯工作是依托于 compile 函數(shù),接下來(lái)我們?cè)敿?xì)解析 compile 。
解析 compile
上述代碼在調(diào)用 compile ,其中模板字符串 template ,選項(xiàng)參數(shù) options 第二個(gè)參數(shù)傳遞給 compile 函數(shù),在章節(jié)三種我們知道,這里傳遞過(guò)去的options如下:
{
shouldDecodeNewlines,
shouldDecodeNewlinesForHref,
delimiters,
comments,
warn
}
compile 源碼
接下來(lái)我們看下 compile 的源碼。
function createCompilerCreator(baseCompile) {
return function createCompiler(baseOptions) {
function compile(
template,
options
) {
var finalOptions = Object.create(baseOptions);
var errors = [];
var tips = [];
finalOptions.warn = function(msg, tip) {
(tip ? tips : errors).push(msg);
};
if (options) {
// merge custom modules
if (options.modules) {
finalOptions.modules =
(baseOptions.modules || []).concat(options.modules);
}
// merge custom directives
if (options.directives) {
finalOptions.directives = extend(
Object.create(baseOptions.directives || null),
options.directives
);
}
// copy other options
for (var key in options) {
if (key !== 'modules' && key !== 'directives') {
finalOptions[key] = options[key];
}
}
}
var compiled = baseCompile(template, finalOptions); {
errors.push.apply(errors, detectErrors(compiled.ast));
}
compiled.errors = errors;
compiled.tips = tips;
return compiled
}
return {
compile: compile,
compileToFunctions: createCompileToFunctionFn(compile)
}
}
}
·首先可以看到:
var finalOptions = Object.create(baseOptions);
配置選項(xiàng)
finalOptions 所有的配置選項(xiàng)最終都會(huì)掛載在這個(gè)對(duì)象上,baseOptions包含編譯器在運(yùn)作的時(shí)候所需的配置選項(xiàng)。
var baseOptions = {
expectHTML: true,
modules: modules$1,
directives: directives$1,
isPreTag: isPreTag,
isUnaryTag: isUnaryTag,
mustUseProp: mustUseProp,
canBeLeftOpenTag: canBeLeftOpenTag,
isReservedTag: isReservedTag,
getTagNamespace: getTagNamespace,
staticKeys: genStaticKeys(modules$1)
};
屬性分別解析
- 第一個(gè)屬性: expectHTML 被設(shè)置為 true 。
- 第二個(gè)屬性:modules
var modules$1 = [
klass$1,
style$1,
model$1
];
var klass$1 = {
staticKeys: ['staticClass'],
transformNode: transformNode,
genData: genData
};
var style$1 = {
staticKeys: ['staticStyle'],
transformNode: transformNode$1,
genData: genData$1
};
var model$1 = {
preTransformNode: preTransformNode
};
我們用到了在細(xì)講。
- 第三個(gè)屬性:directives 值是三個(gè)屬性 (model、text、html) 的對(duì)象,且屬性的值都是函數(shù)。
- 第四個(gè)屬性:isPreTag 它是一個(gè)函數(shù),其作用是通過(guò)給定的標(biāo)簽名字檢查標(biāo)簽是否是 'pre' 標(biāo)簽。
- 第五個(gè)屬性:isUnaryTag 是一個(gè)通過(guò)
makeMap生成的函數(shù),該函數(shù)的作用是檢測(cè)給定的標(biāo)簽是否是一元標(biāo)簽。 - 第六個(gè)屬性:mustUseProp 它是一個(gè)函數(shù),其作用是用來(lái)檢測(cè)一個(gè)屬性在標(biāo)簽中是否要使用
props進(jìn)行綁定。 - 第七個(gè)屬性:canBeLeftOpenTag 一個(gè)使用makeMap生成的函數(shù),它的作用是檢測(cè)非一元標(biāo)簽,但卻可以自己補(bǔ)全并閉合的標(biāo)簽。比如 div 標(biāo)簽是一個(gè)雙標(biāo)簽,你需要這樣使用<div> text </div>,但是你依然可以省略閉合標(biāo)簽,直接這樣寫:<div> text ,且瀏覽器會(huì)自動(dòng)補(bǔ)全。但是有些標(biāo)簽?zāi)悴豢梢赃@樣用,它們是嚴(yán)格的雙標(biāo)簽。
- 第八個(gè)屬性:isReservedTag 它是一個(gè)函數(shù),其作用是檢查給定的標(biāo)簽是否是保留的標(biāo)簽。
- 第九個(gè)屬性:getTagNamespace 它也是一個(gè)函數(shù),其作用是獲取元素(標(biāo)簽)的命名空間。
- 第十個(gè)屬性:staticKeys 它的值是通過(guò)以 modules 為參數(shù)調(diào)用 genStaticKeys 函數(shù)的返回值得到的。 其作用是根據(jù)編譯器選項(xiàng)的 modules 選項(xiàng)生成一個(gè)靜態(tài)鍵字符串。
現(xiàn)在我們粗略的介紹了下baseOptions 中各個(gè)屬性的作用,當(dāng)我們用到時(shí)候再來(lái)詳細(xì)講解他們的源碼。
繼續(xù)往下看:
var errors = [];
var tips = [];
finalOptions.warn = function(msg, tip) {
(tip ? tips : errors).push(msg);
};
很簡(jiǎn)單
finalOptions添加warn 方法
在 finalOptions上添加了 warn 方法,該方法接收兩個(gè)參數(shù):
- msg 錯(cuò)誤或提示的信息
- tip 用來(lái)標(biāo)示 msg 是錯(cuò)誤還是提示。
warn選項(xiàng)主要用在編譯過(guò)程中的錯(cuò)誤和提示收集,如果收集的信息是錯(cuò)誤信息就將錯(cuò)誤信息添加到前面定義的errors數(shù)組里,如果是提示信息就將其添加到 tips 數(shù)組里。
繼續(xù):
if (options) {
// merge custom modules
if (options.modules) {
finalOptions.modules =
(baseOptions.modules || []).concat(options.modules);
}
// merge custom directives
if (options.directives) {
finalOptions.directives = extend(
Object.create(baseOptions.directives || null),
options.directives
);
}
// copy other options
for (var key in options) {
if (key !== 'modules' && key !== 'directives') {
finalOptions[key] = options[key];
}
}
}
這段代碼檢查 options 是否存在,這里的 options 就是使用編譯器編譯模板時(shí)傳遞的選項(xiàng)參數(shù),或者可以簡(jiǎn)單理解為調(diào)用 compileToFunctions 函數(shù)時(shí)傳遞的選項(xiàng)參數(shù)。
而baseOptions理解為編譯器的默認(rèn)選項(xiàng)或者基本選項(xiàng),options 是用來(lái)提供定制能力的擴(kuò)展選項(xiàng)。而上面這段代碼的作用,就是將 options 對(duì)象混合到 finalOptions 中。
兩個(gè)特殊的屬性處理
- modules: 如果 options.modules 存在,就在 finalOptions 對(duì)象上添加 modules 屬性,其值為 baseOptions.modules 和 options.modules 這兩個(gè)數(shù)組合并后的新數(shù)組。
- directives: 對(duì)于directives 采用原型鏈的原理實(shí)現(xiàn)擴(kuò)展屬性對(duì)基本屬性的覆蓋。
繼續(xù):
var compiled = baseCompile(template, finalOptions); {
errors.push.apply(errors, detectErrors(compiled.ast));
}
compiled.errors = errors;
compiled.tips = tips;
上面的代碼調(diào)用了 baseCompile 函數(shù),并分別將字符串模板(template),以及最終的編譯器選項(xiàng)(finalOptions)傳遞了過(guò)去。
compiled 是 baseCompile 對(duì)模板的編譯結(jié)果所以上面這段代碼的作用是用來(lái)通過(guò)抽象語(yǔ)法樹(shù)來(lái)檢查模板中是否存在錯(cuò)誤表達(dá)式的,通過(guò) detectErrors 函數(shù)實(shí)現(xiàn),將compiled.ast 作為參數(shù)傳遞給 detectErrors 函數(shù),該函數(shù)最終返回一個(gè)數(shù)組,該數(shù)組中包含了所有錯(cuò)誤的收集,最終通過(guò)這句代碼將錯(cuò)誤添加到errors。
將收集到的錯(cuò)誤(errors)和提示(tips)添加到compiled上并返回。
baseCompile 函數(shù)是在 createCompilerCreator 函數(shù)調(diào)用時(shí)傳遞的實(shí)參。
// `createCompilerCreator` allows creating compilers that use alternative
// parser/optimizer/codegen, e.g the SSR optimizing compiler.
// Here we just export a default compiler using the default parts.
var createCompiler = createCompilerCreator(function baseCompile(
template,
options
) {
var ast = parse(template.trim(), options);
if (options.optimize !== false) {
optimize(ast, options);
}
var code = generate(ast, options);
return {
ast: ast,
render: code.render,
staticRenderFns: code.staticRenderFns
}
});
從Vue編譯器源碼分析(一) 到 Vue編譯器源碼分析(四) 我們已經(jīng)把編譯器整體代碼組織的結(jié)構(gòu)講分析了。
從下章節(jié)開(kāi)始,就正式的進(jìn)入到Vue編譯器詞法分析階段,去看下模板對(duì)應(yīng)的AST(抽象語(yǔ)法樹(shù))是怎么形成的。
以上就是Vue編譯器解析compile源碼解析的詳細(xì)內(nèi)容,更多關(guān)于Vue編譯器compile解析的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue自動(dòng)路由-單頁(yè)面項(xiàng)目(非build時(shí)構(gòu)建)
這篇文章主要介紹了vue自動(dòng)路由-單頁(yè)面項(xiàng)目(非build時(shí)構(gòu)建),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-04-04
python虛擬環(huán)境 virtualenv的簡(jiǎn)單使用
virtualenv是一個(gè)創(chuàng)建隔絕的Python環(huán)境的工具。這篇文章主要介紹了python虛擬環(huán)境 virtualenv的簡(jiǎn)單使用,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01
解決iview table組件里的 固定列 表格不自適應(yīng)的問(wèn)題
這篇文章主要介紹了解決iview table組件里的 固定列 表格不自適應(yīng)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11
Vue3報(bào)錯(cuò)‘defineProps‘?is?not?defined的解決方法
最近工作中遇到vue3中使用defineProps中報(bào)錯(cuò),飄紅,所以這篇文章主要給大家介紹了關(guān)于Vue3報(bào)錯(cuò)‘defineProps‘?is?not?defined的解決方法,需要的朋友可以參考下2023-01-01
Vue3中使用echarts的簡(jiǎn)單七個(gè)步驟(易懂,附緊急避坑)
近期在做一個(gè)vue3的項(xiàng)目,里面有個(gè)圖表需求,因公司之前使用第三方封裝的圖表缺少文檔,就去看了echars的官網(wǎng)文檔,引入原生echars來(lái)實(shí)現(xiàn),下面這篇文章主要給大家介紹了關(guān)于Vue3中使用echarts的簡(jiǎn)單七個(gè)步驟,需要的朋友可以參考下2023-01-01
vue使用prop可以渲染但是打印臺(tái)報(bào)錯(cuò)的解決方式
今天小編就為大家分享一篇vue使用prop可以渲染但是打印臺(tái)報(bào)錯(cuò)的解決方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11
基于vue 實(shí)現(xiàn)表單中password輸入的顯示與隱藏功能
這篇文章主要介紹了vue 實(shí)現(xiàn)表單中password輸入的顯示與隱藏功能 ,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-07-07
axios對(duì)請(qǐng)求各種異常情況處理的封裝方法
今天小編就為大家分享一篇axios對(duì)請(qǐng)求各種異常情況處理的封裝方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-09-09

