webpack loader 核心机制分析

139 阅读2分钟

webpack loader 核心机制分析

什么是loader?

loader 是一个函数,通过它我们可以在 webpack 处理特定资源(文件)之前,对资源进行预处理,比如:webpack 仅仅只能够识别 js 模块,而我们在使用 ts 编写代码的时候可以提前通过 babel-loader.ts 为后缀的文件编译成 .js 文件,这样 webpack 就可以识别了。

常用配置参数

基础配置示例

module.exports = {
    module: {
        rules: [
            {
                test: /.css$/,
                use: 'css-loader',
                enforce: 'post'
            },
            {
                test: /.ts$/,
                use: 'ts-loader'
            }
        ]
    }
}

// 注意,use的值是一个数组,数组的执行顺序是从右往左,从下往上;
  • test reg 表示的是匹配规则,可以是正则表达式,也可以是字符串,也可以是数组
  • use string|string[] 表示的是 test 中匹配到的文件应该使用哪一个 loader 处理,
  • enforce pre: 前置执行;post: 后置执行

例如:

module.exports = {
    module: {
        rules: [
            {test: /.css$/, use: 'sass-loader', enforce: 'pre'},
            {test: /.css$/, use: 'css-loader'},
            {test: /.css$/, use: 'style-loader', enforce: 'post'},
        ]
    }
}

执行顺序为

graph LR
    A[sass-loader] --> B[css-loader] --> C[style-loader]

loader 的执行顺序为

graph LR
    A[pre-loader] --> B[normal-loader] --> C[inline-loader] --> D[post-loader]

pitch 阶段的执行顺序

pitch

pitch 阶段的说明

loader 的执行阶段分为两个阶段

  • webpack 在使用 loader 处理资源时,首先会经过 loader.pitch 阶段
  • pitch 阶段结束后才会读取文件,在之后才会进行 normal 阶段的处理

Pitch 阶段:loader 上的 pitch 方法,按照 后置(post)-> 行内(inline)->普通(normal)->前置(pre)->的顺序调用; Norma 阶段:loader 上的常规方法,按照 前置(pre)->普通(normal)->行内(inline)->后置(post)的顺序调用。

function loader() {
    // 正常的loader 执行阶段...
}

// remainingRequest:表示剩余需要处理的loader 的绝对路径,以! 分割组成的字符串
// precedingRequest:表示pitch 阶段已经迭代过的loader, 按照 ! 分割成的字符串;
// data : 在pitch 和 loader之间交互的数据
loader.pitch = function (remainingRequest, precedingRequest, data) {
    // pitch loader
    // 如果return 了一个非 undefined 的值,会带来 【熔断效果】
}

熔断

inline loader 举例

  • ! 前缀, 将禁用所有已经配置的 normal loader
import Styles from '!style-loader!css-loader?modules!./style.css';
  • !! 前缀, 将禁用所有已经配置的 loader (pre loader, normal loader, post loader)
import Styles from '!!style-loader!css-loader?modules!./style.css';
  • -! 前缀, 将禁用所有已经配置的 pre loaderloader, 但是不禁用 post loader
import Styles from '-!style-loader!css-loader?modules!./style.css';

loader 的种类

同步 loader
module.exports = function (content) {
    return someSyncOperation(content);
}
异步 loader
function asyncLoader() {
    return Promise((resolve) => {
        resolve('this is result value')
    })
}

function asyncLoader() {
    const callback = this.async();
    // do something
    callback('this is result value')
}
raw loader

默认情况下,资源文件会被转化成 UTF-8字符串,然后传给 loader。 通过谁知 raw, loader 可以接受原始的 Buffer。 每一个loader 都可以使用 string 或者 buffer 的形式传递它的处理结果。 Compiler 将会把他们在 loader 之间相互转换