原文地址: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编译出来的结果。