vite3+vue3 项目打包优化实战之-视图分析(rollup-plugin-visualizer)CDN引入依赖分包gzip压缩history404问题

Posted Min.Mr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vite3+vue3 项目打包优化实战之-视图分析(rollup-plugin-visualizer)CDN引入依赖分包gzip压缩history404问题相关的知识,希望对你有一定的参考价值。

文章目录

写在前面

vue项目在线下环境开发完成后,我们就需要项目的打包上线了,除了要知道打包命令npm run build 之外,我们还要知道项目整体文件依赖情况,web访问加载速度等概念,包括首屏优化方案。我通过一次实战把最基本可以优化的步骤走一下。
将分为以下几个步骤:

  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可选择的图表类型
gzipSizeboolean搜集gzip压缩包的大小到图表
BrotliSizeboolearn搜集brotli压缩包的大小到图表
emitFileboolean使用emitFile生成文件,简单说,这个属性为true,打包后的分析文件会出现在打包好的文件包下,否则就会在项目目录下
sourcemapboolean使用sourcemap计算大小
projectRootstring, RegExp文件的根目录,默认在打包好的目录下

看完这些参数,也有了大概的了解,根据需求配置就好
接下来,你只需要npm run build;就可以查看这个图表了

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

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


第三方库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引入,

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

下面我附图来展示:
package.json找到你的包信息

浏览器拼接你的包并且回车:

你会发现页面请求到了内容(这就说明该库在cdn上已经存在,我们把整个的链接拿下来配置好参数就可以了):

到这里你已经掌握了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'
      ,
    ],
  )
],
)

上面的配置中有一个问题需要提及,我配置了vue-demi,它是pinia仓库的依赖,简单说,如果不配置它我们的cdn构建中间出现了个缺口,它是pinia-vue中间的一个依赖;vue和axios我配置了自动完成,那接下来看下我们进入实战。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="./static/ico/favicon-a91524b8.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>xxxxx</title>
    <script type="module" crossorigin src="./static/js/index-3f77d0fe.js"></script>
    <link rel="modulepreload" crossorigin href="./static/js/@vue-57a1150c.js">
    <link rel="modulepreload" crossorigin href="./static/js/js-cookie-1db5286e.js">
    <link rel="modulepreload" crossorigin href="./static/js/axios-08851a62.js">
    <link rel="modulepreload" crossorigin href="./static/js/lodash-es-9a8f223b.js">
    <link rel="modulepreload" crossorigin href="./static/js/@vueuse-d210d573.js">
    <link rel="modulepreload" crossorigin href="./static/js/@element-plus-1fa478d9.js">
    <link rel="modulepreload" crossorigin href="./static/js/@popperjs-892fd7f5.js">
    <link rel="modulepreload" crossorigin href="./static/js/@ctrl-eb0b847c.js">
    <link rel="modulepreload" crossorigin href="./static/js/dayjs-54e8cf14.js">
    <link rel="modulepreload" crossorigin href="./static/js/async-validator-efc2d198.js">
    <link rel="modulepreload" crossorigin href="./static/js/memoize-one-99e54574.js">
    <link rel="modulepreload" crossorigin href="./static/js/escape-html-4bbaf1e1.js">
    <link rel="modulepreload" crossorigin href="./static/js/normalize-wheel-es-da779ce4.js">
    <link rel="modulepreload" crossorigin href="./static/js/@floating-ui-4b8fd220.js">
    <link rel="modulepreload" crossorigin href="./static/js/element-plus-88e408ab.js">
    <link rel="modulepreload" crossorigin href="./static/js/vue-router-5a9da933.js">
    <link rel="modulepreload" crossorigin href="./static/js/vue-demi-5b9a0fa5.js">
    <link rel="modulepreload" crossorigin href="./static/js/pinia-ef1d9feb.js">
    <link rel="modulepreload" crossorigin href="./static/js/@fortawesome-7be7f9bf.js">
    <link rel="stylesheet" href="./static/css/element-plus-c08499e6.css">
    <link rel="stylesheet" href="./static/css/index-f2f66543.css">
    <link rel="stylesheet" href="./static/css/bootstrap-744009a1.css">
  </head>
  <body>
    <div id="app"></div>
    
  </body>
</html>

这样的入口文件,这么多的link是我提前用了分包的效果,下面我们会实战分包;回到上面,这么多的link引入对我们本地的压力可想而知;再来看分析图:

element-plus的依赖是如此庞大,那我们配置完后,build再来感受下;

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <link rel="icon" type="image/svg+xml" href="./static/ico/favicon-a91524b8.ico" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>xxxxxxxxx</title>
  <link href="https://unpkg.com/element-plus@2.2.17/dist/index.css" rel="stylesheet">
  <link href="https://unpkg.com/bootstrap@5.2.1/dist/css/bootstrap.min.css" rel="stylesheet">
  <script src="https://unpkg.com/vue@3.2.36/dist/vue.global.prod.js"></script>
  <script src="https://unpkg.com/axios@0.27.2/dist/axios.min.js"></script>
  <script src="https://unpkg.com/element-plus@2.2.17/dist/index.full.js"></script>
  <script src="https://unpkg.com/vue-demi@0.13.11/lib/index.iife.js"></script>
  <script src="https://unpkg.com/@element-plus/icons-vue@2.0.9/dist/index.iife.min.js"></script>
  <script src="https://unpkg.com/bootstrap@5.2.1/dist/js/bootstrap.js"></script>
  <script type="module" crossorigin src="./static/js/index-8dbc54cb.js"></script>
  <link rel="modulepreload" crossorigin href="./static/js/js-cookie-1db5286e.js">
  <link rel="modulepreload" crossorigin href="./static/js/vue-router-5755d64e.js">
  <link rel="modulepreload" crossorigin href="./static/js/pinia-7992cf6b.js">
  <link rel="modulepreload" crossorigin href="./static/js/@fortawesome-0742f1fb.js">
  <link rel="stylesheet" href="./static/css/index-f2f66543.css">
  <link rel="stylesheet" href="./static/css/element-plus-c08499e6.css">
  <link rel="stylesheet" href="./static/css/bootstrap-744009a1.css">
</head>

<body>
  <div id="app"></div>

</body>

</html>

cdn标签引入正确,我们也可以本地构建serve 来验证效果,这里就不扩展了,那么再看下分析图

element-plus等第三方库将不会成为我们的本地依赖,这里的tool是我自己的js工具模块,他看起来也是很大,那我们就可以找方法去优化调整,至此你学会了vite框架下的vue项目cdn引入方式;

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

  1. 你需要知道一但依赖网站出现问题,我们的项目也就不行了,所以有依赖如上网站的cdn建议留下备用方案,以便维护。
  2. 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'
      ,
      

vue项目打包上线

一.项目打包

  1. 首先在打包之前做两个优化操作

  • 优化一:在vite.congfig(vite.config.ts文件)去掉项目中console.log和debugger

        解决方式:在vite.config.ts文件中添加esbuild:drop:["console","debugger"] 

export default defineConfig(
  esbuild: 
    drop:['console','debugger']//打包时去掉console语句
  ,
  plugins: [vue(), vueJsx()],
  resolve: 
    alias: 
      '@': fileURLToPath(new URL('./src', import.meta.url)),
      '#': fileURLToPath(new URL('./types', import.meta.url))
    
  ,
  server: 
    proxy: 
      "/m.api": 
        target: 'http://192.168.1.188:8080',
        changeOrigin: true
      ,
      "/upload/admin": //图片上传地址
        target: 'http://192.168.1.188:8080', // 后端服务实际地址
        changeOrigin: true,
        ws: true
      
    
  
)
  • 优化二:在package.json(package.json文件)去掉ts类型检查

          解决方式:"build": "run-p type-check build-only"改为"build": "run-p build-only"

 2.打包

npm run build

3.预览打包后的项目

npm run preview 

4.预览时遇到的一些问题

  • 问题1:echarts首次渲染没问题,第二次渲染却成空白

  • 产生原因:echarts插件自带的bug
  • 解决方式:
onBeforeUnmount(() => //防止echarts带来的空白bug
    if (column) 
        column.dispose()
        column = undefined
    
    if (line) 
        line.dispose()
        line = undefined
    
    if (pie) 
        pie.dispose()
        pie = undefined
    
    if (pies) 
        pies.dispose()
        pies = undefined
    
)
  •  问题2:图标出现错误,控制台输出404

  • 产生原因:未找到图标文件,路径错误

  • 解决方法:在入口index.html文件中路径中的"."去掉

<link rel="icon" href="./favicon.ico">
改为
<link rel="icon" href="/favicon.ico">
 
<link rel="stylesheet" href="./public/iconfont/iconfont.css">
改为
<link rel="stylesheet" href="/public/iconfont/iconfont.css">

 二、项目上线

使用宝塔第三方工具来上线,首先进入公司宝塔的网址,然后输入账户和密码进入宝塔主页,然后创建一个网站,创建网站之后把打包好的dist文件上传到网站目录中

 1.首先进入宝塔首页宝塔Linux面板宝塔Linux面板

 

 2.进入创建好的网站

 3.点击选择添加站点

 

 4.填写公司给的域名,然后点击提交

 5.跳转到创建好之后的页面,单击刚刚创建好的域名

6.站点创建好之后可以访问创建好的站点

 

 7.表示此站点创建成功

 8.然后把打包好的dist文件夹,上传

 

 9.单击上传

 10.正在上传

 11.打开dist文件

 12.复制dist文件夹中所有的文件

 

 

13.然后我们在返回dist文件夹,单击粘贴,选择确定

14.上线的整体文件夹

 15.注意:

  • 问题:上线之后页面会报一个404错误

 

  •  解决1:将路由模式改为hash模式,在router文件夹下的index.ts

history: createWebHistory(import.meta.env.BASE_URL)

改为

history: createWebHashHistory(import.meta.env.BASE_URL)

  •  解决2:不改变路由模式,修改服务器配置文件

                回到宝塔,找到配置文件,点击设置设置反代理 

 

 

        这里以nginx类型的服务器为例, 在宝塔中站点设置中配置文件里"禁止访问的文件或目录"的位置添加一下代码,据vue-router官方文档去添加nginx配置(添加一个简单的回退路由)

 16.打包上线成功之后页面

 

以上是关于vite3+vue3 项目打包优化实战之-视图分析(rollup-plugin-visualizer)CDN引入依赖分包gzip压缩history404问题的主要内容,如果未能解决你的问题,请参考以下文章

ts+vite3+vue3+mock+qs实现本地模拟数据功能

Vue3+Vite3+Ts4配置移动端适配

Vue3+Vite3+Ts4配置移动端适配

Vue3+Vite3+Ts4配置移动端适配

小记vue项目打包优化

node+koa启动vue3.0打包项目