只能识别 js
概念:
loader 加载器,主要用于代码转换,比如 JS 代码降级,CSS 预编译、模块化等
plugin 插件,webpack 打包流程中每个环节都提供了钩子函数,可以利用这些钩子函数参与到打包生命周期中,更改或增加 webpack 的某些功能,比如生成页面和 css 文件、压缩打包结果等
module 模块。webpack 将所有依赖均视为模块,无论是 js、css、html、图片,统统都是模块
entry 入口。打包过程中的概念,webpack 以一个或多个文件作为入口点,分析整个依赖关系。
chunk 打包过程中的概念,一个 chunk 是一个相对独立的打包过程,以一个或多个文件为入口,分析整个依赖关系,最终完成打包合并
bundlewebpack 打包结果
tree shaking 优化。在打包结果中,去掉没有用到的代码(es6 静态模块化)。
HMR 热更新。是指在运行期间,遇到代码更改后,无须重启整个项目,只更新变动的那一部分代码。
dev server 开发服务器。在开发环境中搭建的临时服务器,用于承载对打包结果的访问 hash:
hashhash 是跟整个项目的构建相关,只要项目里有文件更改,整个项目构建的 hash 值都会更改,并且全部文件都共用相同的 hash 值
chunkhash 每个打包过程单独的 hash 值,如果一个项目有多个 entry,则每个 entry 维护自己的 chunkhash。
contenthash 每个文件内容单独的 hash 值,它和打包结果文件内容有关,只要文件内容不变,contenthash 不变。
treeshaking:
tree-shaking 仅支持 ESM 的静态导入语法,对于 CMJ 或者 ESM 中的动态导入不支持 tree shaking。
- 标记 webpack 在分析依赖时,会使用注释的方式对导入和导出进行标记,对于模块中没有被其他模块用到的导出标记为 unused harmony export
- 删除之后在 Uglifyjs (或者其他类似的工具) 步骤进行代码精简,把标记为无用的代码删除。
打包原理:
- 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数
- 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译
- 确定入口:根据配置中的 entry 找出所有的入口文件
- 编译模块:从入口文件出发,调用所有配置的 loader 对模块进行翻译,再把翻译后的内容转换成 AST,通过对 AST 的分析找出该模块依赖的模块,再 递归 本步骤直到所有入口依赖的文件都经过了本步骤的处理
- 完成模块编译:在经过第 4 步使用 loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的 依赖关系图
- 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会
- 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统
热更新原理:
当开启热更新后,页面中会植入一段 websocket 脚本,同时,开发服务器也会和客户端建立 websocket 通信,当源码发生变动时,webpack 会进行以下处理:
- webpack 重新打包
- webpack-dev-server 检测到模块的变化,于是通过 webscoket 告知客户端变化已经发生
- 客户端收到消息后,通过 ajax 发送请求到开发服务器,以过去打包的 hash 值请求服务器的一个 json 文件
- 服务器告诉客户端哪些模块发生了变动,同时告诉客户端这次打包产生的新 hash 值
- 客户端再次用过去的 hash 值,以 JSONP 的方式请求变动的模块
- 服务器响应一个函数调用,用于更新模块的代码
- 此时,模块代码已经完成更新。客户端按照之前的监听配置,执行相应模块变动后的回调函数。
加快打包速度:
- noParse 很多第三方库本身就是已经打包好的代码,对于这种代码无须再进行解析,可以使用 noParse 配置排除掉这些第三方库
- externals 对于一些知名的第三方库可以使用 CDN,这部分库可以通过 externals 配置不进行打包
- 限制 loader 的范围在使用 loader 的时候,可以通过 exclude 排除掉一些不必要的编译,比如 babel-loader 对于那些已经完成打包的第三方库没有必要再降级一次,可以排除掉
- 开启 loader 缓存可以利用 cache-loader 缓存 loader 的编译结果,避免在源码没有变动时反复编译
- 开启多线程编译可以利用 thread-loader 开启多线程编译,提升编译效率
- 动态链接库对于某些需要打包的第三方库,可以使用 dll 的方式单独对其打包,然后 DLLPlugin 将其整合到当前项目中,这样就避免了在开发中频繁去打包这些库