loader的基本概念
在webpack中,loader本质是一个函数,在我们执行文件操作时,会通过该函数对接收到的内容进行转换,返回转换后的结果。因为 Webpack
只支持 JavaScript
文件,所有有的时候,loader也对其他类型的文件进行转译处理,转换为 Webpack 支持的文件。
实现一个同步的 loader
在实现之前,我们先看一下什么是同步loader:
- 默认创建的Loader就是同步的Loader
- 这个Loader必须通过return或者this.callback来返回结果,交给下一个loader来处理
- 通常在有错误的情况下,会使用this.callback
- 第一个参数为ERR或者null
- 返回的是
string
或者buffer
在这里我们先初始化一个项目
1 | npm init -y |
再新建两个文件 index.js
、webpack.config.js
具体结构如下图所示
其中index.js中的内容
1 | // index.js |
webpack.config.js 中的内容
1 | const path = require('path') |
接着,在根目录下新建一个同步loader syncLoader.js
1 | // syncLoader.js |
修改 Webpack
打包配置
1 | const path = require('path') |
准备就绪,使用webpack进行打包,因为 package.json
已经声明了 "main": "index.js"
所以我们直接在根目录输入 webpack
即可,不出意料的话,会在终端输出以下内容:
1 | source: console.log('自己实现一个loader'); |
很明显,第一行的打印内容中 source
是 syncLoader.js
中的内容,后面拼接的是 index.js
中的文本,如下:
1 | // index.js |
我们接着使用 syncLoader.js
对 index.js
中的内容作出一些处理,比如:
1 | // index.js |
输出结果为
1 | source: console.log('自己实现一个loader');同步loader |
当然,我们可以使用 loader-utils
来完成更多自定义的功能,我这里安装 loader-utils@1.2.3
先改写 webpack.config.js
的内容,主要再rules中给 syncLoader
增加了 options
属性,其中 options
的内容可以自定义
1 | rules: [ |
然后我们就可以在 syncLoader.js
通过loader-utils
的 getOptions
获取到 options
配置项
1 | const loaderUtils = require('loader-utils') |
打包结果
1 | { message: '同步loader' } |
可以看到,在控制台输出了 syncLoader loader 新增的配置项内容 同步loader,跟之前的内容相同。
至此,我们就完成了一个同步 loader
当然我们要尽可能的异步化 Loader,如果计算量很小,同步也可以,所以看看如何实现一个异步的 loader
实现一个异步的 loader
在实现之前,我们先看一下什么是异步loader:
- 使用Loader进行一些异步的操作
- 我们希望在异步操作完成之后,再返回这个loader处理的结果
- 使用
this.async()
实现
在根目录新建一个js文件 asyncLoader.js
1 | module.exports = function (source) { |
修改 webpack.config.js
,在use中配置异步的loader,修改后的内容如下
1 | const path = require('path') |
由于loader的执行机制,所以我们预测 先执行 asyncLoader
,再执行syncLoader
查看 dist/main.js
内容,确实如此,至此我们就简单实现了一个 异步loader
总结
- Loader本质是一个导出为函数的JavaScript模块
- loader 的执行顺序是从下往上的,Loader runner库会调用这个函数,然后将上一个loader产生的结果或者资源文件传入进去
- 我们可以通过
loader-utils
获取到 loader 的配置,再对原始文件进行对应操作 - 异步loader主要通过
this.async()
实现
那么那么,为什么 loader 的执行是从下往上,从右往左的呢 ?。。。