vue3 + vite项目打包优化

337 阅读11分钟

vue3 + vite项目打包优化

优化方案:

  1. build 视图分析依赖文件
  2. 第三方库CDN引入
  3. 依赖文件分包
  4. gzip压缩文件
  5. 部署前配置history路由模式的404问题

一、build 视图分析依赖文件

​ 分析项目中的文件大小及引用情况,是优化前的重要一步,从而去采取文件分包,cdn引入等相关技术概念,那么在vite下我们可以利用什么工具来做项目的依赖分析呢?

​ 答案是: ​ Rollup Plugin Visualizer,这是一个依赖分析插件,它提供了多种模式的依赖分析,包括直观的视图分析,sunburst(循环层次图,像光谱)、treemap(矩形层次图,看起来比较直观,也是默认参数)、network(网格图,查看包含关系)、raw-data(原数据模式,json格式), list(列表模式),你可以选择任意一种你喜欢的观察模式,这里我们就以默认的为例;

安装方式如下:
npm install --save-dev rollup-plugin-visualizer
yarn add --dev rollup-plugin-visualizer
选择一种安装即可

安装完成后,即可在vite下的插件属性中进行配置:

import { visualizer } from 'rollup-plugin-visualizer';
export default defineConfig({
  plugins: [vue(), visualizer({
    emitFile: false,
    file: "stats.html", //分析图生成的文件名
    open:true //如果存在本地服务端口,将在打包后自动展示
  })],
})

配置的参数有很多是默认的,如果你没有特殊需求,完全可以不添加参数;下面我添加一个表格对已有参数进行诠释:

参数类型解释
filename/filestring生成分析的文件名
titlestringhtml标签页标题
openboolean以默认服务器代理打开文件
templatestring可选择的图表类型
templatestring可选择的图表类型
BrotliSizeboolearn搜集brotli压缩包的大小到图表
emitFileboolean使用emitFile生成文件,简单说,这个属性为true,打包后的分析文件会出现在打包好的文件包下,否则就会在项目目录下
sourcemapboolean使用sourcemap计算大小
projectRootstring, RegExp文件的根目录,默认在打包好的目录下

接下来,你只需要npm run build;就可以查看这个图表了

![01](E:\BaiduNetdiskWorkspace\4月小课\00-录制\04-vue3 + vite项目打包优化\代码笔记\01.png)

是不是很好看,五颜六色的,这里颜色也是有说法的: 🟦蓝色表示自己写下的js文件项; 🟩绿色是表示依赖的文件项; 其他颜色我们可以根据文件名来判断

![02](E:\BaiduNetdiskWorkspace\4月小课\00-录制\04-vue3 + vite项目打包优化\代码笔记\02.png)

像上面这个文件,明显我们可以看出这是router相关的文件,当鼠标点击时我们可以看出这块依赖文件的大小,他的位置是是哪里;这里也看到它的大小马上到了100kb,是因为我们的主要业务也确实在这里;那我们就可以通过这样的信息采取一些优化方案,包括不限于修改代码的设计方式等,那么下面要说的CDN引入就是为了减少如element-plus及bootstrap5的打包文件大小,减少本地文件载入压力。下图很直观的可以看出element-plus的占据程度

![03](E:\BaiduNetdiskWorkspace\4月小课\00-录制\04-vue3 + vite项目打包优化\代码笔记\03.png)

二、第三方库CDN引入

CDN 是构建在数据网络上的一种分布式的内容分发网。 
CDN 的作用是采用流媒体服务器集群技术,克服单机系统输出带宽及并发能力不足的缺点,可极大提升系统支持的并发流数目,减少或避免单点失效带来的不良影响。

上面是百度百科的一段话,这里我要cdn引入是因为我们只有一个服务器,便称为单系统;那么引入他们各自官方的cdn链接就是在利用分布式内容分发技术,但是毕竟是人家的cdn安全上还需要考虑,如果自己公司有条件,就可以用自己公司的保证安全性;

话接上文,我们通过视图分析发现了element-plus是最大的文件依赖,包括 bootstrap5,那我们就尝试在vite+vue下配置这俩个库的cdn引入来减少请求压力;

cdn管理插件我们使用vite-plugin-cdn-import

安装方式
npm install vite-plugin-cdn-import --save-dev
yarn add vite-plugin-cdn-import -D
选择自己的包管理器下载
// vite.config.js 基本用法
import reactRefresh from '@vitejs/plugin-react-refresh'
import importToCDN from 'vite-plugin-cdn-import'

export default {
    plugins: [
        importToCDN({
            modules: [
                {
                    name: 'react',
                    var: 'React',
                    path: `umd/react.production.min.js`,
                },
                {
                    name: 'react-dom',
                    var: 'ReactDOM',
                    path: `umd/react-dom.production.min.js`,
                },
            ],
        }),
    ],
}

有一些model该插件还提供了自动完成,不要太爽,我们不需要配置参数了

export default {
    plugins: [
        importToCDN({
            modules: [
                autoComplete('react'),
                autoComplete('react-dom')
            ],
        }),
        reactRefresh(),
    ],
}

写法如上,那么有那些是支持自动完成的呢,官方也写出了

自动完成支持的 module
“react” | “react-dom” | “react-router-dom” |
“antd” | “ahooks” | “@ant-design/charts” |
“vue” | “vue2” | “@vueuse/shared” |
“@vueuse/core” | “moment” |
“eventemitter3” | “file-saver” |
“browser-md5-file” | "xlsx | “crypto-js” |
“axios” | “lodash” | “localforage”

接下来我们再看完参数配置即可完成cdn的相关配置 这里的相关属性配置你们去官方看吧,很明确vite-plugin-cdn-import 然后还需要知道是常见cdn网站,我们主要介绍俩个国外的,也是常用的,

UNPKG:https://unpkg.com
jsDelivr :https://www.jsdelivr.com

这里还要学习怎么找到对应库cdn包的路径,我们好来配置参数,以UNPKG为例实践如下: 比如我们要配置element-plus的cdn引入,

先进入unpkg.com 在地址后面链接你的包名 得到链接配置参数即可

到这里你已经掌握了cdn库自动构建的基本知识,下面看一下我的配置片段:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { autoComplete, Plugin as importToCDN } from 'vite-plugin-cdn-import';

export default defineConfig({
  plugins: [vue(),
   importToCDN({
    prodUrl: 'https://unpkg.com/{name}@{version}/{path}',
    modules: [
      autoComplete('vue'),
      autoComplete('axios'),
      {
        name: 'element-plus',
        var: 'ElementPlus', //根据main.js中定义的来
        version: '2.2.17',
        path: 'dist/index.full.js',
        css: 'dist/index.css'
      },
      {
        name: 'vue-demi',
        var: 'VueDemi', //根据main.js中定义的来
        version: '0.13.11',
        path: 'lib/index.iife.js'
      },
      {
        name: '@element-plus/icons-vue',
        var: 'ElementPlusIconsVue', //根据main.js中定义的来
        version: '2.0.9',
        path: 'dist/index.iife.min.js'
      },
      {
        name: 'bootstrap',
        var: 'bootStrap', //根据main.js中定义的来
        version: '5.2.1',
        path: 'dist/js/bootstrap.js',
        css: 'dist/css/bootstrap.min.css'
      },
    ],
  })
],
)}
element-plus等第三方库将不会成为我们的本地依赖,这里的tool是我自己的js工具模块,他看起来也是很大,那我们就可以找方法去优化调整,至此你学会了vite框架下的vue项目cdn引入方式;

还有一点题外话,cdn引入之前:

你需要知道一但依赖网站出现问题,我们的项目也就不行了,所以有依赖如上网站的cdn建议留下备用方案,以便维护。 cdn是对整个库的引入,在你引入前,你要对一个库足够熟悉,比如我有一个好朋友他就在cdn引入中上出现了问题; 大致是这样:项目是vue3项目,我们知道在vue3中的reactive响应式对象函数,

//它可以这样导入:
import { reactive } from "@vue/reactivity";
//也可以这样:
import { onBeforeMount, ref, reactive } from "vue";

那么如果你用@vue/reactivity来导入,上线后发现reactive响应式没了,别问我怎么知道的,我朋友说的。我们cdn可没有引入该组件的相关依赖,只是在本地\node_modules下才有;

三、依赖文件分包

在我们没有配置构建工具的分包功能时,构建出来的build将无比巨大且是独立的一个js and css 文件,这样就会存在本地加载文件的压力,已经成熟的方案在rollup 和 webpack中都有概念;

在vite的官方介绍中有这么一段

build.rollupOptions¶
类型: RollupOptions
自定义底层的 Rollup 打包配置。这与从 Rollup 配置文件导出的选项相同,并将与 Vite 的内部 Rollup 选项合并。查看 Rollup 选项文档 获取更多细节。

vite底层已经集成了rollup的一部分功能,也就是说我们直接配置好即可;详细关于rollup的配置可以去看官方文档rollupjs;这里我直接给出我的配置情况,也是借鉴部分大佬的文章得出;

export default defineConfig({
  plugins: [vue(), viteCompression({
    verbose: true,
    disable: false,
    threshold: 10240,
    algorithm: 'gzip',
    ext: '.gz',
  }), 
   importToCDN({
    prodUrl: 'https://unpkg.com/{name}@{version}/{path}',
    modules: [
      autoComplete('vue'),
      autoComplete('axios'),
      {
        name: 'element-plus',
        var: 'ElementPlus', //根据main.js中定义的来
        version: '2.2.17',
        path: 'dist/index.full.js',
        css: 'dist/index.css'
      },
      {
        name: 'vue-demi',
        var: 'VueDemi', //根据main.js中定义的来
        version: '0.13.11',
        path: 'lib/index.iife.js'
      },
      {
        name: '@element-plus/icons-vue',
        var: 'ElementPlusIconsVue', //根据main.js中定义的来
        version: '2.0.9',
        path: 'dist/index.iife.min.js'
      },
      {
        name: 'bootstrap',
        var: 'bootStrap', //根据main.js中定义的来
        version: '5.2.1',
        path: 'dist/js/bootstrap.js',
        css: 'dist/css/bootstrap.min.css'
      },
    ],
  })
],
  build: {
    outDir: 'mh', //输出目录名
    minify: "terser", //压缩方式
    terserOptions: { 
      compress: {
        drop_console: true, //剔除console,和debugger
        drop_debugger: true,
      },
    },
    // chunkSizeWarningLimit: 1500,大文件报警阈值设置,不建议使用
    rollupOptions: {
      output: { //静态资源分类打包
        chunkFileNames: 'static/js/[name]-[hash].js',
        entryFileNames: 'static/js/[name]-[hash].js',
        assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
        manualChunks(id) { //静态资源分拆打包
          if (id.includes('node_modules')) {
            return id.toString().split('node_modules/')[1].split('/')[0].toString();
          }
        }
      }
    }
  }
})
配置好你的build.output参数,执行命令npm run build我们就可以看目录结构了

四、gzip压缩文件

GZIP最早由Jean-loup Gailly和Mark Adler创建,用于UNⅨ系统的文件压缩。我们在Linux中经常会用到后缀为.gz的文件,它们就是GZIP格式的。现今已经成为Internet 上使用非常普遍的一种数据压缩格式,或者说一种文件格式。

HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术。大流量的WEB站点常常使用GZIP压缩技术来让用户感受更快的速度。这一般是指WWW服务器中安装的一个功能,当有人来访问这个服务器中的网站时,服务器中的这个功能就将网页内容压缩后传输到来访的电脑浏览器中显示出来.一般对纯文本内容可压缩到原大小的40%.这样传输就快了,效果就是你点击网址后会很快的显示出来.当然这也会增加服务器的负载.
一般服务器中都安装有这个功能模块的。

了解完gizp的相关概念后,上面的引用也说明了,gzip不只是我们需要在打包的时候生成,也需要在web服务里开启功能,具体开启方式大家自行探索;

在vite下配置gzip

安装插件vite-plugin-compression;npm i vite-plugin-compression -D vite入口文件引入 `配置参数 build执行后查看 vite-plugin-compression:使用 gzip 或者 brotli 来压缩资源.

import viteCompression from 'vite-plugin-compression';
export default defineConfig({
  plugins: [vue(), viteCompression({
    verbose: true, //是否在控制台输出压缩结果
    disable: false, //是否禁用,相当于开关在这里
    threshold: 10240, //体积大于 threshold 才会被压缩,单位 b,1b=8B, 1B=1024KB  那我们这里相当于 9kb多吧,就会压缩
    algorithm: 'gzip', //压缩算法,可选 [ 'gzip' , 'brotliCompress' ,'deflate' , 'deflateRaw']
    ext: '.gz', //文件后缀
    )}
 ]
)}
上面我尽可能把用到的参数进行了注释,在官方文档中的参数还剩几个,感兴趣的自行研究,目前不涉及。

五、配置history路由模式的404问题

history模式: HTML5 模式,推荐使用这个模式;当使用这种历史模式时,URL 会看起来很 “正常”,例如 example.com/user/id。漂亮!

不过,问题来了。由于我们的应用是一个单页的客户端应用,如果没有适当的服务器配置,用户在浏览器中直接访问 example.com/user/id,就会得… 404 错误。这就丑了。

不用担心:要解决这个问题,你需要做的就是在你的服务器上添加一个简单的回退路由。如果 URL 不匹配任何静态资源,它应提供与你的应用程序中的 index.html 相同的页面。漂亮依旧!

上面是vue-router官方文档的一段话,如果你上线是用的history模式那么只要路由不匹配就会产生404;我们在nginx配置关键服务就好,下面是实战配置(大佬给配置的);

//nginx 配置文件里的 server成员配置,我大概解释一下,配置好启动服务即可
server
    {
        listen 80; //服务端口号
        server_name phpmyadmin;
        index index.html index.htm index.php;
        location /neimenmenhuan {
        proxy_pass http://localhost:8080;  //配置后端接口端口
      }
      location / {
        root  /www/server/phpmyadmin;   //根目录位置
        index index.html index.htm index.php;  //默认入口文件
        try_files $uri $uri /index.html;  //出错重定向 index.html 问题解决于此  
      }
    

      access_log  /www/wwwlogs/access.log;
    }