美文网首页webpack
实现less-loader和style-loader

实现less-loader和style-loader

作者: 成熟稳重的李先生 | 来源:发表于2019-07-21 16:26 被阅读0次

接着上一节的项目文件,新建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
页面中:
image.png
可以看到,能正常的输出结果了。但是css-loader是做什么用的呢?
首先,我们修改index.less文件
@color: red;

body {
  background: @color;
  background: url(./logo.png); //加一张背景图,图是我提前放好的,么的问题
}

打包:

image.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;

执行

image.png
可以看到,打印出了后续的操作(当然,这不会这行),继续改写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;

相关文章

网友评论

    本文标题:实现less-loader和style-loader

    本文链接:https://www.haomeiwen.com/subject/aeldlctx.html