介绍
webpack 是一个用于现代 JavaScript 应用程序的_静态模块打包工具_,
在业务中写的各种格式的文件通过特定的加载器(Loader)编译后,最终统一生成.js、.css、.png等静态资源文件
在webpack的世界里,一张图片、一个css甚至一个字体,都称为模块(Module),彼此存在依赖关系,webpack就是来处理模块间的依赖关系的,并把它们进行打包
适用场景
webpacke的主要是要场景是单页面富应用(SPA),SPA通常是由一个html文件和一堆按需加载的js组成
核心概念
- Entry(入口):webpack开始构建的入口模块,其作用是告诉webpack从哪里开始寻找依赖,并且编译
- Output(出口): 如何命名输出文件,以及输出目录,比如常见的dist目录,其作用是用来配置编译后的文件存储位置和文件名
- Loaders(加载器):通过安装不同的加载器可以对各种后缀名的文件进行处理,如css样式文件,需要用到css-loader和style-loader,.vue格式的文件可使用vue-loader进行处理,使用url-loader和file-loader来支持图片、字体等文件
- Plugins(插件):更多的是优化,提取精华(公共模块去重),压缩处理(css/js/html)等,对webpack功能的扩展。
webpack构建流程
Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:
- 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数
- 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译
- 确定入口:根据配置中的 entry 找出所有的入口文件
- 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理
- 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会
- 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统
模块打包原理
Webpack 实际上为每个模块创造了一个可以导出和导入的环境,本质上并没有修改 代码的执行逻辑,代码执行顺序与模块加载顺序也完全一致。
webpack常用loader
- sass-loader:将SCSS/SASS代码转换成CSS
- less-loader:将less代码转换成css
- css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
- style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS
- babel-loader:把 ES6 转换成 ES5
- ts-loader: 将 TypeScript 转换成 JavaScript
- eslint-loader:通过 ESLint 检查 JavaScript 代码
- tslint-loader:通过 TSLint检查 TypeScript 代码
- vue-loader:加载 Vue.js 单文件组件
- json-loader 加载 JSON 文件(默认包含)
- image-loader:加载并且压缩图片文件
- svg-inline-loader:将压缩后的 SVG 内容注入代码中
- file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件 (处理图片和字体)
- url-loader:与 file-loader 类似,区别是用户可以设置一个阈值,大于阈值会交给 file-loader 处理,小于阈值时返回文件 base64 形式编码 (处理图片和字体)
- i18n-loader: 国际化
- source-map-loader:加载额外的 Source Map 文件,以方便断点调试raw-loader:加载文件原始内容(utf-8)
- cache-loader: 可以在一些性能开销较大的 Loader 之前添加,目的是将结果缓存到磁盘里
webpack常用plugin
- html-webpack-plugin:简化 HTML 文件创建 (依赖于 html-loader)(将新生成的 index.html 文件,替换原来的的)
- clean-webpack-plugin:目录清理(将/dist 文件夹中旧的文件清理掉)
- mini-css-extract-plugin:分离样式文件,CSS 提取为独立文件,支持按需加载 (替代extract-text-webpack-plugin)
- web-webpack-plugin:可方便地为单页应用输出 HTML,比 html-webpack-plugin 好用
- serviceworker-webpack-plugin:为网页应用增加离线缓存功能
- define-plugin:定义环境变量 (Webpack4 之后指定 mode 会自动配置)
- ignore-plugin:忽略部分文件
- uglifyjs-webpack-plugin:不支持 ES6 压缩 (Webpack4 以前)
- terser-webpack-plugin: 支持压缩 ES6 (Webpack4)
- ModuleConcatenationPlugin: 开启 Scope Hoisting
- speed-measure-webpack-plugin: 可以看到每个 Loader 和 Plugin 执行耗时 (整个打包耗时、每个 Plugin 和 Loader 耗时)
- HotModuleReplacementPlugin:模块热替换
- webpack-merge:提取公共配置,减少重复配置代码
- webpack-dashboard:可以更友好的展示相关打包信息。
Loader和Plugin的区别
Loader(加载器) 本质就是一个函数,在该函数中对接收到的内容进行转换,返回转换后的结果。 因为 Webpack 只认识 JavaScript,所以 Loader 就成了翻译官,对其他类型的资源进行转译的预处理工作。
Plugin 就是插件,可以扩展 Webpack 的功能,在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
Loader 在 module.rules 中配置,作为模块的解析规则,类型为数组。每一项都是一个 Object,内部包含了 test(类型文件)、loader、options (参数)等属性。
Plugin 在 plugins 中单独配置,类型为数组,每一项是一个 Plugin 的实例,参数都通过构造函数传入
tree shaking原理
ES6的模块引入是静态分析的,故而可以在编译时正确判断到底加载了什么代码。 分析程序流,判断哪些变量未被使用、引用,进而删除此代码。
- 前提是模块必须采用ES6Module语法,因为treeShaking依赖ES6的静态语法:import 和 export。如果项目中使用了babel的话, @babel/preset-env默认将模块转换成CommonJs语法,因此需要设置module:false,webpack2后已经支持ESModule。
- webpack对模块打标记 && 压缩工具uglifyjs-webpack-plugin
常看相关文档
官方文档:www.webpackjs.com/guides/ 掘金文章:juejin.cn/post/685988… juejin.cn/post/684490…