文章目录
-
- 构建配置包设计
- 功能模块设计
- 目录结构设计
- 构建配置插件
-
- 安装webpack、webpack-cli
- 关联HTML插件html-webpack-plugin
- 解析ES6
- 解析vue、JSX
- 解析CSS、Less和Sass
- 解析图片和字体
- 热更新:webpack-dev-server
- 文件指纹策略:chunkhash、contenthash和hash
- HTML 、CSS和JavaScript代码压缩
- 自动清理构建目录产物
- PostCSS插件autoprefixer自动补齐CSS3前缀
- 静态资源内联
- 使用sourcemap
- Tree Shaking(摇树优化)的使用和原理分析
- Scope Hoisting使用和原理分析
- 代码分割和动态import
- 在webpack中使用ESLint
- 优化构建时命令行的显示日志
- 构建异常和中断处理
- 速度分析:使用 speed-measure-webpack-plugin
- 体积分析:使用webpack-bundle-analyzer
- 多进程/多实例构建
- 多进程并行压缩代码:terser-webpack-plugin 开启 parallel 参数
- 进一步分包:预编译资源模块
- 充分利用缓存提升二次构建速度
- 缩小构建目标与减少文件搜索范围
- 擦除无用的CSS
- 配置其它插件
- 实现源码
构建配置包设计
构建配置管理的可选方案:
- 通过多个配置文件管理不同环境的构建,webpack --config 参数进行控制
- 将构建配置设计成一个库,比如:xxx-webpack
- 抽成一个工具进行管理,比如:create-vue-app
- 将所有的配置放在一个文件,通过 --env 参数控制分支选择
通过多个配置文件管理不同环境的 webpack 配置
- 动态配置项:config.js
- 通用功能:utils.js
- 基础配置:webpack.base.js
- 开发环境:webpack.dev.js
- 生产环境:webpack.prod.js
- 预编译配置:webpack.dll.js
抽离成一个 npm 包统一管理(省略)
- 规范:Git commit日志、README、ESLint 规范、Semver 规范
- 质量:冒烟测试、单元测试、测试覆盖率和 CI
什么是semver 规范?
概念:语义化的版本控制(Semantic Versioning),简称语义化版本,英文缩写为 SemVer
优势:
- 避免出现循环依赖
- 依赖冲突减少
语义化版本(Semantic Versioning)规范格式
- 主版本号: 做了不兼容的 API 修改(进行不向下兼容的修改)
- 次版本号: 做了向下兼容的功能性增加(API 保持向下兼容的新增及修改)
- 修订号: 做了向下兼容的问题修正(修复问题但不影响 API)
通过 webpack-merge 组合配置
const merge = require("webpack-merge")
// 省略其他代码
module.exports = merge(baseConfig, devConfig);
功能模块设计
- 基础配置:webpack.base.js
- 资源解析
- 解析ES6
- 解析vue
- 解析css
- 解析less
- 解析scss
- 解析图片
- 解析字体
- 解析媒体
- 样式增强
- CSS前缀补齐
- CSS px转成rem等
- 目录清理
- 忽略打包内容
- 命令行信息显示优化
- 错误捕获和处理
- CSS提取成一个单独的文件
- 资源解析
- 开发配置:webpack.dev.js
- 代码热更新
- css热更新
- js热更新
- devServer配置
- sourcemap
- 样式压缩(可略)
- 资源拷贝(可略)
- 代码热更新
- 生产配置:webpack.prod.js
- 代码压缩
- 文件指纹
- Tree Shaking(webpack4自带)
- Scope Hositing(webpack4自带)
- 速度优化(基础包CDN等)
- 体积优化(代码分割)
- 资源拷贝(可略)
- 构建报告(可略)
- 构建速度(可略)
- 预编译配置:webpack.dll.js
- 基础库:vue、element-ui等
- 其它库:axios、vue-router等
- 通用功能:utils.js
- CSS加载器
- 资源路径
- 环境变量
- eslint检测配置
- …
- 动态配置项:config.js
- dev: 开发动态配置项
- build:生产动态配置项
目录结构设计
- app-build 放置配置文件
- app-dll 放预编译后的文件
- src(或者lib)放置源代码
- test 放置测试代码(可省略)
结构如下:
+ |- /app-build
+ |- config.js
+ |- utils.js
+ |- webpack.dev.js
+ |- webpack.prod.js
+ |- webpack.base.js
+ |- webpack.dll.js
+ |- /app-dll
+ |- dll.library.min.js
+ |- dll.vendors.min.js
+ |- manifest.library.json
+ |- manifest.vendors.json
+ |- /test
+ |- /src
+ |- .env.development
+ |- .env.production
+ |- .eslintignore
+ |- .eslinrc.js
+ |- .prettierrc
+ |- package.json
+ |- README.md
构建配置插件
安装webpack、webpack-cli
npm i webpack@4 webpack-cli@4.10.0 -D
关联HTML插件html-webpack-plugin
webpack4.x对应的html-webpack-plugin@4
npm install html-webpack-plugin@4 -D
webpack示例配置:
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
]
}
解析ES6
webpack4.x安装@babel/core,@babel/preset-env,babel-loader@8
npm i babel-loader@8 @babel/core @babel/preset-env core-js@3 -D
在根路径下新建一个.babelrc文件,增加ES6的babel preset配置,代码如下:
{
"preset": ["@babel/preset-env"]
}
webpack示例配置:
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader'
}
]
}
解析vue、JSX
安装插件:
npm i @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props vue-loader@15 vue-style-loader@3 vue-template-compiler -D
npm i vue@2 -S
在.babelrc文件中添加JSX相关配置:
{
"presets": [["@babel/preset-env"], "@vue/babel-preset-jsx"]
}
解析CSS、Less和Sass
解析CSS
解析css,需要安装style-loader和css-loader。
其中webpack4.x安装style-loader1.x、css-loader4.x:
npm i css-loader@4 style-loader@1 -D
rules配置:
{
test: /.css$/,
use: ['style-loader', 'css-loader']
}
解析Less
解析less,需要安装less、less-loader。
其中webpack4.x建议安装less-loader@6(less-loader@7.0.1也支持webpack4.x)
npm i less less-loader@6 -D
版本参考:https://github.com/webpack-contrib/less-loader/blob/v6.2.0/package.json
rules配置如下:
{
test: /.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
}
解析sass
安装sass、sass-loader、sass-resources-loader(剔除掉node-sass,深度依赖node版本):
npm i sass@1.32.13 sass-loader@7.3.1 sass-resources-loader@2.2.4 -D
注意:node-sass可以解析/deep/、::v-deep,sass只能解析::v-deep,如果剔除掉node-sass,需要把相关语法升级。像/deep/、::v-deep、:deep()这些是Vue.js框架中用于穿透样式作用域的特定选择器。
以下是对/deep/、::v-deep和:deep() 的对比说明:
| 选择器 | 说明 | 应用示例 |
|---|---|---|
| /deep/ | 是一个用于穿透组件样式作用域的旧版选择器。在某些Vue版本中被移除,不建议使用。 | 在Vue 2.x中,用于穿透样式作用域,如:.parent /deep/ .child { ... } |
| ::v-deep | 是Vue中的一个内置伪选择器,用于访问子组件的样式。它只适用于scoped样式中,并将样式深入到子组件作用域中。 | 在Vue组件的<style scoped>标签中使用,如:.parent ::v-deep .child { ... } |
| :deep() | 是/deep/的替代品,也是一个伪类选择器。适用于全局样式和嵌套组件中的样式,用于穿透样式作用域。 | 可用于Vue组件的<style>标签中,无论是否带有scoped属性,如:.parent :deep(.child) { ... } |
提取CSS
如果需要单独把 CSS 文件分离出来,我们需要使用 mini-css-extract-plugin 插件。
注:v4 版本之后才开始使用 mini-css-extract-plugin,之前的版本是使用 extract-text-webpack-plugin。
安装mini-css-extract-plugin插件:
npm i mini-css-extract-plugin -D
解析图片和字体
资源解析:解析图片
解析图片,可以安装file-loader,其中file-loader最新版本为6.2.0,支持webpack4.x。
npm i file-loader -D
版本参考:https://github.com/webpack-contrib/file-loader/blob/v6.2.0/package.json
rules配置如下:
{
test: /.(png|jpe?g|gif)$/,
use: 'file-loader'
}
资源解析:解析字体
rules配置如下:
{
test: /.(woff|woff2|eot|otf|ttf)$/,
use: 'file-loader'
},
css参考样式:
@font-face {
font-family: 'SourceHeavy';
src: url('./images/SourceHeavy.otf') format('truetype');
}
.search-text {
font-size: 20px;
color: #f00;
font-family: 'SourceHeavy';
}
资源解析:使用url-loader
url-loader 也可以处理图⽚和字体,可以设置较⼩资源⾃动 base64,其中url-loader内部实现也是使用的file-loader。
目前url-loader最新版本为4.1.1,支持webpack4.x.
npm i url-loader -D
版本参考:https://github.com/webpack-contrib/url-loader/blob/master/package.json
rules配置(把之前关于图片的file-loader配置替换):
{
test: /.(png|jpe?g|gif)$/,
use: [{ loader: 'url-loader', options: { limit: 10240 } }],
}
热更新:webpack-dev-server
- webpack-dev-server不刷新浏览器
- webpack-dev-server不输出⽂件,⽽是放在内存中
- 使⽤ HotModuleReplacementPlugin插件
npm i webpack-dev-server@3 -D
package.json示例配置:
"scripts": {
"dev": "webpack-dev-server --open"
}
其中
open是构建完成之后,自动开启浏览器。
文件指纹策略:chunkhash、contenthash和hash
注:文件指纹只能用于生产环境。
文件指纹如何生成
- Hash:和整个项⽬的构建相关,只要项⽬⽂件有修改,整个项⽬构建的hash值就会更改
- Chunkhash:和webpack 打包的chunk 有关,不同的entry 会⽣成不同的chunkhash值
- Contenthash:根据⽂件内容来定义hash ,⽂件内容不变,则contenthash不变
文件指纹设置
- JS文件:设置output的filename,使⽤[chunkhash]。
output: {
path: path.join(__dirname, 'dist'),
filename: '[name]_[chunkhash:8].js'
}
- CSS文件:设置MiniCssExtractPlugin的filename,使⽤[contenthash]
new MiniCssExtractPlugin({
filename: "[name]_[contenthash:8].css"
}),
HTML 、CSS和JavaScript代码压缩
JS压缩
webpack4及以后使用内置optimization,配合自定义压缩插件terser-webpack-plugin使用
npm i terser-webpack-plugin@4 -D
配置示例:
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
// 过滤掉以".min.js"结尾的文件.
exclude: /\.min\.js$/i,
// Enable multi-process parallel running and set number of concurrent runs.
parallel: true,
// Enable file caching. Default path to cache directory: node_modules/.cache/terser-webpack-plugin.
cache: true,
terserOptions: {
// 开启变量名混淆
mangle: true,
compress: {
unused: true,
// 移除所有debugger
drop_debugger: true,
// 移除所有console
drop_console: true,
pure_funcs: [
// 移除指定的指令,如console, alert等
"console.log",
"console.error",
"console.dir"
]
},
format: {
// 删除注释
comments: true
}
},
// 是否将注释剥离到单独的文件中
extractComments: false
})
]
}
CSS压缩
需要安装optimize-css-assets-webpack-plugin,同时使⽤cssnano。
说明:optimize-css-assets-webpack-plugin插件目前官网最新版本5.0.8,使用的webpack为^4.44.1。
npm i optimize-css-assets-webpack-plugin@5 cssnano@4 -D
插件配置地址:https://github.com/NMFR/optimize-css-assets-webpack-plugin/blob/master/package.json
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
module.exports = {
// 其他省略
mode: 'production',
plugins: [
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano'),
}),
],
}
另外官网推荐了另外一个CSS样式插件:css-minimizer-webpack-plugin。如果在开发环境提取的CSS需要压缩,建议使用css-minimizer-webpack-plugin插件,测试压缩速度比optimize-css-assets-webpack-plugin快。
安装:
npm i css-minimizer-webpack-plugin@1.3.0 -D
示例配置:
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
module.exports = {
optimization: {
minimize: true,
minimizer: [
new CssMinimizerPlugin({
test: /\.css$/i
})
]
}
}
HTML压缩
安装html-webpack-plugin,并设置压缩参数。
其中webpack4.x对应的html-webpack-plugin@4。
npm i html-webpack-plugin@4 -D
webpack示例配置:
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src/index.html'),
filename: 'index.html',
chunks: ['index'],
inject: true,
minify: {
html5: true,
collapseWhitespace: true,
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: false,
},
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src/search.html'),
filename: 'search.html',
chunks: ['search'],
inject: true,
minify: {
html5: true,
collapseWhitespace: true,
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: false,
},
})
]
}
自动清理构建目录产物
webpack4.x使用clean-webpack-plugin@3版本:
npm i clean-webpack-plugin@3 -D
webpack配置:
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
plugins: [
new CleanWebpackPlugin(),
]
PostCSS插件autoprefixer自动补齐CSS3前缀
需要安装postcss-loader、postcss、autoprefixer插件。
其中webpack4.x需要安装postcss-loader@4。
npm i postcss-loader@4 postcss@8 autoprefixer -D
示例配置如下:
module.exports = {
module: {
rules: [
{
test: /.css$/,
use: [
'css-loader',
'less-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
[
'autoprefixer',
{
overrideBrowserslist: ['last 2 version', '>1%', 'ios 7']
}
]
]
}
}
}
]
}
]
}
}
静态资源内联
资源内联的意义:
- 代码层⾯:
- ⻚⾯框架的初始化脚本
- 上报相关打点
- css 内联避免⻚⾯闪动
- 请求层⾯:减少 HTTP ⽹络请求数
- ⼩图⽚或者字体内联 (url-loader)
安装raw-loader@0.5.1版本
npm i raw-loader@0.5.1 -D
- raw-loader 内联 html
<%= require('raw-loader!./meta.html') %>
- raw-loader 内联 JS
<%= require('raw-loader!babel-loader!../../node_modules/lib-flexible/flexible.js') %>
示例,例如我们抽离meta通用的代码为一个meta.html,以及flexible.js插件都内联带html页面中。
meta.html示例代码:
<meta charset="UTF-8">
<meta name="viewport" content="viewport-fit=cover,width=device-width,initial-scale=1,user-scalable=no">
<meta name="format-detection" content="telephone=no">
<meta name="keywords" content="keywords content">
<meta name="name" itemprop="name" content="name content">
<meta name="apple-mobile-web-app-capable" content="no">
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
使用sourcemap
作⽤:通过source map定位到源代码
sourcemap参考文章:http://www.ruanyifeng.com/blog/2013/01/javascript_source_map.html
source map 关键字:
- eval: 使⽤eval包裹模块代码
- source map: 产⽣.map⽂件
- cheap: 不包含列信息
- inline: 将.map作为DataURI嵌⼊,不单独⽣成.map⽂件
- module:包含loader的sourcemap
source map 类型:

一般开发环境配置:
module.exports = {
// 其他代码省略
devtool: "source-map"
};
<

最低0.47元/天 解锁文章
1060

被折叠的 条评论
为什么被折叠?



