美文网首页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