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进行处理

相关推荐
wangbing112514 分钟前
ES6 (ES2015)新增的集合对象Set
前端·javascript·es6
nvd1131 分钟前
企业级 LLM 实战:在受限环境中基于 Copilot API 构建 ReAct MCP Agent
前端·copilot
Dragon Wu41 分钟前
TailWindCss cva+cn管理样式
前端·css
烤麻辣烫1 小时前
Web开发概述
前端·javascript·css·vue.js·html
Front思1 小时前
Vue3仿美团实现骑手路线规划
开发语言·前端·javascript
徐同保1 小时前
Nano Banana AI 绘画创作前端代码(使用claude code编写)
前端
Ulyanov1 小时前
PyVista与Tkinter桌面级3D可视化应用实战
开发语言·前端·python·3d·信息可视化·tkinter·gui开发
计算机程序设计小李同学1 小时前
基于Web和Android的漫画阅读平台
java·前端·vue.js·spring boot·后端·uniapp
lkbhua莱克瓦241 小时前
HTML与CSS核心概念详解
前端·笔记·html·javaweb
沛沛老爹1 小时前
从Web到AI:Agent Skills CI/CD流水线集成实战指南
java·前端·人工智能·ci/cd·架构·llama·rag