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.jsreplace-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 webpacknpm run dev打包,最终在dist目录下输出main.js文件。命令行打印记录如下:


将生成dist/main.js放到index.html中,控制台打印如下:

打包过程loader的顺序依次

  1. index.js 异步loader,等待3s;
  2. index.js 同步loader;run1.js和run3.js 异步loader,等待3s。(1、3因为同属于index.js下的同层依赖,所以同时执行;)
  3. run1.js和run3.js 同步loader;run2.js和run4.js 异步loader,等待3s;(run1依赖run2,run3依赖run4,所以在run1和run3执行完成后,分别检测到各自依赖的run2、run4,继续执行)
  4. 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

webpack原理篇(五十九):loader 的链式调用与执行顺序

Webpack Loader种类以及执行顺序

webpack入门和实战:全面理解和运用loader和plugins

webpack loader自定义编写

webpack loader自定义编写