webpack的生命周期与Loader/Plugin

核心对象:

  • compiler: 代表Webpack构建的全局上下文,钩子是全局生命周期钩子
  • compilation: 代表一次构建的编译过程,钩子是编译阶段钩子

生命周期:

整个过程分为【初始化->编译->输出->结束】,一共四个阶段,以下列举一下各个阶段的核心钩子:

  1. 初始化:
  • entryOption 动态新增入口
  1. 编译:
  • compile:等同于vite的config阶段,能够获得最终生成的config文件,如果需要添加一些环境值的占位符,可以在这个阶段介入
js 复制代码
compiler.hooks.compiler.tap('插件名',()=>{
    compiler.options.plugins.push(
        new webpack.DefinePlugin({
          'process.env.APP_VERSION': JSON.stringify(PLACEHOLDER),
        })
    );
    console.log('✅ 已注入APP_VERSION占位符:', PLACEHOLDER);
})
  • compilation: 内部包含整个打包构建流程,像是buildModule和optimize等等,实际打包实例已经创建完成,一般这个阶段可以拿到文件最终的contenthash值
js 复制代码
compiler.hooks.compilation.tap('ContentHashReplacePlugin', () => {
  this.contentHash = this.generateContentHash();
  console.log('✅ 生成真实contentHash:', this.contentHash);
});
  1. 输出:
  • emit: 异步钩子!必须和callback和tapAsync结合使用!准备将数据写入磁盘,这个阶段可以把环境值的占位符替换成真正的数据
js 复制代码
compiler.hooks.emit.tapAsync('MyPlugin', (compilation, callback) => {
  // 遍历所有输出的资源
  for (const [filename, source] of Object.entries(compilation.assets)) {
    if (filename.endsWith('.js')) {
      // 读取原内容,添加版权注释
      const content = source.source();
      const newContent = `/* 版权所有 © 2025 MyProject */\n${content}`;
      // 替换资源内容
      compilation.assets[filename] = {
        source: () => newContent,
        size: () => newContent.length
      };
    }
  }
  callback(); // 异步钩子必须调用 callback 结束
});
  1. 结束:
  • done: 构建完成之后输出一些日志信息,生成报告

tap和tapAsync的区别:

同步钩子和异步钩子调用时候的函数。

tapAsync必须和callback结合使用,用于通知webpack异步流程已经结束,可以继续接下来的流程,不然会卡住。

Plugin: 用于webpack打包生命周期中执行的一些函数,比如css和图片压缩的plugin,无视打包模块的IgnorePlugin

Loader: 用于代码转换,因为浏览器只能解析html,css和js,所以会有各种loader将浏览器没法解析的东西转换成能解析的语言,同时webpack本身无法识别一些文件,也需要Loader做转换,比如css-loader,sass-loader,ts-loader,style-loader,postcss-loader

(1.1) css-loader:因为webpack没办法识别css文件,webpack其实只能理解js和json,所以才会使用需要css-loader去处理css文件引用,将其转为模板字符串

(1.2) style-loader: 将css-loader生成的样式字符串注入到style标签中

(1.3) postcss-loader: 对css做兼容处理,自动增加前缀

执行顺序是postcss-loader->css-loader->style-loader,而配置的时候需要从右向左配置,顺序错误,会导致报错

Loader整体执行阶段类似于洋葱模型,从左到右依次遍历对应的loader,再从右到左执行对应的loader

js 复制代码
module.exports = {
  module: {
    rules: [
      {
        test: /.css$/,
        use: ['style-loader', 'css-loader',  'postcss-loader']
      }
    ]
  }
};

vite自身没有loader,可以通过装插件来配置loader,但是没有原生好用,而且vite很多loader功能都原生内嵌了,而且因为工具特性,vite依赖es模块,而浏览器是完全支持es模块的,无需loader做模块转换,整体上都是依靠plugin进行处理

相关推荐
@大迁世界2 小时前
JavaScript 框架的终结
开发语言·前端·javascript·ecmascript
PPPPickup2 小时前
easychat项目复盘---管理端系统设置
java·开发语言·前端
梦6502 小时前
Vue 实现动态路由
前端·javascript·vue.js
姜糖编程日记2 小时前
C++——初识(2)
开发语言·前端·c++
丶乘风破浪丶2 小时前
Vue项目中判断相同请求的实现方案:从原理到实战
前端·javascript·vue.js
why技术2 小时前
如果让我站在科技从业者的角度去回看 2025 年,让我选一个词出来形容它,我会选择“vibe coding”这个词。
前端·后端·程序员
worxfr3 小时前
CSS Flexbox 布局完全指南
前端·css
0思必得03 小时前
[Web自动化] JS基础语法与数据类型
前端·javascript·自动化·html·web自动化
Dreamcatcher_AC3 小时前
前端面试高频问题解析
前端·css·html