前言
Loader
就像一个翻译员,能将源文件经过转化后输出新的结果,并且这个文件还可以链式地经过多个翻译员翻译。在开发Loader
的时候,应该遵循单一职责原则,只需要完成一种转换,开发的过程中我们只关心Loader
的输入和输出。webpack
是运行在Node.js
上的,一个Loader
就是一个Node
模块。这个模块需要导出一个函数,这个导出的函数的工作就是获得处理前的原内容,对原内容执行处理返回处理后的内容。
一个最简单的Loader
一个最简单的loader源码如下
module.exports = function (source) { //source为compiler 传递给 Loader 的一个文件的原内容 //该函数需要返回处理后的内容,为了简单起见,直接将原内容返回了,相当于该Loader没有做任何转换 return source }
开始开发之前
- 获取
Loader
的options
在开发一个Loader
的时候,要获取传入的options
,需要这样做const loaderUtils = require('loader-utils') module.exports = function (source) { //获取用户传入的options const options = loaderUtils.getOptions(this) return source }
- 同步与异步
Loader
有同步和异步之分,上面介绍的Loader
是同步的Loader
,但在某些场景下转换的步骤只能是异步完成的,例如我们需要通过网络请求才能得出结果,如果采用同步的方式,则网络请求会阻塞整个构建,导致构建非常缓慢。
如果是异步转换,我们需要这样做module.exports = function (source) { //告诉webpack此次转换是异步的,Loader会在callback回调结果 var callback = this.async() asyncOperation(source,function(err,result,sourceMaps,ast){ callback(err,result,sourceMaps,ast) }) }
- 加载本地
Loader
假设本地项目的Loader
处于./src/loaders/myLoader
中,需要如下配置module.exports = { resolveLoader:{ //去哪些目录寻找loaders 有先后之分 modules:['node_modules','./src/loaders'] } }
或者我们也可以这样配置,直接加载对应的Loader处理对应的文件const path = require('path') module.exports = { module: { rules: [{ test: /\.js$/, use: [{ loader: path.resolve('loaders/test.js') }], }] }, }
在webpack.config.js
中加上以上配置后,webpack
先会去node_modules
目录下寻找,如果找不到就会去./src/loaders
下查找
开发我们的Loader
我们现在写一个简单的Loader
,这个Loader
的作用就是将JavaScript
文件内容里面的字符串love转换成 ❤ 。webpac.config.js
的配置如下
//webpack.config.js const path = require('path') module.exports = { entry: './index.js', module: { rules: [{ test: /\.js$/, use: [{ loader: path.resolve('loaders/test.js') }], }] }, output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') } }
我们自己写的Loader
代码如下
//test.js module.exports = function (source) { const regExp = new RegExp("love", "ig") const result = source.replace(regExp, "❤") return result }
入口文件index.js
里只有一行代码,即 module.exports="I love you"
执行打包命令npx webpack
可以看到打包后的文件bundle.js
中
([function (e, t) { e.exports = "I ❤ TAPD" }])
我们的字符'love'已经被转换成了❤