webpack loader实现

作者: HashTang | 来源:发表于2019-10-12 19:21 被阅读0次
    正值前端组件化开发时代,那么必然离不开目前最火的构建工具——webpack(grunt,gulp等暂且不谈)。说到这里,刚好有几个问题:
    • 为什么运行打包命令之后,.vue 文件可以转成 .js 文件
    • 为什么运行打包命令之后,.less 文件可以转成 .css 文件
    • 为什么运行打包命令之后,ES6+ 语法可以转成 ES5 语法

    上面这几个问题,就引出了我们的主角——【loader】。
    loaderwebpack 的一块很重要的组成部分。我们都知道 webpack 是用于资源打包的,里面的所有资源都是“模块”,内部实现了对模块资源进行加载的机制。但是 Webpack 本身只能处理 js 模块,如果要处理其他类型的文件,就需要使用 loader 进行转换。 Loader 可以理解为是模块和资源的转换器,它本身是一个函数,接收文件源码作为参数,返回转换的结果,例如可以使用 loader 加载器可以快速编译预处理器 (less,sass,coffeeScript)Loader 可以在 require() 引用模块的时候添加,也可以在 webpack 全局配置中进行绑定,还可以通过命令行的方式使用。(本篇中的参数配置及使用方式均基于 webpack4.0 版本)

    一、loader的特点

    1、loader 的执行顺序和代码书写的顺序是相反的,即:从下至上,从右至左。
    2、第一个执行的 loader 会接收源文件做为参数,下一次执行的 loader 会接收前一个 loader 执行的返回值做为参数
    3、需要严格遵循“单一职责”原则,即每个 loader 只负责自己需要负责的事情

    二、loader API

    methods 含义
    this.request 被解析出来的 request 字符串。例子:"/abc/loader1.js?xyz!/abc/node_modules/loader2/index.js!/abc/resource.js?rrr"
    this.loaders 所有 loader 组成的数组。它在 pitch 阶段的时候是可以写入的。
    this.loaderIndex 当前 loader 在 loader 数组中的索引。
    this.async 告诉 loader-runner 这个 loader 将会异步地回调
    this.callback 一个可以同步或者异步调用的可以返回多个结果的函数
    this.data 在 pitch 阶段和正常阶段之间共享的 data 对象。
    this.cacheable 设置是否可缓存标志的函数
    this.resource request 中的资源部分,包括 query 参数
    this.resourcePath 资源文件的路径。
    this.resourceQuery 资源的 query 参数
    this.target 编译的目标。从配置选项中传递过来的。
    this.webpack 如果是由 webpack 编译的,这个布尔值会被设置为真
    this.sourceMap 应该生成一个 source map。因为生成 source map 可能会非常耗时,你应该确认 source map 确实有必要请求。
    this.emitWarning 发出一个警告。
    this.emitError 发出一个错误。
    this.loadModule 解析给定的 request 到一个模块,应用所有配置的 loader ,并且在回调函数中传入生成的 source 、sourceMap 和 模块实例(通常是 NormalModule 的一个实例)。如果你需要获取其他模块的源代码来生成结果的话,你可以使用这个函数。
    this.resolve 像 require 表达式一样解析一个 request 。
    this.emitFile 产生一个文件。这是 webpack 特有的。
    this.fs 用于访问 compilation 的 inputFileSystem 属性。
    this.value 向下一个 loader 传值。如果你知道了作为模块执行后的结果,请在这里赋值(以单元素数组的形式)。
    this.inputValue 从上一个 loader 那里传递过来的值。如果你会以模块的方式处理输入参数,建议预先读入这个变量(为了性能因素)。
    更多详细API,以及各API的用法示例,可以访问官网查看。地址:https://www.webpackjs.com/api/loaders

    三、写loader之前的需求整理

    现在有这样一个需求,使用 hxkj-loader 加载并处理名称为 *.hxkj.vip 的文件,将里面的哈希空间全部替换为 www.hxkj.vip。需要实现的转换如下:

    转换前的内容:

    <div>
        <h1>欢迎访问哈希空间</h1>
        <p>哎哟,终于等到你。这里就是让人流连忘返的哈希空间呀!</p>
    </div>
    

    转换后的内容:

    <div>
        <h1>欢迎访问www.hxkj.vip</h1>
        <p>哎哟,终于等到你。这里就是让人流连忘返的www.hxkj.vip呀!</p>
    </div>
    

    四、编写loader

    在与 webpack.config.js 同级目录下新建 hxkj-loader.js,文件的内容如下:

    module.exports = function(source){
        var content="";
        content = source.replace("/哈希空间/g","www.hxkj.vip");
        return content; 
    }
    

    接下来,需要在 webpack.config.js 文件中增加以下的配置:

    const path = require("path"); // 引入 node 的 path 模块
    ...
    module:{
        rules:[{
            test: /\.hxkj\.vip$/, // 正则匹配以 hxkj.vip 结尾的文件
            use:[{
                loader:path.resolve(__dirname, "hxkj-loader") // 使用 path 模块找到 hxkj-loader 的路径
            }]
        }]
    }
    
    好,到此,一个简易版的 loader 就已经写完了。目前 loader 是直接写在本地的,可以考虑将自己写好的 loader 发布到 npm,这样就更加完善了。

    At last,看完之后有什么不懂的,可以留言反馈。

    转载请注明出处:https://www.jianshu.com/p/51b793f6fa0e
    作者:TSY
    个人空间:https://hxkj.vip

    相关文章

      网友评论

        本文标题:webpack loader实现

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