webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
四个概念entry:入口起点,可以配置多页面。
output:出口,项目编译完成后之后文件输出路径。
loader:webpack 自身只理解 JavaScript,loader 能够去处理非 JavaScript 文件并转化 JavaScript,处理源文件,一次处理一个。
plugins:用来扩展 webpack 功能,插件能够执行很多任务。如:打包优化、压缩等。
核心对象Tapable:控制钩子的发布与订阅。
Compiler:webpack 的编译器,继承 Tapable 对象,可以广播和监听 webpack 事件,webpack 生命周期值存在一个 Compiler 对象。Compiler 在 webpack 启动时创建实例,compiler 实例中包含 webpack 的完整配置,包括 loaders, plugins 信息。
Compilation:编译器编译之后的资源信息对象,继承 Tapable 对象,可以广播和监听 webpack 事件,Compilation 实例仅代表一次 webpack 构建和生成编译资源的的过程。
webpack 开发模式开启 watch 选项,每次检测到入口文件模块变化时,会创建一次新的编译: 生成一次新的编译资源和新的 compilation 对象,这个 compilation 对象包含了当前编译的模块资源 module,编译生成的资源,变化的文件,依赖的的状态。
module、chunk、bundlemodule:js 模块,就是被 require 或 export 的模块,如:ES 模块、commonjs 模块、 AMD 模块。
chunk:代码块,是进行依赖分析的时候,代码分割出来的代码块,包括一个或多个 module,是被分组了的 module 集合,code spliting 之后的就是chunk。
bundle:文件,最终打包出来的文件,通常一个 bundle 对应一个 chunk。
打包原理根据文件间的依赖关系对其进行静态分析,然后将这些模块按指定规则生成静态资源。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图,其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。webpack 有两种组织模块的依赖方式,同步、异步。异步依赖将作为分割点,形成一个新的块;在优化了依赖树之后,每一个异步区块都将作为一个文件被打包。
构建流程生成 options(将 webpack.config.js 和 shell 中的参数合并到 options 对象)。
实例化 compiler 对象 (webpack 全局对象,包含 entry、output、loader、plugins等所有配置对象)。
实例化 compilation 对象(compiler.run 方法执行,开始编译过程,生成 compilation 对象)。
分析入口 js 文件,调用 AST 引擎处理入口文件,生成抽象语法树 AST,根据 AST 构建模块的所有依赖。
通过 loader 处理入口文件的所有依赖,转换为 js 模块,生成 AST,然后继续递归遍历,直至所有依赖被分析完毕。
对生成的所有 module 进行处理,调用 plugins,合并,拆分,生成 chunk。
将 chunk 生成为对应 bundle 文件,输出到目录。
HMR(热更新)模块热替换功能会在应用程序应用过程中进行替换、添加或者删除模块,无需加载整个页面。主要通过以下几种方式:
保留在完全重新加载页面时丢失的应用程序状态。
只更逊变更内容,以节省宝贵的开发时间。
调整样式更加快速,几乎相当于在浏览器调试器中更改样式。
webpack 的热更新,只是提供一套接口和基础的模块替换的实现。开发者需要在代码中通过热更新的接口(module.hot.xxx)向 webpack 声明依赖模块和当前模块是否能够更新,以及更新的前后进行的处理。如果接受更新,那么需要开发者自己来在模块替换前清理或者保留必要的数据、状态,并在模块被替换后恢复之前的数据、状态。在 vue-cli 等脚手架中,热更新的开发者这边的工作是由 vue-loader、css-loader 等加载器已经完成了,再配合 webpack 的 module.hot 等 API 来完成了热更新。
大致热更新流程:webpack 进行文件变化监听,服务端和客户端使用 websocket 进行通信,服务端传递模块变化信息给客户端,客户端根据文件变化消息获取变更模块代码,进行模块的替换。
运行时开启热更新配置,在打包的 bundle 里面包含 HMR runtime 及 websocket 功能。
服务端与客户端建立 websocket 长连接。
webpack 监听文件变化,文件保存时触发 webpack 重新编译,编译后代码保存在内存中。
编译时会生成 hot-update.json (已改动模块的 json)、hot-update.js (已改动模块的 js)。
通过 websocket 向客户端发送 hash 值。
客户端对比 hash 值,一致走缓存,不一致再通过 Ajax 获取 hot-update.json,json 包含模块 hash 值,再通过 jsonp 请求获取 hot-update.js。
热更新 js 模块,若失败,则 live reload 刷新浏览器代替热更新(若模块未配置热更新,则同样 live reload)。
webpack如何管理模块