原文地址:hiihl.com/articles/20…css
本篇是Webpack Loader源碼導讀系列中關於less-loader的解讀,主要闡述loader的工做,less編譯部份的內容將來將單獨講解。node
源碼 v4.0.5,src目錄以下:webpack
src
|____cjs.js
|____createWebpackLessPlugin.js
|____formatLessError.js
|____getOptions.js
|____index.js
|____processResult.js
|____removeSourceMappingUrl.js
|____stringifyLoader.js
複製代碼
進入index.js首先看到的是getOptions(loaderContext)
,這一步的做用是將webpack相關配置及loader的query或options部份配置合併,獲得編譯過程的可選項git
@import "~bootstrap/less/bootstrap";
,默認的模塊解析將和webpack一致,但若是loader配置paths,則webpack的解析路徑和alias配置在這裏將無效。在less-loader中會將該值默認設置成true
。less-loader其餘的配置,均可以從less的配置選項中找到,所有轉成駝峯式便可。github
有兩個重要的配置globalVars
和modifyVars
,這兩個是用於添加或修改less變量的,一塊兒看個例子。web
main.lessbootstrap
@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,可是並無定義; 如今咱們在webpack.config.js中配置promise
{
loader: "less-loader",
query: {
sourceMap: true,
globalVars: {
"boxWidth": '200px'
},
modifyVars: {
"boxHeight": '200px'
}
}
}
複製代碼
最後編譯沒有出錯,結果爲bash
.hotpink,
.box {
background: hotpink;
width: 200px;
}
.box {
width: 200px;
height: 200px;
}
複製代碼
在這個例子中,globalVars的做用至關於給每一個less文件頂部
增長一行@boxWidth: 200px
,因此編譯出來的width都爲200px,而modifyVars的做用至關於在 每一個文件底部
增長一行@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中解析了配置之後,就直接調用了less的render方法進行編譯,render方法有三個入參var render = function (input, options, callback)
, 第三個參數是個callback,看render.js源碼能夠知道,若是不傳callback,則render方法會返回一個promise。
看下processResult.js如何處理編譯結果,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);
}
複製代碼
編譯後的結果包括css,map和imports三個,css是less編譯成的css內容,map則是sourceMap相關信息,imports是編譯過程當中全部的依賴文件路徑。 拿到編譯結果後,首先是調用addDependency把全部imports中的文件添加到依賴裏面,這個方法的做用時在watch模式時,依賴的這些文件變化時會出發編譯更新。 而後是removeSourceMappingUrl(css)
,這個方法的做用是移除結果中的sourceMappingURL=
,理由是less-loader沒法知道最終的sourceMap會在哪裏。 最後調用callback(null, css, map)
把結果傳給下一個loader去執行,less-loader的的工做就完成了。
下一篇咱們將繼續將css-loader,如何繼續處理less-loader編譯出來的結果。