如何提高Vue前后端分离项目首页加载速度

    |     2020年4月14日   |   web前端技术, 优化   |     0 条评论   |    1253

前后端分离做成 SPA 后,首页文件常常超过 1MB,首屏就会慢。常见思路有:UI 组件按需加载、路由懒加载、处理组件重复打包、以及 gzip。前两者要看项目条件,UI 按需和 gzip 则几乎总能做。

本文先聊 ElementUI 按需引入和 gzip。按需能拆掉巨大的 element-ui.commons.js;gzip 无论把前端拷进 Spring Boot,还是用 Nginx 分开部署,都能立刻把传输体积压下去。

手段 做什么 效果
ElementUI 按需 babel-plugin-component + 按组件 import vendor 里那块 commons 消失,大约少 150KB
后端 gzip Spring Boot application.yml 打开压缩 响应带 Content-Encoding: gzip
Nginx gzip gzip on 并配 types / 阈值 大于 1K 的 js/css 等被压缩

一、ElementUI 按需加载

问题复现

不做优化时,一般在 main.js 整包引入:

import ElementUI from 'element-ui';

import 'element-ui/lib/theme-chalk/index.css';

Vue.use(ElementUI,{size:'small'});

CSS 必须引入。但这种写法会把接近 60 个组件全部打进项目,用不到的就浪费。用下面命令生成 report.html 分析包内容:

vue-cli-service build --report

关键日志类似:

warning



entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.

Entrypoints:

  app (1.17 MiB)

      css/chunk-vendors.9948ce82.css

      js/chunk-vendors.11959501.js

      css/app.4e8a7623.css

      js/app.ce6f575c.js



  File                                    Size              Gzipped



  dist/js/chunk-vendors.11959501.js       840.77 KiB        227.94 KiB

  dist/js/app.ce6f575c.js                 99.08 KiB         30.95 KiB

  dist/js/chunk-64435448.d0a0516e.js      26.52 KiB         5.87 KiB

  dist/js/chunk-0c17a57a.d553638c.js      23.79 KiB         5.49 KiB

  dist/js/chunk-a3fdbb9c.ddc4c008.js      13.30 KiB         3.45 KiB

  dist/js/chunk-54277bc7.2882c4cd.js      10.40 KiB         2.95 KiB

  dist/js/chunk-4e552d82.c64f4d10.js      1.78 KiB          0.63 KiB

  dist/js/chunk-18458ebc.32fb57c9.js      1.54 KiB          0.62 KiB

  dist/js/chunk-2d0d03c8.3a093d55.js      0.52 KiB          0.36 KiB

  dist/js/chunk-2d237c54.0b312051.js      0.43 KiB          0.33 KiB

  dist/css/chunk-vendors.9948ce82.css     258.19 KiB        41.36 KiB

  dist/css/app.4e8a7623.css               3.46 KiB          1.09 KiB

  dist/css/chunk-0c17a57a.9fe19f94.css    0.86 KiB          0.35 KiB

  dist/css/chunk-64435448.3755e146.css    0.30 KiB          0.15 KiB

入口已经超出官方建议的 244KB。把打包结果拷到 Spring Boot 的 resources/static,浏览器里最大的 chunk-vendors.*.js 加载用了 369ms:

dist 里的 report.html 能看出是谁把 JS 撑大的:chunk-vendors 大,主要是因为里面的 element-ui.commons.js 大。每个模块都能优化,但先打这个出头鸟。

按需引入

官网的办法:先装 babel-plugin-component:

npm install babel-plugin-component -D

改 babel.config.js:

module.exports = {

    presets: [

        '@vue/app',

        ['@babel/preset-env', {

            modules: false

        }]

    ],

    plugins: [

        [

            "component",

            {

                "libraryName": "element-ui",

                "styleLibraryName": "theme-chalk"

            }

        ]

    ]

}

再改 main.js,用到的组件一个一个引入:

import {

    Button,

    Input,

    Table,

    TableColumn,

    Dialog,

    Card,

    Container,

    Icon,

    Select,

    Form,

    Tag,

    Tree,

    Pagination,

    Badge,

    Loading,

    Message,

    MessageBox,

    Menu,

    Tabs,

    TabPane,

    Breadcrumb,

    BreadcrumbItem,

    Dropdown,

    Steps,

    Tooltip,

    Popover,

    Collapse,

    FormItem,

    Checkbox,

    Header,

    DropdownMenu,

    DropdownItem,

    Aside,

    Main,

    MenuItem,

    Submenu,

    Option,

    Col,

    Row,

    Upload,

    Radio,

    DatePicker,

    RadioGroup,

    CollapseItem,

    Switch

} from 'element-ui';

import 'element-ui/lib/theme-chalk/index.css';

Vue.prototype.$ELEMENT = {size: 'small', zIndex: 3000};

Vue.use(Switch);

Vue.use(CollapseItem);

Vue.use(Radio);

Vue.use(RadioGroup);

Vue.use(DatePicker);

Vue.use(Upload);

Vue.use(Row);

Vue.use(Col);

Vue.use(Option);

Vue.use(Submenu);

Vue.use(MenuItem);

Vue.use(Header);

Vue.use(DropdownMenu);

Vue.use(DropdownItem);

Vue.use(Aside);

Vue.use(Main);

Vue.use(Checkbox);

Vue.use(FormItem);

Vue.use(Collapse);

Vue.use(Popover);

Vue.use(Menu);

Vue.use(Tabs);

Vue.use(TabPane);

Vue.use(Breadcrumb);

Vue.use(BreadcrumbItem);

Vue.use(Dropdown);

Vue.use(Steps);

Vue.use(Tooltip);

Vue.use(Tree);

Vue.use(Pagination);

Vue.use(Badge);

Vue.use(Loading);

Vue.use(Button);

Vue.use(Input);

Vue.use(Table);

Vue.use(TableColumn);

Vue.use(Dialog);

Vue.use(Card);

Vue.use(Container);

Vue.use(Icon);

Vue.use(Select);

Vue.use(Form);

Vue.use(Tag);

Vue.prototype.$alert = MessageBox.alert

Vue.prototype.$confirm = MessageBox.confirm

两处要注意:MessageBox 的引入方式和其他组件不同;给组件统一定制 size 和 zIndex 的方式也变了。然后再 build –report:

entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.

Entrypoints:

  app (1.03 MiB)

      css/chunk-vendors.26d2c5b9.css

      js/chunk-vendors.e2a11728.js

      css/app.4e8a7623.css

      js/app.c5dd78e5.js



  File                                    Size              Gzipped



  dist/js/chunk-vendors.e2a11728.js       683.05 KiB        177.91 KiB

  dist/js/app.c5dd78e5.js                 101.70 KiB        31.90 KiB

  dist/js/chunk-64435448.d0a0516e.js      26.52 KiB         5.87 KiB

  dist/js/chunk-0c17a57a.d553638c.js      23.79 KiB         5.49 KiB

  dist/js/chunk-33b8cd94.7bbae1a0.js      13.30 KiB         3.46 KiB

  dist/js/chunk-df7e035a.414b548f.js      10.40 KiB         2.95 KiB

  dist/js/chunk-4e552d82.c64f4d10.js      1.78 KiB          0.63 KiB

  dist/js/chunk-18458ebc.32fb57c9.js      1.54 KiB          0.62 KiB

  dist/js/chunk-2d0d03c8.3a093d55.js      0.52 KiB          0.36 KiB

  dist/js/chunk-2d237c54.0b312051.js      0.43 KiB          0.33 KiB

  dist/css/chunk-vendors.26d2c5b9.css     262.71 KiB        42.11 KiB

  dist/css/app.4e8a7623.css               3.46 KiB          1.09 KiB

  dist/css/chunk-0c17a57a.9fe19f94.css    0.86 KiB          0.35 KiB

  dist/css/chunk-64435448.3755e146.css    0.30 KiB          0.15 KiB

和前面比,按需引入有效果,但不算惊人。再打开 report.html:庞大的 element-ui.commons.js 没了,换成一堆小模块,相关文件大约少了 150KB。感觉还不够,继续上 gzip。

二、gzip:两种部署

  • 前端打包后拷到后端,只部署后端项目
  • 前后端分开,前端用 Nginx(推荐)

Spring Boot 打开压缩

第一种方式前端不用额外处理。后端 application.yml:

server:

  compression:

    enabled: true

重启后首页请求基本都被压缩:

点开一条请求可以看到 gzip 已生效,效果立竿见影:

Nginx 部署

打开配置:vim /usr/local/nginx/conf/nginx.conf,找到如下一段修改:

gzip on;

gzip_min_length 1k;

gzip_buffers 4 16k;

#gzip_http_version 1.0;

gzip_comp_level 2;

gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;

gzip_vary off;

gzip_disable "MSIE [1-6]\.";

含义简要如下:

  • 第1行:开启 Gzip
  • 第2行:不压缩临界值,大于 1K 才压
  • 第3行:buffer,一般不用改
  • 第4行:反向代理末端若是 HTTP/1.0 再考虑;默认 HTTP/1.1,有这句就注释掉
  • 第5行:压缩级别 1–10,越大越慢越好
  • 第6行:压缩的文件类型;JavaScript 有两种写法最好都写上,否则有人会抱怨 js 没压到
  • 第7行:和 Squid 等缓存有关,on 会加 “Vary: Accept-Encoding”
  • 第8行:IE6 对 Gzip 不友好,排除它

保存后 nginx -s reload。用 curl 测是否开启:

curl -I -H "Accept-Encoding: gzip, deflate" "http://www.slyar.com/blog/"



HTTP/1.1 200 OK

Server: nginx/1.0.15

Date: Sun, 26 Aug 2012 18:13:09 GMT

Content-Type: text/html; charset=UTF-8

Connection: keep-alive

X-Powered-By: PHP/5.2.17p1

X-Pingback: http://www.slyar.com/blog/xmlrpc.php

Content-Encoding: gzip

页面成功压缩。再测 css:

curl -I -H "Accept-Encoding: gzip, deflate" "http://www.slyar.com/blog/wp-content/plugins/photonic/include/css/photonic.css"



HTTP/1.1 200 OK

Server: nginx/1.0.15

Date: Sun, 26 Aug 2012 18:21:25 GMT

Content-Type: text/css

Last-Modified: Sun, 26 Aug 2012 15:17:07 GMT

Connection: keep-alive

Expires: Mon, 27 Aug 2012 06:21:25 GMT

Cache-Control: max-age=43200

Content-Encoding: gzip

css 成功压缩。再测 js:

curl -I -H "Accept-Encoding: gzip, deflate" "http://www.slyar.com/blog/wp-includes/js/jquery/jquery.js"



HTTP/1.1 200 OK

Server: nginx/1.0.15

Date: Sun, 26 Aug 2012 18:21:38 GMT

Content-Type: application/x-javascript

Last-Modified: Thu, 12 Jul 2012 17:42:45 GMT

Connection: keep-alive

Expires: Mon, 27 Aug 2012 06:21:38 GMT

Cache-Control: max-age=43200

Content-Encoding: gzip

js 成功压缩。图片也可以压:

curl -I -H "Accept-Encoding: gzip, deflate" "http://www.slyar.com/blog/wp-content/uploads/2012/08/2012-08-23_203542.png"



HTTP/1.1 200 OK

Server: nginx/1.0.15

Date: Sun, 26 Aug 2012 18:22:45 GMT

Content-Type: image/png

Last-Modified: Thu, 23 Aug 2012 13:50:53 GMT

Connection: keep-alive

Expires: Tue, 25 Sep 2012 18:22:45 GMT

Cache-Control: max-age=2592000

Content-Encoding: gzip

最后来个不到 1K 的文件,阈值是 1K,所以没压缩:

curl -I -H "Accept-Encoding: gzip, deflate" "http://www.slyar.com/blog/wp-content/plugins/wp-multicollinks/wp-multicollinks.css"



HTTP/1.1 200 OK

Server: nginx/1.0.15

Date: Sun, 26 Aug 2012 18:23:27 GMT

Content-Type: text/css

Content-Length: 180

Last-Modified: Sat, 02 May 2009 08:46:15 GMT

Connection: keep-alive

Expires: Mon, 27 Aug 2012 06:23:27 GMT

Cache-Control: max-age=43200

Accept-Ranges: bytes

一句话总结:SPA 首页先把 UI 库改成按需引入,再在 Spring Boot 或 Nginx 上打开 gzip,体积和耗时都会立刻下来。

转载请注明来源:如何提高Vue前后端分离项目首页加载速度
本文链接地址:https://ai.zhousir.top/?p=2631
回复 取消