[聚合文章] easywebpack 3.5.0 新特性一览: dll工程化和多进程编译
easywebpack 3.5.0 新特性一览: dll工程化和多进程编译
在 3.5.0 版本之前,项目大以后, webpack 构建打包越来越慢,同时 dll 工程化构建也没有内置支持。虽然可以通过在 easywebpack 中添加 new webpack.DllPlugin() 和 webpack.DllReferencePlugin() 方式实现 dll 方案,但使用起来还是很繁琐: 因为需要先单独为 dll 添加 webpack.config.js 配置, 然后先手动先构建dll,然后在页面里面配置dll的引用,最后再构建页面。easywebpack 3.5.0 从工程化的角度内置支持了。
1 easywebpack 3.5.0 特性一览
- entry include 支持正则配置
- 支持 css extract hot reload
- 支持 webpack dll 配置和自动化构建, 无需手动先构建dll, 然后再构建页面
- 简化 commonsChunk lib 配置, 无需在 onClient 调用 addEntry 设置
- plugins 和 loaders 增加数组的配置的兼容,也就是支持原生配置
- 去掉options节点配置,改为 webpack.config.js 支持原生 Webpack 配置
- 支持多进程 Webpack 编译, 结合dll功能编译速度显著提示,初步测试编译时间减少2/3, 第三方组件越多和页面越多,越明显
- manifest和buildfie合并为新的manifest, 无需 manifest 和 manifestDeps 兼容配置, 同时去掉 buildfie 配置,
- 默认禁用 npm start 启动检查 webpack loader 和 plugin 是否安装的功能, 提高编译速度。
- stylus 和 less loader 默认有开启改为禁用, 减少不必要的安装
- 新增内置插件 webpack-bundle-analyzer 和 stats-webpack-plugin
- node externals 改为 webpack-node-externals 插件实现
- 压缩插件由webpack内置改为 uglifyjs-webpack-plugin 独立插件, 从而支持多进程编译
- easywebpack-cli 增强,提供 dll 编译以及 easy clean 和 easy open 命令。
- 解决 NODE_ENV=production 导致动态安装 npm 依赖失败
- 修复 easywebpack 配置合并覆盖问题
2 Webpack dll 构建
2.1 当前网上流行的 dll 方案
- 1.需要单独写一份 dll 的 webpack 配置文件
- 2.需要手动先编译 webpack dll manifest 文件
- 3.需要在另一份页面 webpack 配置文件中引用 dll manifest 文件
- 4.编译好dll manifest 文件后,再编译页面构建
- 5.构建的 dll.js 文件 和 页面构建生产的 js 文件 手动引入
- 6.dll 配置变更时,需要手动再次重新执行 1 和 4 步骤
2.2 理想中 dll 构建:
- 1.只需要配置 dll 第三方库信息,无需配置完整的 webpack.config.js
- 2.构建时无需手动编译dll,有构建工具底层解决 dll编译和页面编译衔接问题。
- 3.构建底层支持 dll.js 文件 和 页面js 合并注入到页面。
- 4.从底层支持配置变更,自动重新编译dll
2.3 easywebpack dll 方案
easywebpack
3.5.0 版本目前已经解决理想中 dll 构建方案的1,2, 3。 4的支持需要等下个小版本(3.5.x或3.6.0), 这个很快会支持的。
2.3.1 easywebpack dll 配置
只需要在 webpack.config.js
文件添加 dll节点配置即可完成 dll
整个流程。
module.exports = { ... dll:['vue','vuex','axios']}
2.3.2 easywebpack dll 构建流程
使用过 Egg + Vue
或 Egg + React SSR
项目时,本地开发时,我们通过 npm start
一步完成 webpack 编译 和 egg 项目启动,简化了先手动编译 webpack,然后启动egg的流程。Egg 项目是如何解决上面 dll 的问题呢?
- npm start 首次启动时,检查
webpack.config.js
是否配置了dll
节点信息, 如果配置了,同时 manifest-dll.json 文件不存在,则构建 dll.js 文件,同时生成 manifest-dll.json 文件 和 dll 的 资源依赖 manifest.json 文件。 - dll 构建完成后,自动启动 webpack 页面构建,同时把 dll 资源依赖 manifest.json 文件与页面资源依赖 manifest.json 文件进行合并,同时构造好资源依赖。
- webpack 页面构建完成后,自动打开浏览器。
- 下次 npm start 时,因为 manifest-dll.json 文件存在,所以 1 的步骤跳过,直接进行2 和 3,这时候构建速度会显著提升。
- easywebpack-cli 提供 easy clean 清理缓存和 easy open 打开缓存目录命令
常规配置:http://hubcarl.github.io/easywebpack/webpack/base/
3 Egg + Vue/React SSR 多进程编译
在 Egg + Vue/React SSR 项目开发过程中, 服务端渲染需要单独构建服务端运行的文件和客户端运行的文件,这样就涉及两份 webpack 配置。 在原有的方案是在 Egg Agent 里面进行 Webpack 构建的,此时只有 1 个进程编译, 项目大以后构建速度太慢。 在 egg-webpack ^3.2.4, 版本我们进行支持了多进程编译。启动两个进程分别编译 前端构建和Node构建。结合 Webpack dll 功能,通过实际项目测试发现,npm start 启动速度显著提升,其中一个项目构建速度从 90s 减少到 30s 时间,极大提高开发效率。
该修改非必须,如果沿用之前的配置,就表示采用单进程编译
- 如果 webpack.config.js 文件在项目根目录,直接删除 config/config.local.js 文件的 config.webpack 配置即可
- 如果 webpack.config.js 文件不在项目根目录,比如在 build/webpack.config.js,那么需要删除原有的配置,添加如下配置:
config.webpack={ webpackConfigFile: 'build/webpack.config.js'}
4 uglifyjs-webpack-plugin 压缩
Webpack 3 内置的压缩插件 uglifyjs-webpack-plugin
目前还是 0.4.6版本,不支持多进程压缩。官方文档计划在 webpack 4 的时候使用 uglifyjs-webpack-plugin 1.x.x版本。uglifyjs-webpack-plugin 1.x.x版本支持多进程压缩。easywebpack 3.5.0 版本开始不直接显示使用 webpack 内置压缩插件。 如果你显示安装了 uglifyjs-webpack-plugin 1.x.x版本,则会使用 1.x.x 版本进行压缩。
5 commonsChunk 配置简化
easywebpack 3.5.0 版本支持直接 webpack.config.js
文件添加 lib 节点配置即可完成 commonsChunk
公共库的配置。
module.exports = { ... lib:['vue','vuex','axios']}
6 css extract 热更新
easywebpack 在之前的版本支持了 css inline 和 js 的热更新,但不支持 css extract 热更新。 easywebpack 通过取巧的方式支持了 css extract 热更新。easywebpack 构建通过 hotCss 即可开启 css 热更新。
module.exports = { ... hotCss: true}
- 在 Egg + Vue SSR 方案中,无需该配置, 因为开发期间使用的是 css inline 方式,可以满足热更新要求。
- 在 Egg + React SSR 方案中,无需该配置, easywebpack-react 方案已经开启了该开关。
css extract 原理:在研究 Webpack 热更新实现实现原理发现,修改 extract css 时, 虽然不能实现js的模块热更新,但可以通过取巧的方式实现 css 热更新。 当修改修改 extract css 时,webpack 是能够监听到修改的, 同时会发送信息 {"h":"540f0a679c8bcbf12848","c":{"0":true}}
给浏览器, 通过与js修改对比发现, 当修改修改 extract css 时, 是没有模块ID信息的,c节点信息始终是 {}
或 {"0":true}
,这就为css 刷新提供可能。 通过实现 webpack-hot-middleware
提供的 `subscribeAll
方法,对服务端返回的信息进行解析,如果c节点信息是 {}
或 {"0":true}
, 则遍历页面的link css,然后重新设置,让页面无感知刷新。具体代码如下:
var hotClient = require('webpack-hot-middleware/client?noInfo=false&reload=true&quiet=false&autoConnect=false'); var currentHash; hotClient.setOptionsAndConnect({ path: EASY_ENV_HOST_URL + '/__webpack_hmr' }); hotClient.subscribeAll(event => { if (event.action === 'built' && currentHash) { var request = new XMLHttpRequest(); var requestPath = EASY_ENV_PUBLIC_PATH + currentHash + '.hot-update.json'; request.open("GET", requestPath, true); request.timeout = 5000; request.send(null); request.onreadystatechange = function() { if (request.readyState === 4) { if (request.status === 200) { try { var update = JSON.parse(request.responseText); var c = update.c; if (!c || JSON.stringify(c) === '{}' || JSON.stringify(c) === '{"0":true}') { var links = document.getElementsByTagName('link'); for (var i = 0; i < links.length; i++) { var href = links[i].href; if (href && /\.css$/.test(href)) { links[i].href = href; console.log('[HMR] ' + href + ' updated.'); } } } } catch (e) { console.log('Get hot-update.json content error', e); } } } }; } currentHash = event.hash; });
7 内置 jsbundle 文件大小和依赖分析工具
为了方便对 webpack 编译的js 进行大小分析, easywebacpk 内置了 webpack-bundle-analyzer
和 stats-webpack-plugin
两个插件, 请根据需要自行开启。
webpack-bundle-analyzer 插件自带 UI 界面
stats-webpack-plugin 生成 stat.json 文件,然后你需要通过 http://alexkuz.github.io/webpack-chart/或 http://webpack.github.io/analyse/ 工具进行分析。
在 webpack.config.js
需要显示开启,默认是禁用。
module.exports = { ... plugins: { analyzer:true, stats:true }}
8 webpack 原生配置支持
easywebpack的 webpack.config.js
这份配置不是 Webpack 原生的配置文件, 这是专门给 easywebpack-cli
使用的配置文件. 这份配置简化了 Webpack 原生配置, 隐藏众多基础,loader, plugin 等细节, 只提供5个左右的基本配置项, 其中 loader, plugin 通过开关开启就可以使用其功能.在构建时, easywebpack-cli
最终会这份简化的配置转换为 Webpack 原生配置.
考虑到用户的使用习惯,easywebpack >=3.5.0 版本已兼容原生 Webpack 配置项,比如 entry, target, node, resolve, externals, module.noParse, module.alias, module.rules, plugins, devtool, performance等配置。
9 manifest 升级
easywebpack 3.5.0 新增自定义插件 webpack-manifest-resource-plugin(^2.0.2) 替换 webpack-manifest-plugin。 之前的 manifest 依赖关系是在 Egg 运行期间解析的,现在改为构建期组装好资源依赖关系。新生成的 manifest 可以在纯前端项目使用,比如 PWA 场景(easywebpack 计划内置支持 PWA构建, 目前正在调研中......)。
- webpack-manifest-plugin
// ${app_root}/config/manifest.json{ "app/app.js": "/public/js/app/app.2cf6dfd1.js", "app/app.css": "/public/css/app/app.cda9bc64.css", "common.js": "/public/js/common.b59f7169.js", "common.css": "/public/css/common.cda9bc64.css"}
- webpack-manifest-resource-plugin
// ${app_root}/config/manifest.json{ "app/app.js": "/public/js/app/app.2cf6dfd1.js", "app/app.css": "/public/css/app/app.cda9bc64.css", "common.js": "/public/js/common.b59f7169.js", "common.css": "/public/css/common.cda9bc64.css", "deps": { "app/app.js": { "js": [ "/public/js/vendor.337ab787.js", "/public/js/common.b59f7169.js", "/public/js/app/app.2cf6dfd1.js" ], "css": [ "/public/css/common.cda9bc64.css", "/public/css/app/app.cda9bc64.css" ] }}
10 环境变量
为了方便使用, easywebpack 3.5.0 版本 内置了几个可能经常使用的环境变量:
process.env.NODE_ENV
首先会获取用户 process.env.NODE_ENV 值, 如果获取不到,当构建 prod 模式时设置为 production, 否则为 development。 该设置不会影响原有的 process.env.NODE_ENV 系统环境参数。
EASY_ENV_IS_DEV
是否是开发模式(dev)构建
EASY_ENV_IS_TEST
是否是测试环境模式(test)构建
EASY_ENV_IS_PROD
是否是正式环境模式(prod)构建
EASY_ENV_IS_BROWSER
是否是浏览器运行构建模式
EASY_ENV_IS_NODE
否是Node运行构建模式, 也就是 server side render
http://hubcarl.github.io/easywebpack/webpack/env/
11 使用文档
随着 easywebpack 3.5.0 版本的发布, easywebpack 文档进行了重新整理和完善,欢迎查阅:http://hubcarl.github.io/easywebpack
12 相关文档
纯前端项目构建:http://hubcarl.github.io/easywebpack/webpack/base/
Egg + Vue 3.5.0 升级指南:http://hubcarl.github.io/easywebpack/vue/version/
Egg + React 3.5.0 升级指南:http://hubcarl.github.io/easywebpack/react/version/