进阶篇
以⼯程化的⽅式组织 webpack 构建配置,和 webpack 打包优化
一、编写可维护的 webpack 构建配置
构建配置抽离成 npm 包的意义
通用性
-
业务开发者无需关注构建配置
-
统一团队构建脚本
可维护性
-
构建配置合理的拆分
-
README 文档、ChangeLog 文档等
质量
-
冒烟测试、单元测试、测试覆盖率
-
持续集成
构建配置管理的可选方案
通过多个配置文件管理不同环境的构建,webpack --config 参数进行控制
将构建配置设计成一个库,比如:hjs-webpack、Neutrino、webpack-blocks
抽成一个工具进行管理,比如:create-react-app, kyt, nwb
将所有的配置放在一个文件,通过 --env 参数控制分支选择
构建配置包设计
通过多个配置文件管理不同环境的 webpack 配置
-
基础配置:webpack.base.js
-
开发环境:webpack.dev.js
-
生产环境:webpack.prod.js
-
SSR环境:webpack.ssr.js
抽离成一个 npm 包统一管理
-
规范:Git commit日志、README、ESLint 规范、Semver 规范
-
质量:冒烟测试、单元测试、测试覆盖率和 CI
通过 webpack-merge 组合配置
merge = require("webpack-merge")
...
merge(
... { a: [1], b: 5, c: 20 },
... { a: [2], b: 10, d: 421 }
... )
{ a: [ 1, 2 ], b: 10, c: 20, d: 421 }
合并配置:module.exports = merge(baseConfig, devConfig);
功能模块设计
目录结构设计
+ |- /test // test 放置测试代码
+ |- /lib // lib 放置源代码
+ |- webpack.dev.js
+ |- webpack.prod.js
+ |- webpack.ssr.js
+ |- webpack.base.js
+ |- README.md
+ |- CHANGELOG.md
+ |- .eslinrc.js
+ |- package.json
+ |- index.js
使用 ESLint 规范构建脚本
// 使用 eslint-config-airbnb-base
// eslint --fix 可以自动处理空格
module.exports = {
"parser": "babel-eslint",
"extends": "airbnb-base",
"env": {
"browser": true,
"node": true
}
};
冒烟测试 (smoke testing)
冒烟测试是指对提交测试的软件在进行详细深入的测试之前而进行的预测试,这种
预测试的主要目的是暴露导致软件需重新发布的基本功能失效等严重问题。
冒烟测试执行
构建是否成功
每次构建完成 build 目录是否有内容输出
-
是否有 JS、CSS 等静态资源文件
-
是否有 HTML 文件
判断构建是否成功
在示例项目里面运行构建,看看是否有报错
判断基本功能是否正常
编写 mocha 测试用例
-
是否有 JS、CSS 等静态资源文件
-
是否有 HTML 文件
单元测试与测试覆盖率
编写单元测试用例
单元测试接入
-
安装 mocha + chai
npm i mocha chai -D
-
新建 test 目录,并增加 xxx.test.js 测试文件
-
在 package.json 中的 scripts 字段增加 test 命令
"scripts": {
"test": "node_modules/mocha/bin/_mocha”},
-
执行测试命令
npm run test
持续集成的作用
优点:
-
快速发现错误
-
防止分支大幅偏离主干
核心措施是,代码集成到主干之前,必须通过自动化测试。只要有一个测试用例失败,就不能集成。
Github 最流行的 CI
接入 Travis CI
-
travis-ci.org/ 使用 GitHub 账号登录
-
在 travis-ci.org/account/rep… 为项目开启
-
项目根目录下新增 .travis.yml
travis.yml 文件内容
install 安装项目依赖
script 运行测试用例
发布到 npm
添加用户: npm adduser
升级版本
升级补丁版本号:npm version patch
升级小版本号:npm version minor
升级大版本号:npm version major
发布版本:npm publish
Git 规范和 Changelog 生成
良好的 Git commit 规范优势:
-
加快 Code Review 的流程
-
根据 Git Commit 的元数据生成 Changelog
-
后续维护者可以知道 Feature 被修改的原因
技术方案
提交格式要求
本地开发阶段增加 precommit 钩子
Changelog 生成
开源项目版本信息案例
遵守 semver 规范的优势
优势:
-
避免出现循环依赖
-
依赖冲突减少
语义化版本(Semantic Versioning)规范格式
主版本号:当你做了不兼容的 API 修改,
次版本号:当你做了向下兼容的功能性新增,
修订号:当你做了向下兼容的问题修正。
先行版本号
先行版本号可以作为发布正式版之前的版本,格式是在修订版本号后面加上一个连接 号(-),再加上一连串以点(.)分割的标识符,标识符可以由英文、数字和连接号 ([0-9A-Za-z-])组成。
-
alpha:是内部测试版,一般不向外部发布,会有很多 Bug。一般只有测试人员使用。
-
beta:也是测试版,这个阶段的版本会一直加入新的功能。在 Alpha 版之后推出
-
rc:Release Candidate) 系统平台上就是发行候选版本。RC 版不会再加入新的功能了,主要着重于除错。
二、webpack 构建速度和体积优化策略
初级分析:使用 webpack 内置的 stats
stats: 构建的统计信息
package.json 中使用 stats
Node.js 中使用
速度分析:使用 speed-measure-webpack-plugin
速度分析插件作用
分析整个打包总耗时
每个插件和loader的耗时情况
webpack-bundle-analyzer 分析体积
可以分析哪些问题?
依赖的第三方模块文件大小
业务里面的组件代码大小
使用高版本的 webpack 和 Node.js
使用 webpack4:优化原因
多进程/多实例构建:资源并行解析可选方案
多进程/多实例:使用 HappyPack 解析资源
多进程/多实例:使用 thread-loader 解析资源
多进程/多实例:并行压缩
方法一:使用 parallel-uglify-plugin 插件
方法二:uglifyjs-webpack-plugin 开启 parallel 参数
方法三:terser-webpack-plugin 开启 parallel 参数
分包:设置 Externals
进一步分包:预编译资源模块
思路:将 react、react-dom、redux、react-redux基础包和业务基础包打包成一个文件
方法:使用 DLLPlugin 进行分包,DllReferencePlugin对 manifest.jso引用
使用 DLLPlugin 进行分包
使用 DllReferencePlugin 引用 manifest.json
缓存
目的:提升二次构建速度
缓存思路:
-
babel-loader 开启缓存
-
terser-webpack-plugin 开启缓存
-
使用 cache-loader 或者 hard-source-webpack-plugin
缩小构建目标
目的:尽可能的少构建模块
比如 babel-loader 不解析 node_modules
减少文件搜索范围
图片压缩
Imagemin的优点分析
有很多定制选项
可以引入更多第三方优化插件,例如pngquant
可以处理多种图片格式
Imagemin的压缩原理
pngquant: 是一款PNG压缩器,通过将图像转换为具有alpha通道(通常比24/32位PNG文件小60-80%)的更高效的8位PNG格式,可显著减小文件大小。
pngcrush:其主要目的是通过尝试不同的压缩级别和PNG过滤方法来降低PNG IDAT数据流的大小。
optipng:其设计灵感来自于pngcrush。optipng可将图像文件重新压缩为更小尺寸,而不会丢失任何信息。
tinypng:也是将24位png文件转化为更小有索引的8位图片,同时所有非必要的metadata也会被剥离掉
tree shaking(摇树优化)复习
概念:1 个模块可能有多个方法,只要其中的某个方法使用到了,则整个文件都会被打到
bundle 里面去,tree shaking 就是只把用到的方法打入 bundle ,没用到的方法会在uglify 阶段被擦除掉。
使用:webpack 默认支持,在 .babelrc 里设置 modules: false 即可
- production mode的情况下默认开启
要求:必须是 ES6 的语法,CJS 的方式不支持
无用的 CSS 如何删除掉?
PurifyCSS: 遍历代码,识别已经用到的 CSS class
uncss: HTML 需要通过 jsdom 加载,所有的样式通过PostCSS解析,通过document.querySelector 来识别在 html 文件里面不存在的选择器
在 webpack 中如何使用 PurifyCSS?
使用 purgecss-webpack-plugin
和 mini-css-extract-plugin 配合使用
构建体积优化:动态 Polyfill
Promise 的浏览器支持情况
构建体积优化:动态 Polyfill
Polyfill Service原理
构建体积优化:如何使用动态 Polyfill service
polyfill.io 官方提供的服务
基于官方自建 polyfill 服务
//huayang.qq.com/polyfill_service/v2/polyfill.min.js?unknown=polyfill&features=Promise,Map,Set
体积优化策略总结
Scope Hoisting
Tree-shaking
公共资源分离
图片压缩
动态 Polyfill