持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情
webpack 工作基本原理
webpack工作原理流程大概如下:
-
首先 webpack 会读取项目中由开发者定义的 webpack.config.js 配置文件,或者从 shell 语句中获取必要的参数。
-
这是 webpack 内部接收业务配置信息的方式。这样即完成了配置读取的初步工作。
-
将所需的 webpack 插件实例化,在 webpack 事件流上挂载插件钩子,这样在合适的构建过程中,插件就具备了改动产出结果的能力。
-
同时根据配置所定义的入口文件,从入口文件开始,进行依赖收集,对所有依赖的文件进行编译,这个编译过程依赖 loaders ,不同类型的文件根据开发者定义的不同 loader 进行解析。
-
编译好的内容使用 acron 或者其他抽象语法树能力,解析生成抽象语法树,分析文件依赖关系,将不同模块化语法替换为 webpack_require ,即使用 webpack 自己的加载器进行模块化实现。
-
上述步骤完成后,参数结果,根据开发者配置,将结果打包到相应目录。
在整个打包过程中, webpack 和插件都采用给予事件流的发布/订阅模式。监听某些关键过程,并在这些环节中执行插件任务。最后所有文件的编译和转化都已经完成,输出最终的资源结果。
compiler 与 compilation
compiler 与 compilation 这两个对象是 webpack 核心原理中最重要的概念。
-
compiler 对象:他的实例包含了完整的 webpack 配置,且全局只有一个 compiler 实例,因此这种中心化的设计,使得当 webpack 运行,插件实例化时,可以通过这个对象访问 webpack 内部环境。
-
compilation 对象: 当 webpack 以开发模式运行,当检测到文件有变化时,一个新的 compilation 对象将会被创建。
Compiler 模块是 webpack 的主要引擎,它通过 CLI 或者 Node API 传递的所有选项创建出一个 compilation 实例。 它扩展(extends)自 Tapable 类,用来注册和调用插件。 大多数面向用户的插件会首先在 Compiler 上注册。
在为 webpack 开发插件时,你可能需要知道每个钩子函数是在哪里调用的。想要了解这些内容,请在 webpack 源码中搜索 hooks.<hook name>.call。
Compiler 支持可以监控文件系统的 监听(watching) 机制,并且在文件修改时重新编译。 当处于监听模式(watch mode)时, compiler 会触发诸如 watchRun, watchClose 和 invalid 等额外的事件。 通常在 开发环境 中使用, 也常常会在 webpack-dev-server 这些工具的底层调用, 由此开发人员无须每次都使用手动方式重新编译。 还可以通过 CLI 进入监听模式。
编写 webpack plugin
上面我们提到了 webpack 事件流机制,该机制是说,在 webpack 构建的生命周期中, webpack 会广播许多时间。在该机制下,开发者注册的各种插件可以根据需要监听与自身相关的事件。插件捕获事件后,可以在合适的时机通过 webpack 提供的 API 去改变编译结果。
以下生命周期钩子函数,是由 compiler 暴露, 可以通过如下方式访问:
compiler.hooks.someHook.tap('MyPlugin', (params) => {
/* ... */
});
取决于不同的钩子类型,也可以在某些钩子上访问 tapAsync 和 tapPromise
下面是一个以beforeCompile钩子为例子的案例:
AsyncSeriesHook
在创建 compilation parameter 之后执行。
- 回调参数:
compilationParams
初始化 compilationParams 变量的示例如下:
compilationParams = {
normalModuleFactory,
contextModuleFactory,
};
此钩子可用于添加/修改 compilation parameter:
compiler.hooks.beforeCompile.tapAsync('MyPlugin', (params, callback) => {
params['MyPlugin - data'] = 'important stuff my plugin will use later';
callback();
});