深入理解Webpack Loader:处理模块的工具

9/14/2023 Webpack

在前一篇文章中,我们已经讨论了 Webpack 的生命周期和如何编写自定义的 Plugin。这次,让我们来深入了解 Webpack 的另一个核心部分 - Loader。

# Webpack 的生命周期和 Loader 的作用

Webpack 的生命周期可以分为三个阶段:准备阶段、编译阶段和产出阶段。Loader 主要发挥作用的阶段是编译阶段。默认情况下,Webpack 只能打包 CommonJS 规范的 JavaScript 文件,因此需要 Loader 来处理不同类型的文件,并将它们转换为可以理解的模块。

# Webpack 的执行上下文

在自定义 loader 的时候,Webpack 仅仅会把正则匹配的文件的源码当作参数传入,其他有用的信息需要通过执行上下文this去获取。

Webpack 提供loader-utils工具去方便开发者去开发 loader,推荐使用v1 版本 (opens new window),最常用的就是loaderUtils.getOptions(this)去获取 loader 的传入参数

除了使用 loader-utils 之外,默认this也有很多实用的方法供开发者使用。

  1. this.query,也是获取传入参数,如果有配置 options 的话就获取该对象,没有获取去?开头的字符串,当然官方推荐使用 loader-utils 去获取参数
  2. this.callback,用于返回结果的函数,用于同步或者异步返回结果。
this.callback(
  err: Error | null,
  content: string | Buffer,
  sourceMap?: SourceMap,
  meta?: any
);
  1. this.async,异步返回函数。
const loaderUtils = require('loader-utils');

module.exports = function(source) {
  const callback = this.async();

  setTimeout(() => {
    callback(null, '12345');
  }, 200)
}
  1. this.emitFile,文件写入,url-loader就通过这个函数去实现文件写入
const loaderUtils = require('loader-utils');

module.exports = function(content) {
  const url = loaderUtils.interpolateName(this, "[name].[ext]", {
    content,
  });
  this.emitFile(url, content);
	this.callback(null, content);
}

更多的API (opens new window)可以参考

# Loader 开发环境

Webpack 提供了[loader-runnder](https://github.com/webpack/loader-runner)的开发工具,让开发者可以脱离 webpack 的环境去开发 loader。

// my-loader.js
module.exports = function(source) {
  const json = JSON.stringify(source)
  	.replace('howard', 'Howard');

  return `export default ${json}`;
}

然后在根目录创建一个 run.js 文件

// run-loader.js
const { runLoaders } = require('loader-runner');
const fs = require('fs');
const path = require('path');

runLoaders({
  resource: path.join(__dirname, './me.txt'),
  loaders: [
    {
      loader: path.join(__dirname, './src/my-loader.js'),
    }
  ],
  context: {},
  readResource: fs.readFile.bind(fs)
}, (err, result) => {
  err ? console.log(err) : console.log(result);
});

# 常用的 Loader

Loader 名字 官网地址 作用
babel-loader https://github.com/babel/babel-loader 前端现代神器,必备,万能的 js 转换器,React,Vue,Typescript 常用。
style-loader https://github.com/webpack-contrib/style-loader 一个用于在浏览器中加载样式文件的 webpack 加载器。
css-loader https://github.com/webpack-contrib/css-loader 用于处理 webpack 中的 CSS 文件,将其转换为可被浏览器理解的模块。
postcss-loader https://github.com/webpack-contrib/postcss-loader 一个用于在 webpack 构建过程中自动处理 CSS 的加载器,可用于执行各种 CSS 处理和优化任务。
sass-loader https://github.com/webpack-contrib/sass-loader 用于在 webpack 构建过程中处理 Sass 文件,将其转换为普通的 CSS 样式。
url-loader https://github.com/webpack-contrib/url-loader 用于处理文件资源,特别是图像和字体文件,它可以将小文件转换为 base64 数据 URL,以减少 HTTP 请求并提高性能。但目前在 Webpack5 中,更推荐使用 type: asset 去处理文件
vue-loader https://github.com/vuejs/vue-loader 一个用于处理 Vue.js 单文件组件的 webpack 加载器,它将.vue 文件中的模板、样式和脚本部分提取出来并进行编译,以便在浏览器中正确渲染 Vue 组件。