当前位置: 首页 > 科技观察

《项目实战》优化项目建设时间

时间:2023-03-19 23:01:38 科技观察

背景前几天晚上下班路过隔壁项目组,听他们说项目建设:现在在线打包时间太长了,修一个bug1分钟,release半小时后,心里难受。他们的项目比较大,在线构建时间特别长,基本都在15分钟以上。和他们聊了几句,回头看了看自己项目的构建时间:其实挺长的,就抽空优化了一下,效果还是挺明显的。优化后:正文部分,我分享的内容主要是:提高webpack打包性能的一些配置优化大型项目构建时间的一些思考,希望对大家有所启发。Text我们的项目不是很大,是一个中等规模的国际化项目,也就一百多页。之前本地构建时间挺长的,第一次启动就花了三分钟。后来我配置了Vite,本地启动时间减少到20s左右。有兴趣的可以参考我的文章:【项目实战】Webpack转Vite,加速开发!看了下,线上构建时间五六分钟,不痛不痒,不过应该还有优化的空间,所以打算优化一下。1、发现问题既然要优化构建时间,那么第一步当然是先发现问题,找出耗时阶段,然后再进行优化。这里我使用了SMP插件。SMP插件的用法很简单,这里简单提一下://webpack.config.jsconstSpeedMeasurePlugin=require('speed-measure-webpack-plugin');constsmp=newSpeedMeasurePlugin();module.exports=smp.wrap({//...});使用SMP插件获取各个阶段的打包时间:发现问题发现两个明显的问题:IgnorePlugin耗时近20秒。less-loader部分执行了2次,浪费了一分多钟。ts-loader需要一分半钟,相当长。二、解决问题1、IgnorePlugin查看配置,发现配置中的IgnorePlugin没有达到预期的效果,所以将其删除。2、查看less-loader的配置,发现less部分确实多处理了一次。less文件的处理,可以直接参考官方文档,文档地址:https://webpack.docschina.org/loaders/less-loader/我的配置:{test:/\.less$/,使用:['style-loader','css-loader',{loader:'less-loader',options:{javascriptEnabled:true,sourceMap:true,modifyVars:{//injectourownglobalvars//https://github.com/ant-design/ant-design/issues/16464#issuecomment-491656849hack:`true;@import'${require.resolve('./src/vars.less')}';`,...themeVariables,},limit:10000,name:'[name].[hash:7].[ext]',outputPath:'styles/',},},],},{test:/\.css$/,use:['style-loader','css-loader'],},3.ts-loader中ts-loader部分的优化可以参考:https://webpack.js.org/guides/build-performance/#typescript-loader文档中也有比较清晰的描述:文档建议我们开启transpileOnly选项,关闭类型检查。如果要类型检查,可以使用ForkTsCheckerWebpackPlugin,它会在另一个进程中做相关检查。对于这个插件,我们在优化构建的时候也探索过内存溢出的问题。有兴趣的可以参考我的文章:项目构建内存溢出?查看Nodememorylimit现在我们也启用这个选项。开启后,在本地构建时,本地报警告:这个错误,很熟悉,就是我们之前提到的导入类型的问题:你不知道“导入类型”Fixit:问题解决.重新构建,得到如下结果:经过优化,我们发现IgnorePlugin和HtmlWebpackPlugin的时间大大缩短了。less-loader等恢复正常,只执行一次。ts-loader时间大大缩短,从1分30秒缩短到40秒。局部效果明显,需要在线验证。3、确认在线执行有效后,得到如下结果:然后查看页面,一切正常。完美的!回过头来看,不难发现,其实我并没有太大的改变,而且取得了不错的成绩。对于中小型项目,更改配置往往可以满足我们的要求,但是大型项目呢?例如,具有数十个模块和数百页的项目。回到开头的问题:一分钟修复bug,半小时发布。简单的修改配置并不能减少时间。这个时候怎么办?优化大型项目构建时间的一些思考拆分子应用假设我们有一个近30个大模块的项目:有几十个页面,这种系统的构建时间会比较长,需要进行优化。而且在项目后期,问题会越来越明显,比如:代码越来越臃肿,业务模块本身不相关,构建速度越来越慢,无法独立部署。拆分后的架构:每个子项目都有一个单独的入口,是一个可以独立部署的项目。子工程打包成单独的umd包:主工程启动时加载这些子工程:加载后需要处理routing和store,示例代码://baseexportconstbootstrap=()=>{/...ReactDOM.render((),document.getElementById('root'));returnPromise。resolve();};//mainconstloadSubApp=(htmlEntry:string)=>{returnimportHTML(`${htmlEntry}?${Date.now()}`).then((res:any)=>res.execScripts()).then((exportedValues:any)=>{console.log(`importHTML:${htmlEntry}loaded,exports:`,exportedValues);const{store,router}=exportedValues||{}asany;router&&addCustomRouter(router);store&&addCustomStore(store);}).catch(e=>{console.error('importHTML:${htmlEntry}loaderror:',e);});};constload=()=>{if(__ENV__!=='dev'){constpaths:string[]=[];subAppConfig.subApps.forEach(item=>{if(item.project===localStorage.getItem('ops_project')){paths.push(...item.paths);}});Promise.all(paths.map(path=>loadSubApp(path))).catch(e=>console.log(e)).finally(setAllLoaded);}else{setAllLoaded();}};constinit=()=>{console.log('init:StarttobootstrapthemainAPP');addCustomStore(rootStore);bootstrap().then(()=>{load();});};init();codesharingcommonpackagecomponentutilstypings..externalsreactfamilybucketmomentantd..风格隔离并在样式中添加一个以子项目命名的命名空间:开发调试以ops项目为例,让ops-common包的开发调试像本地文件一样方便:1.让项目编译commonpackage2.wepback别名3.TS别名独立部署同项目上每个子项目申请独立模块拆解子应用的优缺点优点:每个子应用可以独立发布,子应用-模块和主模块是解耦的。子工程可以单独编译,主工程只需要导入,减少主模块的构建时间。缺点:额外的复杂性和维护成本结论一般来说,对于中小型项目,优化打包配置可以解决一些问题。优化大型项目的构建时间,可以考虑拆分子应用的模式。只是这种模式需要考虑一些维护问题,比如如何维护版本标签,如何快速回滚等等,这些需要结合你项目的实际情况再做决定。今天的内容就这些了,希望对你有所启发。