loader是什么?
Loader是打包方案,webpack不能识别非js结尾的模块,告知webpack某些特定文件如何打包,loader其实是在webpack编译期间执行的一个函数
替换一个字符串
这里我想使用loader把word替换个xxx,发现没有我想用的loader,只能自己写一个了
console.log('hello word');
// loader函数
/**
* source 代码片段
* map surcemap 可选
* meta 模块原数据 可选
*/
module.exports = function (source, map, meta) {
return source.replace('word', 'xxx');
}
// webpack.config.js
const path = require('path');
module.exports = {
mode: 'development',
entry: {
main: './src/index.js'
},
module: {
rules: [{
test: /.js/,
use: [
{
loader: path.resolve(__dirname, './loaders/replaceLoader.js'),
},
]
}]
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
}
}
build结果,自定义loader实现了我们的效果
能不能把替换的内容变成参数传递的?
通过loader函数内部this.query获取loader配置的options
// loader
module.exports = function (source, map, meta) {
const options = this.query;
return source.replace('word', options.name);
}
通过loader-utils获取
const loaderUtils = require('loader-utils');
module.exports = function(source) {
const options = loaderUtils.getOptions(this);
return source.replace('dell', options.name);
}
const path = require('path');
module.exports = {
mode: 'development',
entry: {
main: './src/index.js'
},
module: {
rules: [
{
test: /.js/,
use: [
{
loader: path.resolve(__dirname, './loaders/replaceLoader.js'),
// 相当于为loader函数传递参数
options: {
name: '123123123'
}
}
]
}
]
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
},
};
可以发现上诉我们都是通过path路径引入loader,能不能类似与less-loader直接写loader名称就可以,答案显示当然可以,通过resolveLoader配置loader文件夹
const path = require('path');
module.exports = {
mode: 'development',
entry: {
main: './src/index.js'
},
// 自定义loader文件夹
resolveLoader: {
modules: ['node_modules', './loaders']
},
module: {
rules: [
{
test: /.js/,
use: [
{
// 同级目录node_modules或者loaders找replaceLoader.js
loader: 'replaceLoader',
options: {
name: '123123123'
}
}
]
}
]
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
},
};
this.callback
除了通过return返回loader编译结果的值还可以通过this.callback
this.callback(
err: Error | null,
content: string | Buffer,
sourceMap?: SourceMap,
meta?: any
);
const loaderUtils = require('loader-utils');
module.exports = function(source) {
const options = loaderUtils.getOptions(this);
callback(null, source.replace('word', options.name));
}
异步loader(会阻塞)
异步loader,使用this.async(),返回值通过this.async()的返回值callback输出
const loaderUtils = require('loader-utils');
module.exports = function(source) {
const options = loaderUtils.getOptions(this);
const callback = this.async();
setTimeout(() => {
const result = source.replace('word', options.name);
callback(null, result);
}, 1000);
}
定义loader需要注意什么
- commonjs风格
- 导出的是一个函数
- 不可以是箭头函数this上有很多参数可以看webpack官方文档,箭头函数无this指向
查看更多相关loader配置
webpack无疑是个庞大的体系,文章仅仅介绍了如何完整定义一个loader的全过程,如果想了解的更多可以查看webpack loader-api