本文是Webpack系列第五篇,主要学习Webpack5 loader原理
**介绍
**
帮助webpack将不同类型的文件转换为webpack可识别的模块
执行顺序
分类
-
pre:前置 loader
-
normal:普通 loader
-
inline:内联 loader
-
post:后置loader
执行顺序
- 执行优先级为:pre > normal > inline > post
- 相同优先级:从右到左,从上到下
使用方式
- 配置方式:在 webpack.config.js 文件中指定,可配置 pre、normal、post ⭐️推荐
{
enforce: 'pre',
test: /.js$/,
loader: 'loader',
}
- 内联方式:在import语句中指定
import styles from 'style-loader!css-loader?modules!./styles.css''
注:
- css-loader,style-loader处理 style.css文件
- 通过!将资源中的loader分开;
inline-loader可以通过添加不同前缀,跳过其他类型loader
- !跳过normal loader
import styles from '!style-loader!css-loader?module!./styles.css';
- ~!跳过 pre 和normal loader
import styles from '~!style-loader!css-loader?module!./styles.css';
- !!跳过pre,normal和postloader
import styles from '!!style-loader!css-loader?module!./styles.css';
开发第一个loader
例子🌰
module.exports = function (content, map, meta) {
console.log(content);
return content;
};
loader本质是一个函数,当解析资源时,会调用相应的loader去处理,接收到文件内容作为参数,返回内容出去
- content:文件内容
- map:SourceMap
- meta:别的loader传递的数据
同步loader
// 写法一
module.exports = function (content) {
return content;
};
// 写法二
module.exports = function (content, map, meta) {
// err: 代表是否有错误,将错误传出去
// content:处理后的内容
// map:继续传递source-map
// meta:给下一个loader传递参数
const err = null;
this.callback(err, content, map, meta);
};
同步loader中不能出现异步操作 ⭐️⭐️ 推荐写法二:出错可以传出,也可以给下一个loader传参
异步loader
例子🌰
module.exports = function (content, map, meta) {
const callback = this.async();
setTimeout(() => {
console.log("test asyc");
callback(null, content, map, meta);
}, 1000);};
raw loader
例子🌰
// 写法一
module.exports = function (content) {
return content;
};
module.exports.raw = true;
// 写法二
function testRawLoader(content) {
return content;
}
testRawLoader.raw = true;
module.exports = testRawLoader;
接收到的content是buffer数据流,处理图片时用这种形式
pitchloader
例子🌰
module.exports = function (content) {
return content;
};
module.exports.picth = function () {
console.log("pith");
};
pitch方法执行在loader执行之前loader API
| 方法名 | 含义 | 用法 |
|---|---|---|
| this.async | 异步回调loader,返回this.callback | const callback = this.async() |
| this.callback | 可以同步或异步调用的并返回多个结果的函数 | this.callback(err, content, sourceMap?, meta?) |
| this.getOptions(schema) | 获取loader的options | this.getOptions(schema) |
| this.emitFile | 产生一个文件 | this.emitFile(name, content,sourceMap) |
| this.utils.contextify | 返回一个相对路径 | this.utils.contextify(context, request) |
| this.utils.absolutify | 返回一个绝对路径 | this.utils.absolutify(context, request) |
自定义loader
clean-log-loader
module.exports = function (content) {
return content.replace(/console.log(.*);?/g, "");
};
******banner-loader
**
// loaderconst schema = require("./schema.json");
module.exports = function (content) {
const options = this.getOptions(schema);
const prefix = `
/*
* Authour: ${options.author}
*/ `;
return prefix + content;
};
// schema
{
"type": "object",
"properties": {
"author": {
"type": "string"
}
},
"additionalProperties": false
}
// webpack.config.js 使用
{
test: /.js$/,
loader: './loaders/banner-loader',
options: {
author: 'A',
}
},
******babel-loader
**
// loader
const babel = require("@babel/core");
const schema = require("./schema.json");
module.exports = function (content) {
const callback = this.async();
const options = this.getOptions(schema);
babel.transform(content, options, function (err, result) {
if (err) {
callback(err);
} else {
callback(null, result.code);
}
});
return content;
};
// schema
{
"type": "object",
"properties": {
"presets": {
"type": "array"
}
},
"additionalProperties": true
}
// webpack.config.js
{
test: /.js$/,
loader: "./loaders/file-loader",
options: {
presets: ["@babel/preset-env"],
},
},
/ End感谢阅读,如果觉得有用,点个赞、关注、在看***
涉及代码repo:github.com/qiqzhao/loa…