代码压缩
代码压缩值得是文件级别的压缩,类似于你用的winrar以及好压等压缩工具来压缩的结果。压缩的文件一般以.gz结尾。比如:app.ea467643.js.gz。
服务端压缩
以nginx为例,找到配置文件,添加如下配置即可
server {
gzip on;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/xml text/css;
...
}
开启前,文件大小1.7MB
开启后,文件大小646Kb
如何确定,后端返回的是压缩过的文件
如果服务器对资源进行压缩编码了,它就会通过响应头Content-Encoding告知当前请求用了什么编码格式,当然如果服务器没干这事,则不会返回这个响应头,比如某个请求用gzip压缩了返回的内容
客户端压缩
webpack打包时直接使用gzip压缩。
返回内容是在请求服务器的时候使用gzip进行动态压缩。这样存在的问题时,对于同一个资源的不同请求,反复压缩,这无疑会增加服务器的CPU和内存消耗。使用webpack去提前压缩好,然后让后端服务器拿去用现成压缩好的,则就可以避免这个问题。
安装压缩工具包
npm install compression-webpack-plugin --save-dev
在vue.config.js里配置如下(其实就是在配置webpack)
const CompressionPlugin = require('compression-webpack-plugin'); const compressionPlugin = new CompressionPlugin({ test: /.(js|css)?$/i, // 哪些文件要压缩 filename: '[path].gz[query]',// 压缩后的文件名 algorithm: 'gzip',// 使用gzip压缩 minRatio: 1,// 压缩率小于1才会压缩 deleteOriginalAssets: false // 删除未压缩的文件,谨慎设置,如果希望提供非gzip的资源,可不设置或者设置为false }) module.exports = { configureWebpack:{ // 配置压缩gz插件 plugins:[compressionPlugin] } };
然后配置nginx.conf
gzip_static设置为on之后,这样在访问资源的时候,如果存在“资源路径.gz”的文件,则会直接返回该文件,其优先级高于动态的gzip。
server { ... gzip on; gzip_types text/plain application/javascript application/x-javascript text/javascript text/xml text/css; gzip_static on; }
最后重启服务器,刷新页面就可以看到效果了。
类库不打包,引用外部模块
在 webpack 里有个 externals,可以忽略不需要打包的库。这样,就大大减少了chunk-vendors包的体积。
防止将某些 import
的包 ( package ) 打包到 bundle 中,而是在运行时 (runtime ) 再去从外部获取这些扩展依赖 ( external dependencies )。
即webpack外部扩展,依赖前置。利用cdn加速
这是没有使用外部模块前的体积,1.7MB
这是使用之后的,43kb
使用配置如下
在vue.config.js中
module.exports = { configureWebpack:{ externals: { // 使用外部资源 'vue': 'Vue', 'vue-router': 'VueRouter', 'vuex': 'Vuex', 'axios': 'axios', 'echarts': 'echarts', 'element-ui':'ELEMENT', 'lodash': '_', 'dayjs': 'dayjs' } } };
在public/index.html中,配置如下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <link rel="icon" href="<%= BASE_URL %>favicon.ico"> <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/vuex/3.2.0/vuex.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/vue-router/3.1.3/vue-router.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.19.2/axios.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/echarts/4.7.0/echarts.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.13.2/index.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.8.27/dayjs.min.js"></script> <title>xxx</title> </head> <body> <noscript> <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> </noscript> <div id="app"></div> <!-- built files will be auto injected --> </body> </html>
其他注意的
开发环境下是不需要如上这些配置的,所以如果追求极致,可以额外判断一下
index.html
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <link rel="icon" href="<%= BASE_URL %>favicon.ico"> <% if(NODE_ENV==='production'){ %> <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/vuex/3.2.0/vuex.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/vue-router/3.1.3/vue-router.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.19.2/axios.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/echarts/4.7.0/echarts.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.13.2/index.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.8.27/dayjs.min.js"></script> <% } %> <title>xxx</title> </head> <body> <noscript> <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> </noscript> <div id="app"></div> <!-- built files will be auto injected --> </body> </html>
vue.config.js
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
externals: process.env.NODE_ENV === 'production'?{ // 使用外部资源(开发环境下不用这个) 'vue': 'Vue', 'vue-router': 'VueRouter', 'vuex': 'Vuex', 'axios': 'axios', 'echarts': 'echarts', 'element-ui':'ELEMENT', 'lodash': '_', 'dayjs': 'dayjs' }:{}
打包分析工具
在如上的讲解中,都是通过network来分析查看,工具出库前后包大小,请求时长的对比。实际上,有个专业的工具包来做此事,那就是BundleAnalyzerPlugin。
是一个webpack的插件,使用也很简单。
const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer'); const bundleAnalyzerPlugin = new BundleAnalyzerPlugin({}); module.exports = { configureWebpack:{ plugins:[ bundleAnalyzerPlugin // 打包分析 ] } };
然后,每次npm run build成功之后,就会自动打开8888端口号的该分析结果页面
这个分析的更加清晰
vendors提取的是第三方公共库,公共资源,这些文件会打到dist/js/chunk-vendors.js里面 ,提取规则是每个页面都引入的才会打到chunk-vendors.js里面(如vue.js)
完整配置
提出上边完整的vue.config.js配置
// eslint-disable-next-line @typescript-eslint/no-var-requires const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer'); // eslint-disable-next-line @typescript-eslint/no-var-requires const CompressionPlugin = require('compression-webpack-plugin'); const bundleAnalyzerPlugin = new BundleAnalyzerPlugin({ }); const compressionPlugin = new CompressionPlugin({ test: /.(js|css)?$/i, // 哪些文件要压缩 filename: '[path].gz[query]',// 压缩后的文件名 algorithm: 'gzip',// 使用gzip压缩 minRatio: 1,// 压缩率小于1才会压缩 deleteOriginalAssets: false // 删除未压缩的文件,谨慎设置,如果希望提供非gzip的资源,可不设置或者设置为false }) module.exports = { publicPath: process.env.BASE_URL, devServer: { proxy: process.env.VUE_APP_SERVER, // 代理 open: true // 启动项目自动开启浏览器 }, configureWebpack:{ plugins:[ //插件 bundleAnalyzerPlugin, // 打包分析 compressionPlugin // gz压缩 ], externals: { // 使用外部资源 'vue': 'Vue', 'vue-router': 'VueRouter', 'vuex': 'Vuex', 'axios': 'axios', 'echarts': 'echarts', 'element-ui':'ELEMENT', 'lodash': '_', 'dayjs': 'dayjs' } } };
路由和组件懒加载
const routes = [ { path: '/', name: 'data-home', component: () => import(/* webpackChunkName: "data-home" */ '../views/data/index.vue'), children: [ { path: '/', name: 'today-data', component: () => import(/* webpackChunkName: "today-data" */ '../views/data/today-data/index.vue') }, { path: '/our-data', name: 'our-data', component: () => import(/* webpackChunkName: "our-data" */ '../views/data/our-data/index.vue') }, { path: '/customer-data', name: 'customer-data', component: () => import(/* webpackChunkName: "customer-data" */ '../views/data/customer-data/index.vue') } ] }, { path: '/login', name: 'login', component: () => import(/* webpackChunkName: "login" */ '../views/accounts/login.vue') } ];
这样的话,单个组件或文件依赖其他部分,并不会在打包的时打在一起,而非根据懒加载关键字来切割。
当需要的使用的时候,再去请求并加载。
这样就减少了单个模块或文件的体积,从而加快相应速度(尤其是首屏)。
需要注意的是在vue-cli3升级之后,配置了webpack的预加载,这时候除了路由懒加载需要的当前页面资源,其他资源也会被请求,但不会被解析。
白色文件就是预加载的文件,仍然会耗时下载,只是不会被解析。这些文件属于prefetch,也就是预读取,他的加载基本不会影响到当前页面的打开,而且在读取完成后,可以降低页面跳转的等待时间,是一个非常好的功能。
预加载技术(prefetch)是在用户需要前我们就将所需的资源加载完毕,不是所有浏览器都支持,主要是Chrome浏览器。
有人说:单如果由于预加载文件比较多,反而阻塞了实际需要的文件下载,首页渲染速度可能也会导致变慢。
但是我不这么认为,因为这是浏览器提供的功能,它会处理好这个关系。倒是会给开发人员造成疑惑“我明明懒加载”了,则么还是一起请求
解决办法
// vue.config.js module.exports = { chainWebpack: config => { // 移除 prefetch 插件 config.plugins.delete('prefetch') // 或者 // 修改它的选项: config.plugin('prefetch').tap(options => { options[0].fileBlacklist = options[0].fileBlacklist || [] options[0].fileBlacklist.push(/myasyncRoute(.)+?.js$/) return options }) } }
参考:
https://www.jb51.net/article/182323.htm
https://blog.csdn.net/crazywoniu/article/details/73480344
https://www.cnblogs.com/HYZhou2018/p/10419703.html
https://www.jianshu.com/p/078afc10fd3c
https://segmentfault.com/q/1010000018392785
https://blog.csdn.net/huangpb123/article/details/84170557
https://www.cnblogs.com/callmesummer/p/4345197.html