前言
最近零零散散的对刚接手的一个新项目做了一些优化,白屏、打包相关的内容都涉及到了,写一篇文章来记录一下。
白屏相关
DNS预解析、资源预加载
对于项目中有很多静态资源涉及到的公共域名,如g.alicdn.cmon,采用DNS预连接 + 解析:
对于项目中一些必要的JS资源,采用资源预加载,可以大幅度缩短资源加载时间:
结果:整体白屏时间降低400~600ms。
页面级路由懒加载
原本项目打包出来的JS文件只有一个bundle.js,涵盖了整个项目的业务代码,对于业务方来说来说,可能访问最多的就是新增和详情两个页面,所以对于首屏加载是不友好的,应该优化成访问哪个页面加载对应页面的资源,基于Ice2.0调研,将路由中的组件都转换为懒加载模式:
routes.ts
import { lazy, IRouterConfig } from 'ice'; // ice不支持layout组件设置为懒加载 import Layout from '@/layouts/BasicLayout'; const Home = lazy(() => import(/* webpackChunkName: 'Home' */ '@/pages/Home')); const NotFound = lazy(() => import(/* webpackChunkName: 'NotFound' */ '@/components/NotFound')); const ManualDetect = lazy(() => import(/* webpackChunkName: 'ManualDetect' */ '@/pages/ManualDetect')); const AddMission = lazy(() => import(/* webpackChunkName: 'addMission' */ '@/pages/ReconnaissanceMission/add-mission')); const MissionDetail = lazy( () => import(/* webpackChunkName: 'missionDetail' */ '@/pages/ReconnaissanceMission/missionDetail'), ); const NewMissionDetail = lazy( () => import(/* webpackChunkName: 'newMissionDetail' */ '@/pages/ReconnaissanceMission/newMissionDetail'), ); const NoPermission = lazy(() => import(/* webpackChunkName: 'NoPermission' */ '@/pages/NoPermission')); const Board = lazy(() => import(/* webpackChunkName: 'Board' */ '@/pages/Board')); const BusinessInsight = lazy(() => import(/* webpackChunkName: 'BusinessInsight' */ '@/pages/BusinessInsight')); const ChuangDaoInsight = lazy(() => import(/* webpackChunkName: 'ChuangDaoInsight' */ '@/pages/ChuangDaoInsight')); const Report = lazy(() => import(/* webpackChunkName: 'Report' */ '@/pages/Report')); const routes: IRouterConfig[] = [ { path: '/', component: Layout, children: [ { path: '/manualDetect', component: ManualDetect, }, { path: '/addMission', component: AddMission, }, { path: '/MissionDetail', component: MissionDetail, }, { path: '/newMissionDetail', component: NewMissionDetail, }, { path: '/', exact: true, component: Home, }, { path: '/noPermission', exact: true, component: NoPermission, }, { path: '/board', exact: true, component: Board, }, { path: '/businessInsight', exact: true, component: BusinessInsight, }, { path: '/chuangDaoInsight', exact: true, component: ChuangDaoInsight, }, { path: '/report', exact: true, component: Report, }, { component: NotFound, }, ], }, ]; export default routes;
看一下效果。
在改动前是这样的:
图片
无论访问哪个页面,请求固定的JS文件,大小为2.3MB。
改动以后发版:
首屏刷新:
图片
切换一个路由:
图片
效果很明显了,文件资源也小了很多,白屏时间自然就下降了。
详细的文章在这里:
React中的懒加载以及在Ice中实践
结果:白屏时间整体降低,请求资源大小整体下降。
构建相关
优化本地热更新时间
项目本地热更新时间比较慢,大约在8~9秒,基于ice运行时中间件在每次代码变更时加入缓存同时移除对node_module目录下的babel转换,可以写一段这样的代码:
module.exports = ({ onGetWebpackConfig }) => { onGetWebpackConfig((config) => { config.module .rule('tsx') .test(/\.jsx?|\.tsx?$/) .exclude.add(/node_modules/) .end() .use('babel-loader') .tap((options) => { return { ...options, cacheDirectory: true, }; }); }); };
在build.json中注入该插件:
{ // ... "plugins": [ "@ali/build-plugin-faas", [ "build-plugin-ignore-style", { "libraryName": "antd" } ], "@ali/build-plugin-ice-def", "./src/index.ts" ] }
图片
结果:热更新时间降低到4秒左右,降低50%。
构建包大小优化
CDN资源替代项目依赖包
利用Webpack模块可视化工具,项目中的依赖是这样的:
图片
图片
从上图可以看到:在开发环境整个构建包体积达到了19.44MB,echarts、antv、moment这些包,体积都比较大,达到了MB量级,并且在项目中前两者使用频率很低,只有引用过一次,对于这种情况,考虑将依赖包转换为CDN引入的方式,原因如下:
- 减少打包产物大小;
- 减少白屏时间;
- 版本固定,使用频率低,通过CDN单独引入还会有浏览器强缓存的效益;
通过Webpack中externals,取消对于node_modules中枚举包的计算,并且在项目index.html中从CDN引入所列举到的包。
{ // ... "externals": { "echarts": "echarts", "moment": "moment" }, }
externals这里的key、value值分别对应npm中的包名和CDN引入后在window下的全局变量名,找包的CDN路径很简单,但是如何知道全局变量名是什么呢?
可以打开CDN链接,格式化代码,大概是这个样子的:
function(e, t) { "object" == typeof exports && "object" == typeof module ? //判断环境是否支持commonjs模块规范 module.exports = t(require("vue")) : "function" == typeof define && define.amd ? //判断环境是否支持AMD模块规范 define("ELEMENT", ["vue"], t) : "object" == typeof exports ? //判断环境是否支持CMD模块规范 exports.ELEMENT = t(require("vue")) : e.ELEMENT = t(e.Vue) } ("undefined" != typeof self ? self: this,function(e){ //省略... });
从这个JS文件可以看到,这个全局变量是ELEMENT咯~这块更详细的教程可以看一下这篇文章,这位博主总结的很全:
Webpack系列』—— externals用法详解
代码分割
这里利用Webpack现有的能力,对使用频繁的第三方库和模块进行统一抽离,这一部分可以写在上面提到的Ice中间件里去:
module.exports = ({ onGetWebpackConfig }) => { onGetWebpackConfig((config) => { config.optimization.splitChunks({ cacheGroups: { vendor: { priority: 1, test: /node_modules/, chunks: 'initial', minChunks: 1, minSize: 0, name: 'vendor', filename: 'vendor.js', }, common: { chunks: 'initial', name: 'common', minSize: 100, minChunks: 3, filename: 'common.js', }, }, }); }); };
抽离出来的模块如图:
图片
结果:优化后的构建包体积为9.1MB,降低了50%以上大小。
原文地址:https://mp.weixin.qq.com/s/n1demEjVgdwv2tfOl3s3Zw