原文地址:http://hiihl.com/articles/2018/1/17/lessloader.md
本篇是Webpack Loader源碼導(dǎo)讀系列中關(guān)于less-loader的解讀,主要闡述loader的工作,less編譯部份的內(nèi)容未來將單獨講解。
源碼結(jié)構(gòu)
源碼 v4.0.5,src目錄如下:
src
|____cjs.js
|____createWebpackLessPlugin.js
|____formatLessError.js
|____getOptions.js
|____index.js
|____processResult.js
|____removeSourceMappingUrl.js
|____stringifyLoader.js
options說明
進(jìn)入index.js首先看到的是getOptions(loaderContext)
,這一步的作用是將webpack相關(guān)配置及l(fā)oader的query或options部份配置合并,得到編譯過程的可選項
- paths 模塊解析的路徑,默認(rèn)使用webpack的resolver,必須是個絕對路徑數(shù)組;舉例,在less中我們想引用node_modules下bootstrap的less文件,可以這樣寫
@import "~bootstrap/less/bootstrap";
,默認(rèn)的模塊解析將和webpack一致,但如果loader配置paths,則webpack的解析路徑和alias配置在這里將無效。 - plugins 數(shù)組,編譯時使用的插件,已有的插件見plugins
- sourceMap 源碼映射,需要同css-loader一同配置;可以是boolean類型,也可以是對象,sourceMap相關(guān)配置如下:
- {String} sourceMapFilename,對應(yīng)lessc中屬性值為String的--source-map選項;
- {String} sourceMapRootPath,對應(yīng)lessc的--source-map-rootpath選項;
- {String} sourceMapURL,對應(yīng)lessc的--source-map-url選項;
- {String} sourceMapBasePath,對應(yīng)lessc的--source-map-basepath選項;
- {Boolean} sourceMapLessInline 對應(yīng)lessc的--source-map-less-inline選項;
- {Boolean} sourceMapMapInline 對應(yīng)lessc的--source-map-map-inline選項;
- {Boolean} outputSourceFiles 對應(yīng)lessc的--source-map-map-inline選項;注意
在less-loader中會將該值默認(rèn)設(shè)置成true
。
less-loader其他的配置,都可以從less的配置選項中找到,全部轉(zhuǎn)成駝峰式即可。
有兩個重要的配置globalVars
和modifyVars
,這兩個是用于添加或修改less變量的,一起看個例子。
main.less
@import "./other.less";
.box:extend(.hotpink) {
width: @boxWidth;
height: @boxHeight;
}
other.less
@boxHeight: 10px;
.hotpink {
background: hotpink;
width: @boxWidth;
}
上面的例子中,other.less中定義了變量@boxHeight在main.less中會使用到,值為10px;main.less和other.less中都使用到了@boxWidth,但是并沒有定義;
現(xiàn)在我們在webpack.config.js中配置
{
loader: "less-loader",
query: {
sourceMap: true,
globalVars: {
"boxWidth": '200px'
},
modifyVars: {
"boxHeight": '200px'
}
}
}
最后編譯沒有出錯,結(jié)果為
.hotpink,
.box {
background: hotpink;
width: 200px;
}
.box {
width: 200px;
height: 200px;
}
在這個例子中,globalVars的作用相當(dāng)于給每個less文件頂部
增加一行@boxWidth: 200px
,所以編譯出來的width都為200px,而modifyVars的作用相當(dāng)于在
每個文件底部
增加一行@boxHeight: 200px
,這樣就會覆蓋已有的@boxHeight: 10px
,所以最后編譯出來的height是200px而不是10px;
這有什么作用呢?
有了這兩個配置項,我們就可以把部份樣式抽出變量,通過不同的變量組合成不同的主題,例如:
default.less
@primary-color: #003cee;
themes/pink.js
module.exports = {
"@primary-color": 'pink'
};
webpack.config.js
{
loader: 'less-loader',
query: {
modifyVars: require('./themes/pink')
}
}
loader中解析了配置以后,就直接調(diào)用了less的render方法進(jìn)行編譯,render方法有三個入?yún)?code>var render = function (input, options, callback),
第三個參數(shù)是個callback,看render.js源碼可以知道,如果不傳callback,則render方法會返回一個promise。
編譯結(jié)果處理
看下processResult.js如何處理編譯結(jié)果,resultPromise就是前面提到的render返回的promise。
function processResult(loaderContext, resultPromise) {
const { callback } = loaderContext;
resultPromise
.then(({ css, map, imports }) => {
imports.forEach(loaderContext.addDependency, loaderContext);
return {
// Removing the sourceMappingURL comment.
// See removeSourceMappingUrl.js for the reasoning behind this.
css: removeSourceMappingUrl(css),
map: typeof map === 'string' ? JSON.parse(map) : map,
};
}, (lessError) => {
throw formatLessError(lessError);
})
.then(({ css, map }) => {
callback(null, css, map);
}, callback);
}
編譯后的結(jié)果包括css,map和imports三個,css是less編譯成的css內(nèi)容,map則是sourceMap相關(guān)信息,imports是編譯過程中所有的依賴文件路徑。
拿到編譯結(jié)果后,首先是調(diào)用addDependency把所有imports中的文件添加到依賴?yán)锩?,這個方法的作用時在watch模式時,依賴的這些文件變化時會出發(fā)編譯更新。
然后是removeSourceMappingUrl(css)
,這個方法的作用是移除結(jié)果中的sourceMappingURL=
,理由是less-loader無法知道最終的sourceMap會在哪里。
最后調(diào)用callback(null, css, map)
把結(jié)果傳給下一個loader去執(zhí)行,less-loader的的工作就完成了。
下一篇我們將繼續(xù)將css-loader,如何繼續(xù)處理less-loader編譯出來的結(jié)果。