Skip to content

webpack-loader

Webpack Loader 的工作原理基于 模块转换链,其核心功能是将不同类型的文件(如 CSS、图片、TS)转换为 Webpack 可处理的模块。以下是其详细机制:

概念

  1. Loader 本质
    • 一个 函数,接收源文件内容作为输入,返回转换后的内容。
    • 支持链式调用,多个 loader 按顺序处理同一个文件。
  2. 执行顺序,从右到左或从下到上。
js
{
    test: /\.scss$/,
        use: [
        'style-loader',  // 最后执行:将 CSS 注入 DOM
        'css-loader',    // 解析 CSS 中的 @import 和 url()
        'sass-loader'    // 首先执行:将 SCSS 编译为 CSS
    ]
}

工作流程

  1. 模块请求解析
    • 当 Webpack 遇到非 JS 模块导入(如 import './style.css')时,根据 module.rules 匹配对应的 loader。
  2. Loader 链调用
    • 按配置顺序依次调用 loader,每个 loader 接收前一个 loader 的输出(或原始文件内容)。
  3. 结果传递
    • 最后一个 loader 必须返回 JS 代码(字符串或 Buffer),因为 Webpack 只能处理 JS 模块。
    • 返回的 JS 代码会被 Webpack 解析为模块,并加入依赖图。

开发要点

基本结构

js
// 同步 loader
module.exports = function(source) {
  // source: 源文件内容(字符串或 Buffer)
  // 转换逻辑
  const result = doSomething(source);
  return result; // 必须返回 JS 代码
};

// 异步 loader
module.exports = function(source) {
  const callback = this.async(); // 获取异步回调
  setTimeout(() => {
    const result = doSomethingAsync(source);
    callback(null, result); // 回调参数:(error, result)
  }, 1000);
};

loader API

js
// this包含 Webpack 提供的工具和信息:
module.exports = function(source) {
  // 获取 loader 配置参数
  const options = this.getOptions();
  
  // 获取文件路径
  const filePath = this.resourcePath;
  
  // 添加依赖(让 Webpack 监听文件变化)
  this.addDependency('path/to/dependency');
  
  // 返回多个结果
  return this.callback(null, source, sourceMap, meta);
};

Loader 与 Plugin 的区别

特性LoaderPlugin
作用对象单个文件整个构建过程
核心功能文件格式转换(如 SCSS → CSS)修改、优化或生成资源
执行时机模块解析阶段通过钩子在特定阶段触发
配置方式module.rulesplugins 数组
返回值必须是 JS 代码无(通过修改 compilation 对象

优化建议

使用缓存

  1. 使用 cache-loader(webpack4以下) 或 babel-loadercacheDirectory 选项开启缓存,减少重复构建时间。
js
{
  test: /\.js$/,
  use: {
    loader: 'babel-loader',
    options: {
      cacheDirectory: true // 开启缓存
    }
  }
}

使用 thread-loader 开启多线程处理,提升构建速度。

js
{
  test: /\.js$/,
  use: {
    loader: 'thread-loader',
    options: {
      workers: 2 // 设置线程数
    }
  }
}

缩小处理范围

精准配置 loader 的作用范围,使用 includeexclude 限制处理的文件目录。

js
{
  test: /\.js$/,
  include: path.resolve(__dirname, 'src'), // 只处理 src 目录
  exclude: /node_modules/,
  use: 'babel-loader'
}

demo

1. 字符串替换

js
module.exports = function(source) {
  return source.replace(/Hello/g, 'Hi');
};

2. 带有异步操作的字符串替换

js
// replace-loader.js
const { getOptions } = require('loader-utils');
const { validate } = require('schema-utils');

// 选项验证模式
const schema = {
    type: 'object',
    properties: {
        search: {
            type: 'string',
            required: true
        },
        replace: {
            type: 'string',
            required: true
        },
        flags: {
            type: 'string',
            default: 'g'
        }
    }
};

module.exports = function(source) {
    const options = getOptions(this) || {};
    validate(schema, options, { name: 'ReplaceLoader' });

    const callback = this.async();

    // 模拟异步操作
    setTimeout(() => {
        try {
            const regex = new RegExp(options.search, options.flags);
            const result = source.replace(regex, options.replace);
            callback(null, result);
        } catch (error) {
            callback(error);
        }
    }, 100);
};

webpack常见的loader

  1. css-loader:解析css
  2. less-loader:解析less为css
  3. style-loader:将css注入dom中
  4. postcss-loader:补充css前缀
  5. file-loader:将文件输出到目录中,返回url
  6. url-loader:类似于file-loader,输出base64
  7. babel-loader:将es6转为es6
  8. ts-loader:转换ts
  9. vue-loader:转换vue文件