参考资料
核心概念
Webpack 是一个现代 JavaScript 应用程序的模块打包工具,它的核心概念包括以下几个:
-
入口 (Entry):
-
入口起点指示 webpack 应该使用哪个模块作为构建其内部依赖图的开始。进入入口起点后,webpack 会找出哪些模块和库是入口起点(直接和间接)依赖的。
JavaScriptmodule.exports = { entry: './src/index.js', };
-
-
输出 (Output):
-
输出选项指示 webpack 如何以及在哪里输出它所创建的 bundles,以及如何命名这些文件。
JavaScriptmodule.exports = { output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }, };
-
-
加载器 (Loaders):
-
加载器让 webpack 能够处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。加载器可以将所有类型的文件转换为 webpack 能够处理的有效模块。
JavaScriptmodule.exports = { module: { rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader'], }, ], }, };
-
-
插件 (Plugins):
-
插件用于执行范围更广的任务,包括打包优化、资源管理和注入环境变量等。插件的功能极其强大,可以用来处理各种各样的任务。
JavaScriptconst HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }), ], };
-
-
模式 (Mode):
-
通过选择
development
,production
或none
之中的一个,来设置 webpack 内置的优化。
JavaScriptmodule.exports = { mode: 'development', };
-
-
模块 (Modules):
- 在 webpack 里,一切文件皆模块,通过入口文件来开始,并通过一系列的导入或加载请求来进行模块间的连接。
常用Loader
-
Babel Loader
-
用于将 ES6+ 代码转译为 ES5。
JavaScriptmodule.exports = { module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: 'babel-loader', }, ], }, };
-
-
CSS Loader 和 Style Loader
-
css-loader
使你可以使用类似@import
和url()
的方式实现require()
的功能。 -
style-loader
将 CSS 插入到 DOM 中。
JavaScriptmodule.exports = { module: { rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader'], }, ], }, };
-
-
Sass Loader
-
将 Sass/SCSS 文件编译为 CSS。
JavaScriptmodule.exports = { module: { rules: [ { test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'], }, ], }, };
-
常用Plugin
-
HTML Webpack Plugin (html-webpack-plugin) :
-
生成一个 HTML 文件,并自动注入所有的生成的 bundle。
JavaScriptconst HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { plugins: [ new HtmlWebpackPlugin({ template: './src/index.html', }), ], };
-
-
Clean Webpack Plugin:
-
Webpack 5 中可以通过
output.clean
选项替代clean-webpack-plugin
。
JavaScriptmodule.exports = { output: { path: path.resolve(__dirname, 'dist'), clean: true, // 每次构建前清理 /dist 文件夹 }, };
-
-
Mini CSS Extract Plugin (
mini-css-extract-plugin
):-
提取 CSS 到单独的文件中,而不是在 JavaScript 中内联。需要配合
loader
使用
JavaScriptconst MiniCssExtractPlugin = require('mini-css-extract-plugin'); module.exports = { module: { rules: [ { test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader'], }, ], }, plugins: [ new MiniCssExtractPlugin({ filename: '[name].[contenthash].css', }), ], };
-
-
Hot Module Replacement Plugin (webpack.HotModuleReplacementPlugin):
-
启用热模块替换(HMR),在运行时更新各种模块,而无需完全刷新。
-
在 Webpack 5 中不需要显式添加插件,只需在
devServer
中启用hot
选项。
JavaScriptmodule.exports = { devServer: { contentBase: './dist', hot: true, }, };
-
构建过程
- 初始化阶段
- 在这个阶段,Webpack 从配置文件和命令行参数中读取并解析配置。然后,Webpack 根据配置初始化内部状态和插件系统。
- 读取配置:从
webpack.config.js
文件或命令行参数中读取配置。 - 初始化插件:根据配置文件中的
plugins
选项初始化插件实例。 - 确定入口文件:确定项目的入口文件(
entry
)。
- 构建依赖图
- Webpack 会从入口文件开始,递归地解析所有依赖,形成一个依赖图。
- 解析模块:使用
Loaders
处理非 JavaScript 文件,如 CSS、图片等。每个模块会被递归地解析其依赖。 - 创建模块对象:Webpack 为每个模块创建一个模块对象,并保存在内存中。
- 模块编译
- Webpack 使用相应的
Loaders
将模块的源代码转换为可以在浏览器中运行的 JavaScript 代码。 - 处理模块:通过加载器链对模块进行转换。
- 生成 AST(抽象语法树):Webpack 将模块源代码转换为 AST,以便进一步处理。
- 收集依赖:从 AST 中提取模块的依赖项,并将其加入到依赖图中。
- Webpack 使用相应的
- 生成代码块(Chunks)
- Webpack 会根据依赖图将所有模块分组,形成不同的代码块(Chunks)。这些代码块最终会被打包成一个或多个输出文件。
- 代码拆分:根据配置中的
optimization.splitChunks
等选项,Webpack 会将代码拆分为多个 Chunk。 - 生成 Chunk 对象:Webpack 创建 Chunk 对象并将相关的模块添加到其中。
- 优化阶段
- 优化阶段是确保打包后的代码性能和大小得到提升的关键步骤。Webpack 5 提供了一些内置的优化功能:
- 代码压缩:使用 TerserWebpackPlugin 压缩 JavaScript 代码。
- CSS 压缩:使用 css-minimizer-webpack-plugin 压缩 CSS 代码。
- 代码分割:使用 SplitChunksPlugin 进行代码分割,将公共模块提取到单独的文件中。
- Tree Shaking:移除未使用的代码,减小包的大小。
- 作用域提升:模块合并,提升运行效率。
- 输出阶段
- Webpack 将每个代码块转换为一个或多个输出文件,并将其写入到磁盘上。
- 生成输出文件:Webpack 根据配置中的
output
选项生成最终的输出文件。 - 应用插件:在输出阶段,Webpack 会调用相关的插件(如
HtmlWebpackPlugin
)来处理输出文件。
Webpack优化
开发优化
-
开启模块热替换(HMR)
- 模块热替换可以在不刷新整个页面的情况下更新模块,提高开发效率。
-
使用 Source Maps
- Source Maps 有助于在浏览器中调试原始源代码,而不是转换后的代码。不同类型的 Source Maps 在性能和详细程度上有所不同。
-
优化编译速度
-
使用
cache
和parallel
选项来加速构建过程。
YAMLconst TerserPlugin = require('terser-webpack-plugin'); module.exports = { mode: 'development', optimization: { minimize: true, minimizer: [ new TerserPlugin({ cache: true, parallel: true, sourceMap: true, }), ], }, };
-
-
使用持久化缓存
-
Webpack 5 提供了持久化缓存功能,可以显著提高重复构建的速度。
JavaScriptmodule.exports = { cache: { type: 'filesystem', // 使用文件系统缓存 }, };
-
-
更快的增量编译
-
配置
watchOptions
来优化文件监听,减少不必要的文件扫描。
JavaScriptmodule.exports = { watchOptions: { ignored: /node_modules/, aggregateTimeout: 300, // 防抖延迟 poll: 1000, // 轮询时间 }, };
-
打包优化
-
使用生产模式
-
生产模式下,Webpack 会自动启用各种优化,如压缩代码和启用 Tree Shaking。
JavaScriptmodule.exports = { mode: 'production', };
-
-
启用 Tree Shaking
-
Tree Shaking 可以移除未使用的代码,减小打包后的文件大小。确保使用 ES6 模块语法(
import
和export
)。
JavaScriptmodule.exports = { mode: 'production', optimization: { usedExports: true, }, };
-
-
代码分割
-
使用代码分割技术,将代码拆分为多个文件,以便更好地利用浏览器缓存和加速加载速度。
JavaScriptmodule.exports = { optimization: { splitChunks: { chunks: 'all', }, }, };
-
-
压缩 JavaScript
-
使用
TerserPlugin
压缩 JavaScript 代码。
JavaScriptconst TerserPlugin = require('terser-webpack-plugin'); module.exports = { optimization: { minimize: true, minimizer: [new TerserPlugin()], }, };
-
-
压缩 CSS
-
使用
css-minimizer-webpack-plugin
压缩 CSS 文件。
Javaconst CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); module.exports = { optimization: { minimize: true, minimizer: [ '...', // 保留默认的 minimizer new CssMinimizerPlugin(), ], }, };
-
-
持久化缓存
-
配置持久化缓存,以便在后续构建中复用编译结果。
JavaScriptmodule.exports = { cache: { type: 'filesystem', // 使用文件系统缓存 buildDependencies: { config: [__filename], // 当配置文件变化时,缓存失效 }, }, };
-
-
Bundle 分析
-
使用
webpack-bundle-analyzer
插件可视化和分析打包结果,帮助发现和解决性能瓶颈。
JavaScriptconst { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); module.exports = { plugins: [ new BundleAnalyzerPlugin(), ], };
-
-
懒加载和按需加载
-
使用动态
import()
语法实现懒加载和按需加载模块,优化首次加载时间。
JavaScript// 在你的代码中 import(/* webpackChunkName: "my-chunk-name" */ './myModule').then(module => { // 使用模块 });
-
-
内联 CSS 和 JavaScript
-
在某些情况下,将关键 CSS 和 JavaScript 内联到 HTML 中可以减少 HTTP 请求次数,提高加载速度。
JavaScriptconst HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { plugins: [ new HtmlWebpackPlugin({ template: './src/index.html', minify: { collapseWhitespace: true, removeComments: true, removeRedundantAttributes: true, removeScriptTypeAttributes: true, removeStyleLinkTypeAttributes: true, useShortDoctype: true, }, inject: 'body', }), ], };
-