一、概念
帮助webpack将不同类型的文件转换为webpack可识别的模块。
二、Loader执行顺序
分类
- pre:前置loader
- normal:普通loader
- inline:内联loader
- post:后置loader
执行顺序
- 4类loader的执行顺序为per>normal>inline>post
- 相同优先级的loader执行顺序为:从右到左,从下到上。
例如:
// 此时loader执行顺序:loader3 - loader2 - loader1
module: {
rules: [
{
test: /\.js$/,
loader: "loader1",
},
{
test: /\.js$/,
loader: "loader2",
},
{
test: /\.js$/,
loader: "loader3",
},
],
},
// 此时loader执行顺序:loader1 - loader2 - loader3
module: {
rules: [
{
enforce: "pre",
test: /\.js$/,
loader: "loader1",
},
{
// 没有enforce就是normal
test: /\.js$/,
loader: "loader2",
},
{
enforce: "post",
test: /\.js$/,
loader: "loader3",
},
],
},
使用Loader 的方式
- 配置方式:在 webpack.config.js 文件中指定 loader。(pre、normal、post loader)
- 内联方式:在每个 import 语句中显式指定 loader。(inline loader)
inline Loader
用法:import Styles from ‘style-loader!css-loader?modules!./styles.css’;
含义:使用 css-loader 和 style-loader 处理 styles.css 文件通过 ! 将资源中的 loader 分开
inline loader 可以通过添加不同前缀,跳过其他类型 loader。! 跳过 normal loader。
import Styles from '!style-loader!css-loader?modules!./styles.css';
-! 跳过 pre 和 normal loader。
import Styles from '-!style-loader!css-loader?modules!./styles.css';
!! 跳过 pre、 normal 和 post loader。
import Styles from '!!style-loader!css-loader?modules!./styles.css';
三、开发一个Loader
最简单的Loader
//loader/loader1.js
module.exports = function (content){
console.log(content)
return content;
}
他接受要处理的源码作为参数,输出转换后的js代码
Loader接受的参数
- content 源文件的内容
- map sourceMap数据
- meta 数据可以是任何内容
Loader分类
- 同步Loader
module.exports = function (content ,map ,meta) {
/*
第一个参数:err代表是否有错误
第二个参数:content处理后的内容
第三个参数:sorce-map继续传递sourcemap
第四个参数:meta给下一个loader传递参数
*/
//相比于普通return方式这种写法可以传递更多参数,不中断loader执行。
//return content
this.callback(null,content,map,meta)
}
- 异步Loader
由于同步计算过于耗时,在 Node.js 这样的单线程环境下进行此操作并不是好的方案,我们建议尽可能地使你的 loader 异步化。但如果计算量很小,同步 loader 也是可以的。
module.exports = function (content, map, meta) {
const callback = this.async();
// 进行异步操作
setTimeout(() => {
callback(null, result, map, meta);
}, 1000);
};
- Raw Loader
默认情况下,资源文件会被转化为 UTF-8 字符串,然后传给 loader。通过设置 raw 为 true,loader 可以接收原始的 Buffer
module.exports = function (content) {
// content是一个Buffer数据
return content;
};
module.exports.raw = true; // 开启 Raw Loader
- Pitching Loader
webpack 会先从左到右执行 loader 链中的每个 loader 上的 pitch 方法(如果有),然后再从右到左执行 loader 链中的每个 loader 上的普通 loader 方法。在这个过程中如果任何 pitch 有返回值,则 loader 链被阻断。webpack 会跳过后面所有的的 pitch 和 loader,直接进入上一个 loader 。
module.exports = function (content) {
return content;
};
module.exports.pitch = function (remainingRequest, precedingRequest, data) {
console.log("do somethings");
};
手写banner-loader
作用:给代码添加文本注释包括作者、日期
//loader/banner-loader.js
const schema = require("./schema.json");
module.exports = function (content,map,meta){
//获取Loader的options,同时对options做校验
//schema 是options的校验规则。
const options = this.getOptions(schema);
const date = (new Date()).toLocaleString()
const prefix = `
/*
Author ${options.author}
Date ${date}
*/
`
return `${prefix} \n ${content}`
}
下面是schema.json文件
{
"type":"object",
"porperties":{
"author":{
"type":"string"
}
},
"addtionalProperties":false
}
在webpack.config.js中配置
//...省略
module: {
rules: [
{
test:/\.js$/,
loader:'./loader/banner-loader',
options:{
author:'老王'
}
}
]
},
在dist压缩文件main.js中
/***/ "./src/main.js":
/*!*********************!*\
!*** ./src/main.js ***!
\*********************/
/***/ (() => {
eval("\n /* \n Author 老王\n Date 2024/1/13 14:32:11\n */\n \n console.log('hello main')\n\n//# sourceURL=webpack:///./src/main.js?");
/***/ })
/******/ });
/************************************************************************/