# 编写自己的Loader
在我们使用 Webpack 的过程中,我们使用了很多的loader
,那么那些loader
是哪里来的?我们能不能写自己的loader
然后使用?
答案当然是可以的,Webpack 为我们提供了一些loader
的API,通过这些API我们能够编写出自己的loader
并使用。
# 如何编写及使用自己的Loader
场景
我们需要把.js
文件中,所有出现Webpack is good!
,改成Webpack is very good!
。实际上我们需要编写自己的loader
,所以我们有如下的步骤需要处理:
- 新建
webpack-loader
项目 - 使用
npm init -y
命令生成package.json
文件 - 创建
webpack.config.js
文件 - 创建
src
目录,并在src
目录下新建index.js
- 创建
loaders
目录,并在loader
目录下新建replaceLoader.js
- 安装
webpack
、webpack-cli
按上面的步骤新建后的项目目录如下:
|-- loaders
| | -- replaceLoader.js
|-- src
| | -- index.js
|-- webpack.config.js
|-- package.json
首先需要在webpack.config.js
中添加下面的代码:
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
module: {
rules: [
{
test: /\.js$/,
use: [path.resolve(__dirname, './loaders/replaceLoader.js')]
}
]
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
}
随后在package.json
文件添加build
打包命令:
// 其它配置
"scripts": {
"build": "webpack"
}
接下来在src/index.js
文件中添加一行代码:这个文件使用最简单的例子,只是打印一句话。
console.log('Webpack is good!');
最后就是在loader/replaceLoader.js
编写我们自己loader
文件中的代码:
说明
- 编写
loader
时,module.exports
是固定写法,并且它只能是一个普通函数,不能写箭头函数(this
指向) source
是打包文件的源文件内容
const loaderUtils = require('loader-utils');
module.exports = function(source) {
return source.replace('good', 'very good');
}
使用我们的loader
: 要使用我们的loader
,则需要在modules
中写loader
:
理解
resolveLoader
:它告诉了 Webpack 使用loader
时,应该去哪些目录下去找,默认是node_modules
,做了此项配置后,我们就不用去显示的填写其路径了,因为它会自动去loaders
文件夹下面去找。
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
resolveLoader: {
modules: ['node_modules', './loaders']
},
module: {
rules: [
{
test: /\.js$/,
use: [{
loader: 'replaceLoader',
options: {
name: 'wanghuayu'
}
}]
}
]
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
}
最后我们运行npm run build
,在生成的dist
目录下打开main.js
文件,可以看到文件内容已经成功替换了,说明我们的loader
已经使用成功了。
/***/ "./src/index.js":
/*!**********************!*\
!*** ./src/index.js ***!
\**********************/
/*! no static exports found */
/***/ (function(module, exports) {
eval("console.log('Webpack is very good!');\n\n//# sourceURL=webpack:///./src/index.js?");
/***/ })
/******/ });
# 如何向Loader传参及返回多个值
问题
- 我们如何返回多个值?
- 我们如何向自己的Loader传递参数?
# 如何返回多个值
说明
Webpack 的 API允许我们使用callback(error, result, sourceMap?, meta?)
返回多个值,它有四个参数:
Error || Null
:错误类型, 没有错误传递null
result
:转换后的结果sourceMap
:可选参数,处理分析后的sourceMap
meta
: 可选参数,元信息
返回多个值,可能有如下情况:
// 第三,第四个参数是可选的。
this.callback(null, result);
# 如何传递参数
我们知道在使用loader
的时候,可以写成如下的形式:
// options里面可以传递一些参数
{
test: /\.js$/,
use: [{
loader: 'replaceLoader',
options: {
word: 'very good'
}
}]
}
再使用options
传递参数后,我们可以使用官方提供的loader-utils来获取options
参数,可以像下面这样写:
const loaderUtils = require('loader-utils');
module.exports = function(source) {
var options = loaderUtils.getOptions(this);
return source.replace('good', options.word)
}
# 如何在Loader中写异步代码
在上面的例子中,我们都是使用了同步的代码,那么如果我们有必须异步的场景,该如何实现呢?我们不妨做这样的假设,先写一个setTimeout
:
const loaderUtils = require('loader-utils');
module.exports = function(source) {
var options = loaderUtils.getOptions(this);
setTimeout(() => {
var result = source.replace('World', options.name);
return this.callback(null, result);
}, 0);
}
如果你运行了npm run build
进行打包,那么一定会报错,解决办法是:使用this.async()
主动标识有异步代码:
const loaderUtils = require('loader-utils');
module.exports = function(source) {
var options = loaderUtils.getOptions(this);
var callback = this.async();
setTimeout(() => {
var result = source.replace('World', options.name);
callback(null, result);
}, 0);
}
至此,我们已经掌握了如何编写、如何引用、如何传递参数以及如何写异步代码,在下一小节当中我们将学习如何编写自己的plugin
。