接着上一节的项目文件,新建index.less,同时安装解析器
less
。并且新建loader文件less-loader.js,style-loader.js和css-loader.js
//首先,在webpack配置文件中配置less
{
test: /\.(le|c)ss/,
use: ["style-loader", "css-loader", "less-loader"]
}
//less-loader.js
let less = require("less");
function loader(source){
let css;
less.render(source, (err, r) => { // 这些都是less转义器提供的默认写法
css = r.css;
})
return css;
}
module.exports = loader;
//index.less
@color: red;
body {
background: @color;
}
// index.js中引入index.less
import "./index.less";
//css-loader.js
// css-loade此处我们的css-loader什么也不做,就只让它传递文件
function loader(source){
return source;
}
module.exports = loader;
//style-loader.js
function loader(source) {
// 我们在style-loader中导出一个脚本
let str = `
let style = document.createElement("style");
style.innerHTML = ${JSON.stringify(source)};
document.head.appendChild(style);
`;
return str;
}
module.exports = loader;
执行:
页面中:
image.png
可以看到,能正常的输出结果了。但是css-loader是做什么用的呢?
首先,我们修改index.less文件
@color: red;
body {
background: @color;
background: url(./logo.png); //加一张背景图,图是我提前放好的,么的问题
}
打包:
并没有找到
这是因为less转化时,会把“./logo.png”当成普通字符串,而“url(./logo.png)”这句话的真实含义是,url(require(./lodo.png)),也就是引用文件。所以,我们要以模块的形式解析这句话
// css-loader.js
function loader(source) {
let reg = /url\((.+?)\)/g; // 首先,匹配以url引入的代码
let pos = 0;
let current;
let arr = ["let list = []"];
while ((current = reg.exec(source))) {
//[matchUrl, g]
let [matchUrl, g] = current;
let last = reg.lastIndex - matchUrl.length; //拿到url的“u”index
arr.push(`list.push(${JSON.stringify(source.slice(pos, last))})`);将字面量“url...”之前的内容先以字符串拿到
pos = reg.lastIndex; //初始位置变成url的字符串index
arr.push(`list.push('url('+require(${g})+')')`); // 将普通css改为“url(require('./logo.png'))”
}
arr.push(`list.push(${JSON.stringify(source.slice(pos))})`); //将“url('./logo.png')”后边的内容以字符串传入
arr.push(`module.exports = list.join('')`); // 导出这个大段字符串
console.log(arr.join("\r\n"));
return source;
}
module.exports = loader;
以上,css-loader将index.less文件拆成了一个字符串,并且将url这种引入方式做了些修改,接着我们要来完善style-loader.js了。
说到这里,之前的博文什么是loader?粗略的讲了下pitchLoader--正常顺序(与文档流一致)写的loader,如果有返回值,那么不会执行后续的loader,或者加载资源
// style-loader.js
function loader(source) {
// 我们在style-loader中导出一个脚本
let str = `
let style = document.createElement("style");
style.innerHTML = ${JSON.stringify(source)};
document.head.appendChild(style);
`;
return str;
}
// 在style-loader上写了pitch
loader.pitch = function(remainingRequest) { // 在webpack配置中,style-loader是第一个loader,所以css-loader...都在它后边
//剩余的请求
// 让style-loader去处理less-loader!css-loader ./index.less
console.log(remainingRequest);
};
module.exports = loader;
执行
可以看到,打印出了后续的操作(当然,这不会这行),继续改写style-loader
// style-loader.js
let loaderUtils = require("loader-utils");
function loader(source) {
// 我们在style-loader中导出一个脚本
let str = `
let style = document.createElement("style");
style.innerHTML = ${JSON.stringify(source)};
document.head.appendChild(style);
`;
return str;
}
// 在style-loader上写了pitch
loader.pitch = function(remainingRequest) {
//剩余的请求
// 让style-loader去处理less-loader!css-loader ./index.less
let str = `
let style = document.createElement("style");
style.innerHTML = require(${loaderUtils.stringifyRequest(
this,
"!!" + remainingRequest
)});
document.head.appendChild(style);
`; // require()返回的就是css-loader处理后的结果,stringifyRequest会把绝对路径转化为相对路径,而“!!”前边提到过,意思是只使用这个行内loader
return str;
};
module.exports = loader;
网友评论