Webpack自定义loader的执行顺序实战分析
Posted IT飞牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Webpack自定义loader的执行顺序实战分析相关的知识,希望对你有一定的参考价值。
在使用webpack打包过程中,官网提供了丰富的loader和plugin,可以让我们通过简单的配置就能完成很多复杂转换处理工作。
有时候我们需要对指定类型的文件做通用处理,这时候我们就需要使用自定义loader,webpack提供了loader api。
同步 Loaders
无论是return
还是 this.callback
都可以同步地返回转换后的 content 值:
sync-loader.js
module.exports = function (content, map, meta)
return someSyncOperation(content);
;
this.callback
方法则更灵活,因为它允许传递多个参数,而不仅仅是 content。
sync-loader-with-multiple-results.js
module.exports = function (content, map, meta)
this.callback(null, someSyncOperation(content), map, meta);
return; // 当调用 callback() 函数时,总是返回 undefined
;
异步 Loaders
对于异步 loader,使用 this.async 来获取 callback 函数:
async-loader.js
module.exports = function (content, map, meta)
var callback = this.async();
someAsyncOperation(content, function (err, result)
if (err) return callback(err);
callback(null, result, map, meta);
);
;
async-loader-with-multiple-results.js
module.exports = function (content, map, meta)
var callback = this.async();
someAsyncOperation(content, function (err, result, sourceMaps, meta)
if (err) return callback(err);
callback(null, result, sourceMaps, meta);
);
;
实例演示:
1、在项目根目录下创建目录myloader
,编写自定义loader,在里面新建replace-loader-async.js
和replace-loader.js
replace-loader-async.js
module.exports = function (content, map, meta)
console.log(`自定义loader-$this.resourcePath-异步-$Date.now()`);
content = content.replace(/root/g, this.query.name);
let callback = this.async();
setTimeout(() =>
callback(null, content);
, 3000);
replace-loader.js
module.exports = function (content, map, meta)
console.log(`自定义loader-$this.resourcePath-同步-$Date.now()`);
content = content.replace(/\\sis\\s/g, " 是 ");
return content;
2、在src
下新建以下文件,index.js
设置为entry。
index.js
import "./run1";
import "./run3";
console.log("hello,this is root");
run1.js
import order from "./run2";
console.log("this is run1");
run2.js
console.log("this is run2");
run3.js
import order from "./run4";
console.log("this is run3");
run4.js
console.log("this is run4");
3、配置webpack.config.js
const path = require("path");
module.exports =
entry: "./src/index.js",
output:
path: path.resolve(__dirname, "dist"),
filename: "[name].js"
,
mode: "development",
resolveLoader:
modules: ['./node_modules', './myloader'] // 配置loader的查找目录
,
module:
rules: [
test: /\\.js$/,
use: [
"replace-loader",
loader: "replace-loader-async",
options:
name: "根"
]
]
;
4、执行npx webpack
或npm run dev
打包,最终在dist目录下输出main.js
文件。命令行打印记录如下:
将生成dist/main.js
放到index.html中,控制台打印如下:
打包过程loader的顺序依次
- index.js 异步loader,等待3s;
- index.js 同步loader;run1.js和run3.js 异步loader,等待3s。(1、3因为同属于
index.js
下的同层依赖,所以同时执行;) - run1.js和run3.js 同步loader;run2.js和run4.js 异步loader,等待3s;(run1依赖run2,run3依赖run4,所以在run1和run3执行完成后,分别检测到各自依赖的run2、run4,继续执行)
- run2.js和run4.js 同步loader;
loader执行的流程图
webpack 会递归的构建一个 依赖关系图,可以想象成一个树形结构,我理解是节点下的同层依赖并行执行,跨层依赖串行执行。同层依赖文件按照import/require先后顺序执行,跨层依赖从上至下执行。
8是entry,那么3、10属于同层依赖,并行执行;1、6并行;4、11并行;
串行的执行线有:
- 8->3->1
- 8->3->6->4
- 8->3->6->11
- 8->10->14->13
以上是关于Webpack自定义loader的执行顺序实战分析的主要内容,如果未能解决你的问题,请参考以下文章
webpack原理篇(五十九):loader 的链式调用与执行顺序