看了一下我司官网的webpack打包出来的大小状况,发现有不少能够优化的点,好比 lodash、moment.js、antd等等;
本文主要围绕webpack的打包优化,并根据业务状况适当的作减法。html
优化前必定要有一个界面能记录目前的打包状况,推荐用webpack-bundle-analyzer这个包, 它能够看到打包后每一个模块的大小,还能给出gizp压缩后的大小,在生产环境中加载的模块都是通过gzip压缩过的,能够做为真实访问的大小依据。
安装也很简单:前端
// cli npm install --save-dev webpack-bundle-analyzer
注意生产环境(production)是表明线上真实的环境,因此analyzer要对生产环境的包进行分析的,因此我配置了一下本地打包生产环境的构建配置,在package.json加入下面的配置:react
"scripts": { ... "local_production": "cross-env NODE_ENV=local_production npm run build" }
而后在webpack配置里面判断process.env.NODE_ENV === 'local_production'
,构建production环境的构建而且加入analyzer分析生产环境打包出来的状况。webpack
// webpack.config.js const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; if(process.env.NODE_ENV === 'local_production') { webpack_config.plugins.push( new BundleAnalyzerPlugin( { analyzerMode: 'server', analyzerHost: '127.0.0.1', analyzerPort: 8889, reportFilename: 'report.html', defaultSizes: 'parsed', openAnalyzer: true, generateStatsFile: false, statsFilename: 'stats.json', statsOptions: null, logLevel: 'info' } ) ); }
这里是个人项目用analyzer生成出来的包大小状况(打包前)
git
主要看index.xxxx.js,它包含了全部的公共依赖,咱们要作的就是减小没必要要的公共资源的体积,能够减小大量没必要要的代码。github
从上面的能够看出来antd.less占了很大部分面积,由于我要在项目中自定义theme,可是官方的那套配置的形式来自定义theme只能修改变量,不能改组件,因此我先加载全部的antd.less再在后面接着加载一个theme.less用于修改主题变量和修改antd组件样式。web
移除了antd以后index包小了三百多k,这还远远不够,接着看下面的优化点npm
lodash也是须要优化按需加载的方式的,推荐这篇教程Webpack按需打包Lodash的几种方式, 按照教程改进后,lodash 小了500多k。json
其实moment引进来的时候会带有不少语言包的,咱们只用到了其中一个中文的包,因此其余语言包均可以去掉,网络
plugins: [ new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /zh-cn/), ]
后来又发现项目中只用到了moment().format()这个方法,因为moment.js只有一个大的moment.js模块,没有按模块分开写,没法按需打包,那么其实咱们能够本身实现个简易版的moment来替代moment.js,下面是我找到的实现简易版moment代码:
// 简易版moment代替moment.js class Moment { private date:Date; constructor(arg = new Date().getTime()) { this.date = new Date(arg); } padStart(num) { num = String(num); if (num.length < 2) { return '0' + num; } else { return num; } } unix() { return Math.round(this.date.getTime() / 1000); } static unix(timestamp) { return new Moment(timestamp * 1000); } format(formatStr) { const date = this.date; const year = date.getFullYear(); const month = date.getMonth() + 1; const day = date.getDate(); const week = date.getDay(); const hour = date.getHours(); const minute = date.getMinutes(); const second = date.getSeconds(); const weeks = ['一', '二', '三', '四', '五', '六', '日']; return formatStr.replace(/Y{2,4}|M{1,2}|D{1,2}|d{1,4}|h{1,2}|m{1,2}|s{1,2}/g, (match) => { switch (match) { case 'YY': return String(year).slice(-2); case 'YYY': case 'YYYY': return String(year); case 'M': return String(month); case 'MM': return this.padStart(month); case 'D': return String(day); case 'DD': return this.padStart(day); case 'd': return String(week); case 'dd': return weeks[week]; case 'ddd': return '周' + weeks[week]; case 'dddd': return '星期' + weeks[week]; case 'h': return String(hour); case 'hh': return this.padStart(hour); case 'm': return String(minute); case 'mm': return this.padStart(minute); case 's': return String(second); case 'ss': return this.padStart(second); default: return match; } }); } } export const moment = (arg) => { return new Moment(arg); };
这样就直接能够把moment.js 干掉了,包体积又小了很多。
下面是优化后的analyzer生成出来的包大小状况
包体从2.7M优化到了1.7M,gzip从297k减少到212k,访问虽然只是快了一点点,但在低网速环境下访问仍是看获得区别的。
接下来说一个跟包大小无关又很重要的优化点,就是单页应用的第一个入口html,正常状况下入口html只是用来加载js包,等js加载完以后才渲染出相关界面出来,这个入口html自己没有内容展现,但它是整个网站的第一个请求,取到这个入口html以后才开始加载js,等到加载完js才开始渲染界面,这段时间是占网站总体加载时间最多的,以下图:
第一个请求只要128ms,直到加载完公共js渲染出界面须要1s左右,这时候若是入口index没内容的话那就是纯粹的白屏时间了,因此咱们应该好好利用这个入口index.html,能够作一个骨架屏或者loading动画,能让用户在等白屏时间里可以有个界面能看到,停留时间会更长一些,也能让用户觉得这个网站一下就刷出来看到东西的感受。
对于这个入口index的利用,我是加入了顶部导航栏进去的,让用户能够第一眼看到导航栏知道有什么导航项,并且也是能够点进去的,而内容区对于不一样的路径访问会有不一样的界面,因此我就简单的弄个loading便可。
至此,这一版优化减小了加载的时间,同时合理利用了入口index做为loading页,提升用户体验。
前端优化工做是一个长期且复杂的工做,有不少能够考虑的地方,能够根据网络环境、框架、用户群体、业务状况、代码结构等多个方面合理地安排选择优化方案,本文只是我对于现有公司官网的优化的一部分,在这里分享给你们,若是以为有用就点个赞吧👍