优化前
先感受下优化前编译好的Javascript文件及其大小:
❯ ll ../static/js/admin/
total 15M
-rw-r--r-- 1 dongwm staff 388K Aug 17 14:00 app.js
-rw-r--r-- 1 dongwm staff 77K Aug 17 14:00 chunk-01433734.js
-rw-r--r-- 1 dongwm staff 77K Aug 17 14:00 chunk-0b283872.js
-rw-r--r-- 1 dongwm staff 323K
Aug 17 14:00 chunk-20f6014c.js
-rw-r--r-- 1 dongwm staff 5.1K Aug 17 14:00 chunk-2d0ac00f.js
-rw-r--r-- 1 dongwm staff 5.1K Aug 17 14:00 chunk-2d0b1605.js
-rw-r--r-- 1 dongwm staff 13K Aug 17 14:00 chunk-2d0babdf.js
-rw-r--r-- 1 dongwm staff 3.1K Aug 17 14:00 chunk
-2d0cfa15.js
-rw-r--r-- 1 dongwm staff 4.5K Aug 17 12:30 chunk-2d230fe7.js
-rw-r--r-- 1 dongwm staff 2.8K Aug 17 14:00 chunk-2d2382a4.js
-rw-r--r-- 1 dongwm staff 8.0M Aug 17 14:00 chunk-378562d0.js
-rw-r--r-- 1 dongwm staff 28K Aug 17 14:00 chunk-4ee4a833.js
-rw-r--r--
1 dongwm staff 48K Aug 17 14:00 chunk-ecbac3dc.js
-rw-r--r-- 1 dongwm staff 5.3M Aug 17 14:00 chunk-vendors.js
可以看到竟然有8M和5.3M这么大的文件!在本地开发时由于本地网络打开文件很快感受不明显,但当把这些文件部署到服务器上,能明显感觉首屏打开时间是非常慢的。
好,看到了问题,我们来优化~
减小chunk-vendors.js体积
挨个来解决,首先看
chunk
-
vendors
.
js
。博客管理后台项目是基于Vue-CLI 3 搭建的,所以可以通过
yarn build
--
report
查看打包的内容中各库文件体积的占比(背后用了webpack-bundle-analyzer)。build成功后在dist目录下有个report.html文件,你可以在浏览器打开它:
这个项目的报告是这样的:里面会列出全部编译文件,占的区域越大说明文件越大,鼠标点到某个区域都可以看到对应区域代表文件的相关信息。
chunk
-
vendors
.
js
在右上角,大小仅次于
chunk
-
378562d0.js
。往区域里面看,可以看到
chunk
-
vendors
.
js
中主要是element-ui,其次是vue.runtime.esm.js,其余的文件都比较小。
想要减少chunk-vendors.js体积,思路有2个:
-
使用公共CDN。最彻底的方案,把ui库抽离出来。当然还可以「更彻底」,把vue、vuex、vue-router、axios等等依赖都剥离出去。
-
对element-ui中用的组件按需引入。虽然用了element-ui,但是只用了其中一部分常用组件,但是在编译时把全部ui库都引入了,所以优化思路是: 只包含需要的那部分。
要注意,企业开发和开源项目是否决定用公共CDN是有不同的考量的:
-
服务的重要性。凡是服务就可能会不稳定,如果你依赖外部的CDN提供服务,它挂了就直接影响你的企业服务,用户体验。除了问题你没有办法只能看着等着它解决。尤其是这种非营利性的CDN,很多开发者会比较担心它的服务质量。所以服务越重要你对里面用的东西的掌控度就要越高,在企业里面一般都要做到完全可控。
-
用户体验。对于我们这个项目来说,管理后台部分只有有限的几个人可以选择,不影响全部用户,且使用者是「自己人」时,访问速度并不是最重要的标准,再说精简后速度是可接受的。
在element-ui官网中对于2种方案都有说明,有兴趣的可以去了解。在这里我选择了「使用公共CDN」:
具体做法如下:
1. 把vue和element-ui从构建中剥离出来
直接在页面上引入 js 和 css 文件即可开始使用。看一下修改后的
public
/
index
.
html
lang="en">
charset="utf-8">
http-equiv="X-UA-Compatible" content="IE=edge">
name="viewport" content="width=device-width,initial-scale=1.0">
BASE_URL %>favicon.ico">
rel="stylesheet" href="https://unpkg.com/[email protected]/lib/theme-chalk/index.css">
blog
We're sorry but blog doesn't work properly without JavaScript enabled. Please enable it to continue.
id="app">
使用unpkg.com这个CDN服务中对应的vue和element-ui,但是应该制定要使用的版本
2. 修改vue.config.js配置
在configureWebpack键中使用
externals
:
module.exports = {
...
configureWebpack: {
devtool: 'eval-source-map',
output: {
filename: 'static/js/admin/[name].js',
chunkFilename: 'static/js/admin/[name].js'
},
externals: { // 新加这部分
'vue': 'Vue',
'element-ui': 'ELEMENT'
}
},
...
}
这样在编译时就不会把这2个库打包进来了
3. 去掉src/main.js部分逻辑
把原来的对应用法去掉(下面展示git diff的效果):
diff --git a/admin/src/main.js b/admin/src
/main.js
index cdc8eb9..165c77e 100644
--- a/admin/src/main.js
+++ b/admin/src/main.js
@@ -4,9 +4,6 @@ import Cookies from 'js-cookie'
import 'normalize.css/normalize.css' // A modern alternative to CSS resets
-import Element from 'element-ui'
-import 'element-ui/lib/theme-chalk/index.css'
-
import '@/styles/index.scss' // global css
import App from './App'
@@ -17,9
+14,7 @@ import './icons' // icon
import * as filters from './filters' // global filters
-Vue.use(Element, {
- size: Cookies.get('size') || 'medium', // set element-ui default size
-})
+Vue.prototype.$ELEMENT = { size: Cookies.get('size') || 'medium' };
验证效果
现在重新build就可以看到
chunk
-
vendors
.
js
文件的变化:
❯
ll dist/static/js/admin/ |grep chunk-vendors.js
-rw-r--r-- 1 dongwm staff 1.1M Aug 17 14:26 chunk-vendors.js
从5.3M -> 1.1M,降了约80%,而且在线上Nginx配置了Gzip压缩,文件会更小,优化完成~
另外也解释下没把vuex、vue-router、axios等库也拆出来。优化的起因是库体积大,而这些库都比较小,没有强烈优化的意愿。另外在我的项目经验中,拆了之后用CDN会让请求数会变多,非常容易让整体CDN服务变慢。大家可以试试,如果页面外链的资源太多反而速度更慢,还不如现在这些都压缩在一个文件中来的速度快呢。
这部分全部代码看延伸阅读链接2
减少chunk-378562d0.js体积
如果你细心可能会觉得编译后的文件名字很奇怪,有很多chunk-开头的文件:
❯ ll dist/static/js/admin/ |grep chunk
-rw-r--r-- 1 dongwm staff 323K Aug 17 14:26 chunk-20f6014c.js
-rw-r--r-- 1 dongwm staff 5.1K Aug 17
14:26 chunk-2d0ac00f.js
-rw-r--r-- 1 dongwm staff 5.1K Aug 17 14:26 chunk-2d0b1605.js
-rw-r--r-- 1 dongwm staff 13K Aug 17 14:26 chunk-2d0babdf.js
-rw-r--r-- 1 dongwm staff 3.1K Aug 17 14:26 chunk-2d0cfa15.js
-rw-r--r-- 1 dongwm staff 4.5K Aug 17 14:26 chunk-2d230fe7.js
-
rw-r--r-- 1 dongwm staff 2.8K Aug 17 14:26 chunk-2d2382a4.js
-rw-r--r-- 1 dongwm staff 28K Aug 17 14:26 chunk-4ee4a833.js
-rw-r--r-- 1 dongwm staff 77K Aug 17 14:26 chunk-685bad3f.js
-rw-r--r-- 1 dongwm staff 8.0M Aug 17 14:26 chunk-6fdb661a.js
-rw-r--r-- 1
dongwm staff 77K Aug 17 14:26 chunk-7425814b.js
-rw-r--r-- 1 dongwm staff 48K Aug 17 14:26 chunk-ecbac3dc.js
-rw-r--r-- 1 dongwm staff 1.1M Aug 17 14:26 chunk-vendors.js
为什么要这么搞呢?其实这是当时写代码时候就做过得一个优化「按需加载」,我们回忆一下router.js文件中的路由的写法,就拿登录页举例吧:
{
name: 'login',
path: '/login',
component: () => import('@/views/login'),
hidden
: true
},
代码分离(Code Splitting)是Webpack 中最引人注目的特性之一。此特性能够把代码分离到不同的bundle 中,然后可以按需加载或并行加载这些文件。
()
=>
import
(
'@/views/login'
)
就是一种按需加载的写法,我最喜欢这么用。其他的代码分离方案我这里就不介绍了,大家有兴趣可以去了解。
这样用户就不用一次加载整个大文件,而是把每个页面路由对应的模块分离成不同的chunk文件,按需加载。
PS: 当然对于我们这个管理后台的例子,除了CreatePost页复杂一些,其他的都算简单,所以不用代码分离文件总体也很小,另外代码分离是每个chunk文件还包含了一部分重复的代码,所以不拆也可以接受。
好,说回来。其实如果你用心想一下,就知道上面那个
chunk
-
6fdb661a
.
js
是指的那个页面。想想那个页面逻辑最复杂?对,就是CreatePost页面,因为里面有tui-editor,它用到了highlight.js、codemirror等等。
当然,看report.html文件也能看到,大家可以翻到前面看看那张截图。里面占用空间大的包含tui-editor-Editor.js、highlight.js、codemirror.js和jQuery等。
一开始我的思路也是
拆
,但是拆完之后发现,由于页面上unpkg网站请求太多,这些文件加载时间都很长,反而更慢了。后来又试了下「组件按需引入」,发现成本高收益很低,最终文件没怎么降下来。
其实一开始用tui-editor是一个无奈之举,我本来不喜欢它的理由之一正是现在它暴露出来的缺点: 依赖太多,文件太大。
怎么办呢?换。改用其他Markdown编辑器方案!然后搜索了一下,从官网找到了一个简单的例子(延伸阅读链接1),把它改造了一下,够用。
我把
src
/
components
/
MarkdownEditor
/
index
.
vue
改成了如下:
id="editor">
v-html="compiledMarkdown">
对于我们这个管理后台项目,除了CreatePost页复杂一些,其他的页面都算简单,前面我们看到一大堆chunk-前缀的js和css的文件,其中很多文件很小。大家想想,打开一个页面时要访问很多静态文件势必影响加载静态资源的时间。
之前已经说过了,这是为了做代码分离(Code Splitting)。但是当我们优化之后,「文件多且每个文件小」就成了一个问题。怎么做呢?就是「合」。也就是修改src/router.js中的路由,直接import。比如Home,原来这么写:
PS: 如果希望编译时取消Splitchunks,也就是合并chunk-vendors.XX到app.XX(JS或者CSS),可以在chainWebpack里加这么一段: