Webpack源码浅析

本文深入剖析了Webpack的启动方式,包括直接启动和通过引入包启动。重点解析了Webpack的编译起点,如Compiler和Compilation类,以及process、compiler.run()、compiler.compile()、compilation.seal()和compiler.hooks.emit.callAsync()等关键步骤。Webpack通过Compiler实例化和Compilation对象处理模块依赖关系,形成依赖树,并在编译完成后输出文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

webpack启动方式

webpack有两种启动方式:

  1. 通过webpack-cli脚手架来启动,即可以在Terminal终端直接运行;
    webpack ./debug/index.js --config ./debug/webpack.config.js
    
  2. 通过require('webpack')引入包的方式执行;其实第一种方式最终还是会用require的方式来启动webpack,可以查看./bin/webpack.js文件

webpack编译的起点

const compiler = webpack(config)开始

webpack函数源码(./lib/webpack.js):

const webpack = (options, callback) => {
    let compiler = createCompiler(options)
    // 如果传入callback函数,则自启动
    if(callback){
        compiler.run((err, states) => {
            compiler.close((err2)=>{
                callbacl(err || err2, states)
            })
        })
    }
    return compiler
}

webpack函数执行后返回compiler对象,在webpack中存在两个非常重要的核心对象,分别为compilercompilation,它们在整个编译过程中被广泛使用。

  • Compiler类(./lib/Compiler.js):webpack的主要引擎,在compiler对象记录了完整的webpack环境信息,在webpack从启动到结束,compiler只会生成一次。你可以在compiler对象上读取到webpack config信息,outputPath等;
  • Compilation类(./lib/Compilation.js):代表了一次单一的版本构建和生成资源。compilation编译作业可以多次执行,比如webpack工作在watch模式下,每次监测到源文件发生变化时,都会重新实例化一个compilation对象。一个compilation对象表现了当前的模块资源、编译生成资源、变化的文件、以及被跟踪依赖的状态信息。

两者的区别?
compiler代表的是不变的webpack环境; compilation代表的是一次编译作业,每一次的编译都

### Webpack 源码结构与实现原理 Webpack 是一种用于构建 JavaScript 应用程序的静态模块打包器,其核心目标是以一致且开放的方式加载和处理各种资源文件。以下是对其源码结构和实现原理的深入分析: #### 1. **初始化阶段** Webpack 的初始化阶段主要负责解析配置文件 `webpack.config.js` 或者通过命令行传递的参数来生成最终的配置选项。此阶段的核心任务是从配置中提取入口文件、插件列表以及其他必要的设置。 - 配置文件的作用在于定义项目的构建规则,例如入口文件路径、输出目录以及所使用的 Loader 和 Plugin[^3]。 - 初始化过程中会创建一个 Compiler 实例,它是整个构建流程的核心对象。Compiler 对象包含了所有的配置信息,并提供了钩子函数以便于扩展功能[^4]。 #### 2. **Compiler 核心机制** Compiler 是 Webpack 中最重要的类之一,它代表了一个完整的编译过程。当启动 Webpack 时,首先会实例化一个 Compiler 对象。随后,该对象会触发一系列生命周期事件(如 beforeRun、run、emit 等),并通过这些事件驱动整个构建流程。 - 在 Compiler 的内部,有一个名为 Compilation 的子对象,专门用来表示单次具体的编译操作。每次重新编译都会生成一个新的 Compilation 实例。 - Compiler 使用 Tapable 插件库实现了事件监听器模式,允许开发者在不同阶段注入自定义行为。 #### 3. **Loader 执行机制** Loaders 是 Webpack 处理非 JavaScript 文件的关键组件。它们按照链式调用的方式依次转换输入文件的内容。为了支持复杂的转换需求,Webpack 提供了一种称为 Pitching Loaders 的特殊机制。 - 当遇到某个文件需要被多个 loaders 加载时,Webpack 不会简单地按顺序逐一执行,而是先让所有 loader 的 pitch 方法逆序运行。这样可以提前决定某些 loader 是否参与实际转化逻辑[^5]。 下面是一个简化版的 runLoaders 函数实现示例: ```javascript exports.runLoaders = function (options, callback) { const context = createContext(options); const processOptions = { resourceBuffer: null }; iteratePitchingLoaders(processOptions, context, (err, result) => { if (err) return callback(err, {}); callback(null, { result, resourceBuffer: processOptions.resourceBuffer }); }); }; ``` #### 4. **Plugin 注册与执行** Plugins 则是在更高层次上影响构建流程的行为单元。不同于仅限于特定类型的文件处理的 loaders,plugins 可以介入到整个编译周期内的任意环节。 - Plugins 主要是通过订阅 compiler 上的各种 hooks 来完成各自的任务。例如 HtmlWebpackPlugin 就会在 compilation 完成之后自动插入 HTML 文档所需的脚本链接[^3]。 - Webpack 内部利用 tapable 库提供的同步/异步 hook 类型(SyncHook、AsyncParallelHook 等)连接 plugin 功能点与 main thread 流程。 #### 5. **总结** 综上所述,Webpack 的强大之处不仅体现在它可以灵活组合各类工具形成统一解决方案方面,更重要的是它的高度可定制性和清晰分离的关注点——即由 core engine 负责基础架构搭建,而具体业务则交予 plugins 和 loaders 去实现。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值