easywebpack 3.5.0 新特性一览: dll工程化和多进程编译

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