首页天道酬勤前端的构建工具(webpack发布组件库)

前端的构建工具(webpack发布组件库)

admin 12-21 23:10 174次浏览

作者|娱乐前台开发专家芃苏

编辑| xrpdsb/p耳机| CSDN从视觉中国下载

引言

前端构建工具的发展

请回忆一下2015年到2016年的时候。 开发者们从大量使用Task Runner的Grunt工具开始逐渐转向Gulp这样的Pipeline格式的工具。 Gulp还可以与许多个性化插件(如gulp-streamify )配合使用,以清晰、方便地控制整个前端的准备工作链接,如页面更新、代码编译和压缩等。 自动化的“流水线”工具取代了许多繁杂的手工业者,可以说具有跨时代的意义。 对Webpack来说,其本质是基于“模块化”思想的“JS预编译”解决方案,诞生初期,与之类似的方案有Browserify,与Webpack属于同一派系的有sea.js或requick

现在,许多日常工作接触的项目可以完全抛弃Gulp。 但是,在工作中有时会接触到旧项目,其中Gulp的使用和维护屡见不鲜。 2019年初,通过旧项目“gulp 3.x webpack 3.x”的技术升级,了解到了gulp 4.x的动向,与gulp-browserify和gulp-webpack(5年前发表,现在web 在积极比较Webpack“计划”和Gulp系“工具”时,有必要明确两者解决问题的范围和想法。 现在,再次回顾历史,对于技术发展的变迁顺序,可以有一个基本的、客观的概念。

2017年的时候,Gulp和Webpack在用户的使用率和“继续使用”的意向上还处于伯仲。 但是,从《State of Javascript 2019》可以看出,Webpack完全挤掉了其他工具和类库,成为了屈指可数的广泛使用、备受争议的Build Tool。 2018年2月25日,Webpack发布了4.0.0正式版; 它对许多项目进行了web包4.10.2版的升级; 正月前后,将部分项目升级为4.29.0的最新版本。 在这一系列“跟进式升级”中,一方面不断引入Webpack对模块构建的新思路和理念,以更好地应对未来的变化,另一方面与项目基础设施的优化相结合,提高性能

这次回顾

虽然说web包工具只是前端项目CI流程的一小部分(构建build ),但其本身所涉及的节点知识和管理经验是整个技能。 详细来说,它包含web包特有的软件包和第三方插件生态,并针对相应的babel、typescript、flow.js和eslint配置等多个生态进行了Javascript语言本身的编译/分析另外,要妥善管理本地静态资源文件和远程CDN资源文件路径。 打包配置决定打包结果。 这包括域间的知识、节点层的服务结构、模板结构的知识。 此外,还有令人头疼的问题,如NPM许多软件包的版本控制。 其中细节数不胜数,但在所有第三方工具都正确使用的前提下,可能还有开发者需要自己开发的plugin小工具。 知识谱系之大,显而易见。

本文没有介绍Webpack Docs的使用指南或第三方插件的使用“指向北方”。 结合过去项目的经验,记录从实践中得到的使用技术,也经常记录走弯路带来的问题,希望对其他很多尖端技术人员有一点参考价值。 (数据包校验列表: react :16.3.2、拜尔:7.0. 0、web数据包:4. 29.0、节点: 11.8.0 )

文件结构

4.x版早期的CLI工具集命令随web包主包提供,而4.x版和更高版本的web包CLI作为独立包排除,类似于tnpm run start的脚本其次,在开发/日常环境(dev )和预发布/生产环境) prod中,打包战略有很大不同。

1 .关于dev的日常环境:

有方便的调试和蓝牙输入、比较强的源映射;

粒状性小,且期望根据变动代码进行针对性的加载(live reloading/hotmodulereplacement );

想进行代理服务器代理相关的调试;

可以根据开发者的情况,简单地配置本地的dev-server。

对于Prod生产环境:

通过压缩Ja

vscript/CSS代码,获取更小的文件加载体积;

通过包的拆解来得到更优的加载策略,从而降低load time;

比较轻量的source mapping(当然,zgddd需要一些trace信息做日志和报警的时候是另外一番情景);

线上的产品的一些个性诉求(比如,对同一份Javascript代码也许要匹配不同的样式文件)等。

3. 通常评估效率维度主要有以下几个,稳重提到的数据来源主要属于前三个:

本地开发compile(w/ DLL or NO DLL)

本地开发re-compile(w/ DLL or NO DLL)

本地测试build(webpack analyse分析的重点部分)

云构建时长 (NO DLL or 配置化OSS支撑DLL)

在Webpack的新版本中,webpack-merge: 4.2.1 这个独立包的使用,开发者使用webpack.common.js文件对开发和生产环境中的公共部分进行配置,webpack.dev.js针对开发环境,webpack.prod.js针对生产环境。区分后,两种环境的配置差异,一目了然:

(图:webpack配置文件结构)

关于cz.config.js和flowGlobalVars.js里面“话题点”颇多,不在此处重点描述。

如果需要DLL配置(在后面的优化部分会重点讲),还需要单独加入一个webpack.dll.js打包的配置文件。当然,dll其实也是一个普通的文件Output,我们可以在webpack.common.js文件中module.exports时,写两个区分开。通过这种不是很常见的灵活写法(Exporting multiple configurations),可以更多的去理解文件的I/O和module模块的概念。

基础/自定义配置

▐ CommonsChunkPlugin被取代

被移入到了webpack.optimization.splitChunks中。有关拆包切分和颗粒度控制,这个其实从Webpack的层面已经为我们做了很多优化,自身也是有一套基础默认的优化策略的。类比来看,React生态里面diff算法本身也是有策略机制的,更多的优化,使用者可以在这个对象里面加入回调方法,自己去细化控制。

这里需要特别注意的是cacheGroups,当不明确哪些内容需要被cache时,或者是颗粒度不好把控时,这样的切分会给我们带来非常多的冗余文件。下面的代码中,定义了一个vendors对象,那么我们的output文件(不包含chunksFiles)的每一个都会生成一个cache文件。加入output的有app.bundle.js和polyfill.bundle.js,一旦加入这个vendors对象,打包的时候会额外的生成两份文件,分别是vendors-app.js和vendors-polyfill.js。虽然不用担心这两个文件内容会重新打包代码进去,里面只是放一些cache索引,但这两个文件如果在不确定要用他们来做什么的时候,cacheGroups的设置,需要重新认真去考虑。

▐ OccurrenceOrderPlugin

本身不在是一个webpack类下面的构造器,而是被重新命名(之前的名称因为单词拼写错误了),然后放入到新的位置,调用起来需要重新去书写:new webpack.optimize.OccurrenceOrderPlugin。

▐ terser(默认的内置压缩工具包)

webpack.optimization.minimizer的新版本中,default built-in的工具已经由旧有的uglifyJS变成了terserJS,旧的uglify已经被depreacted处理,相信不久之后的状态就会变成legacy,新的terser更好的性能,对ES6+的语法支持的更多,也同时兼容了babel 7的生态,同步其它第三方库代码压缩后的诉求。目前我在使用的是terser-webpack-plugin,和普通的terser配置的参数上有一些差异,需要自己手动引入(官方文档推荐)。

▐ module.rules.exclude[0]

module.rules.exclude[0]的文件地址书写,要求更加严格(4.11.0以后的版本)。

以往我们在对module.rules做配置时,有些文件不希望被遍历到,那么我们通过exclude这个参数配置,将其跳过,有时候会使用'src/contianer/xx.jsx'这样的写法,如果是多个path索引,那就放到一个Array中就好。但这种写法,在新版本中是不被允许的,我们只能使用path.resolve或/regExp/的写法去声明文件路径地址。(Bonus Basic Tips,如何用正则书写并集和特定路径,如我希望include所有src加上一个指定的npm包: /(src\/.*)|(node_modules\/.*@ali\/lark-components)/)

▐ alias和绝对路径

webpack在打包的时候,通常需要对文件的路径去做查找、搜索,它需要明确知道文件的引用位置和引用关系,从而能够完整的知道整个映射mapping关系。减少这方面的开销,我们可以考虑去配置alias,从而以绝对路径的写法代替大量相对路径写法。好处的话,一方面是帮助webpack更快的去定位文件位置,另一方面书写起来,也不再用被输入 '../../*' 还是 '../../../*' 而困扰。

Webstorm寻找绝对路径:在配置里面对webpack配置项加入webpack文件路径就好,Webstorm IDE会自己找到对应的alias关系。

VSCode寻找绝对路径:插件层面没有发现太好的办法,如果项目正在使用typescript,可以在tsconfig.json里面配置相关的编译项,可以达到和上面Webstorm同样的效果。

▐ 大图片上传CDN

上传CDN后可以大幅减小包体积。另外,webpack也不需要再去关注那些图片的文件索引路径了。项目稍微大一些,本地图片5Mb ~ 10Mb的情况非常普遍,亟待优化。

▐ devServer Proxy的代理能力

去调研这个能力,得益于一次请求层的改造。诉求是希望Token不再显示传递,而是通过塞到Header去实现。在本地开发的环境,我们通常使用jsonp去解决跨域问题,但其本质其实是在网页中嵌入一段<script />,自然也就不能写入Header信息,这个和我们的初衷并不相符,无法满足诉求。所以对于这样的跨域问题,我们通过几个简单的参数配置,在请求发起和请求返回的两端,分别做了代理配置,从而“欺骗”了“源Origin”,得以解决本地开发的跨域问题:

devServer: {// ...headers: {'Access-Control-Allow-Origin': '*', // CORS},proxy: { // for ajax cors'/h5/ajaxObj': {target: 'http://xxx.xxx.xxx.com',onProxyReq: (proxyReq) => {proxyReq.setHeader('Origin', 'http://xxx.xxx.com');},onProxyRes: (proxyRes) => { // …},},},},

优化性能 by Node / Happypack

基础配置和需要的自定义配置已经有了,整个项目的构建时间有可能还是非常不理想的,当前本文提及的测试项目,大概有57s的时间,还是有很多地方没有补足的,可优化的空间非常大。

第一步可以先关注下Node版本,经过测试,是对整体速度可以至少提升30%的事情,尤其是在Node V8版本到V10的时候,以下是之前在另一个项目做技术改造时记录到的数据:

Node版本

v 8.x

v 10.x

compile

32s - 36s

26s

re-compile

8s - 9s

4s

但是这次,在把项目直接升级到了 v 11.x 后发现,有带node-sass的项目编译构建都崩溃了。才意识到,node-sass的版本也需要相应的版本更新。也测试了Babel v 6.x 到 v 7.x 版本的升级效果,本来以为babel的大版本升级会带来显著的编译速度提高,实际上却并不理想(基本可以忽略不计)。

打算开启多线程能力,去处理模块化打包里面那些本是单线程执行的 loaders 们的工作。Happypack的提升效率对整个项目的首次编译而言,效果是20%左右,比较明显。加入Happypack能力的时候,有两点需要注意:

其对file-loader和url-loader的支持不好,可以考虑不加,毕竟我们项目里面图片类(最好上传CDN)的和非常规格式的文件只是小部分;

这次也尝试了把ts-loader加入到多线程中,但是也出现了不少编译问题。大概率怀疑是我个人的配置问题,但过程中去看issues见到了不少ts-loader和ts生态依赖兼容性的问题。目前这个项目.ts只是少数文件,作为一种尝试,大部分文件还都是.jsx和.js,所以针对ts也先不加入Happypack能力了。

优化性能 by DLL/ Optimization

首先需要借助一些工具来进行分析,如:webpack-bundle-analyzer ,通过这个工具我们可以对整个构建(用于生产,Webpack Analyse针对的build过程,不是compile)过程和结果进行数据、图形上的分析,从而得知问题具体出现在了哪里。进而得知DLL所需拆分的内容是什么。以下内容是在第一次分析时得出的:

这个图片的 3532 modules和62 chunks可以看到具体的模块以及chunks划分后的情况。更加直观的我们来看下面这张图,可以看到Parsed的尺寸,入口文件(7.09MB)和主chunk(2.04MB,主要是一些首页就需要加载的node_module)的大小都很夸张,并且node_modules里面的包基本上是一一打包、整整齐齐:

有了这些分析结果,对应解法的思路就很清晰了:首先要抽离常用的node_modules(这是DLL的意义),然后要逐个分析,把不被经常用到的node_module们(仅被某些页面使用,不具有公共特点)也抽出去。

对于React项目中的React、React-Dom、React-router、Redux等,还要一些第三方比较大的库,比如antv或者G2相关的,也要进行DLL抽离了:

modules数量由3532降低到1500,编译时间缩短了三倍

在做了上述DLL的抽离后其实效果已经很明显了,进一步的提升空间,可以对optimization进行了配置(用法详见官方文档):

terser

chunksAll

no mimimizer sourceMap

结尾

本文大概主要介绍了一些工具衍变背景、基础的组织结构和自定义配置,以及如何通过分析工具去来做性能优化,其中很多小的细节没办法一一提到,比如我们看到加载的chunk都是hash值的时候,如何能够辨别是什么组件呢:解法是可以在路由处通过配置moduleName的方式去做:

=> import(/* webpackChunkName: "chunkNameDisplay" */'../containers/UserList/chunkNameDisplay')

诸如此类,实在繁多。随着Webpack 5.x版本的陆续发布和众多团队使用之后,也许很多东西又会有大的改变。并且各种框架的集成已经越来越丰富,更多的解放程序员在工程化维护上的双手,我们关注工程化的演进,看看Webpack生态会给我们带来什么样的惊喜。

SwiftUIiteratingthroughdictionarywithForEach浅谈Java父子类加载顺序css如何实现给元素块加阴影的效果DeepRust匹配:有更好的方法吗?C++构造析构赋值运算函数怎么应用C#中的位操作小结
三类代理问题(网络代理设置是什么意思) pack用法(npm webpack)
相关内容