美文网首页
webpack loader

webpack loader

作者: 冷暖自知_zjz | 来源:发表于2022-05-06 21:40 被阅读0次

    说明

    webpack默认只能处理JavaScript和JSON文件,但前端项目中,文件类型多种多样.比如.vue、.ts、图片、.css等,这就需要各种各样的loader来处理各种文件,最后交给webpack的是js模块(通过loader来弥补webpack处理其他文件的能力)

    loader的本质

    loader 是导出为一个函数的 node 模块。该函数在 loader 转换资源的时候调用。
    //最简单的一个loader,不处理任何文件,直接返回资源

    function loader(source) {
        //  一个包含资源文件内容的字符串
        return source;
    }
    module.exports = loader;
    

    loader 在webpack中的调用时机

    Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程 :

    1.初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数。
    2.开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译。
    3.确定入口:根据配置中的 entry 找出所有的入口文件。
    4.编译模块:从入口文件出发,调用所有配置的 loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理。
    5.完成模块编译:在经过第 4 步使用Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系。
    6.输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会。
    7.输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。

    在webpack中使用

    webpack.config.js

    module.exports = {
      //...
      module: {
        rules: [
          {
            test: /\.less/,
            use: ['style-loader','less-loader'],
          },
        ],
      },
    };
    

    上面这段代码的意思是匹配后缀为.less的文件依次应用 less-loader=>style-loader

    less-loader 的源码的大概样子

    // less-loader.js

    const less = require('less');
    module.exports = function(source) {
        // this.async()表示该loader为异步loader
        const callback = this.async();
        // less 为node的一个模块 该模块的render函数接收两个参数,
        //  source为less文件的字符串,cd()函数为处理完的回调函数
        // render的作用就是把less变为css  也就是一个函数输入less输出css
        less.render(source, function(err, data) {
            callback(err, data.css)
        })
    }
    

    // style-loader.js

    module.exports = function(source) {
        // source为已经转成的css代码
        // 1.动态的生成style标签
        let style = document.createElement('style');
        // 2.将css代码插入到style标签中
        style.innerHTML = JSON.stringify(source);
        // 3.将style标签插入到head标签中
        document.head.appendChild(style);
        let content= `
            let style = document.createElement('style');
            style.innerHTML = ${JSON.stringify(source)};
            document.head.appendChild(style);
        `;
        return content;
    }
    

    自己实现一个webpack loader

    // replace-loader.js (将代码中的console.log(xxx)替换为控字符串)

    module.export = function(source) {
        const result = source.replace(/console.log(.*)/g, '');
        return result;
    }
    

    loader在webpack中的作用

    最后执行的loader(例如上面例子中的style-loader):让webpack能够处理非js文件(将非js模块转化为js模块)

    中间执行的loader 可以返回一下一个loader能识别的字符格式就可以

    loader的分类与用法

    loader 分类

    同步:

    function loader(source) {
        //  一个包含资源文件内容的字符串
        return source;
    }
    module.exports = loader;
    
    

    异步:

    module.exports = function(source) {
        // 告诉 Webpack 本次转换是异步的,Loader 会在 callback 中回调结果
        var callback = this.async();
        //doSomething 异步操作
        doSomething(source, function(err, result, sourceMaps, ast) {
            // 通过 callback 返回异步执行后的结果
            callback(err, result, sourceMaps, ast);
        });
    };
    
    

    loader返回其他的结果

    module.exports = function(source) {
      // 通过 this.callback 告诉 Webpack 返回的结果
      this.callback(null, source, sourceMaps);
      // 当你使用 this.callback 返回内容时,该 Loader 必须返回 undefined,
      return;
    };
    /**
      this.callback(
        // 当无法转换原内容时,给 Webpack 返回一个 Error
        err: Error | null,
        // 原内容转换后的内容
        content: string | Buffer,
        // 用于把转换后的内容得出原内容的 Source Map,方便调试
        sourceMap?: SourceMap,
        // 如果本次转换为原内容生成了 AST 语法树,可以把这个 AST 返回,
        // 以方便之后需要 AST 的 Loader 复用该 AST,以避免重复生成 AST,提升性能
        abstractSyntaxTree?: AST
    );
    
    */
    
    
    

    raw loader

    在默认的情况下,Webpack 传给 Loader 的原内容都是UTF-8格式编码的字符串。
    但有些场景下 Loader 不是处理文本文件,而是处理二进制文件,例如 file-loader,就需要 Webpack 给 Loader 传入二进制格式的数据。 为此,你需要这样编写 Loader

    module.exports = function(source) {
      // 在 exports.raw === true 时,Webpack 传给 Loader 的 source 是 Buffer 类型的
      source instanceof Buffer === true;
      // Loader 返回的类型也可以是 Buffer 类型的
      // 在 exports.raw !== true 时,Loader 也可以返回 Buffer 类型的结果
      return source;
    };
    // 通过 exports.raw 属性告诉 Webpack 该 Loader 是否需要二进制数据 
    module.exports.raw = true;
    
    

    获得option

    可以获得给Loader配置的options

    const loaderUtils = require('loader-utils');
    module.exports = function(source) {
      // 获取到用户给当前 Loader 传入的 options
      const options = loaderUtils.getOptions(this);
      return source;
    };
    

    完整API: https://webpack.js.org/api/loaders/

    参考

    https://juejin.cn/post/6844904038543130637

    https://webpack.docschina.org/contribute/writing-a-loader/

    https://indexsarrol.cn/2020/12/24/webpack-and-loader/

    相关文章

      网友评论

          本文标题:webpack loader

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