当前位置:   article > 正文

Vite打包性能优化及填坑_vite4优化

vite4优化

最近在使用 Vite4.0 构建一个中型前端项目的过程中,遇到了一些坑,也做了一些项目在构建生产环境时的优化,在这里做一个记录,以便后期查阅。(完整配置在后面)

上面是dist文件夹的截图,里面的内容已经有30mb了,是时候该做点什么了。

分析

想要实现优化,首先我得先知道,是什么占了这么大的空间。是图片?是库?还是其他静态资源?

  1. 将文件分门别类,js,css这些资源目录分别打包到对应的文件夹下

    1. js
    2. 复制代码build: {
    3.     rollupOptions: {
    4.       output: {
    5.         chunkFileNames: 'js/[name]-[hash].js'// 引入文件名的名称
    6.         entryFileNames: 'js/[name]-[hash].js'// 包的入口文件名称
    7.         assetFileNames: '[ext]/[name]-[hash].[ext]'// 资源文件像 字体,图片等
    8.       }
    9.     }
    10. }
  2. 查看项目的依赖,找出大块头

rollup-plugin-visualizer是一个打包体积分析插件,对应webpack中的webpack-bundle-analyzer。配置好后运行构建命令会生成一个stats.html

  1. bash
  2. 复制代码npm i rollup-plugin-visualizer -D
  3. js
  4. 复制代码import { visualizer } from 'rollup-plugin-visualizer'
  5. js
  6. 复制代码plugins: [
  7.     visualizer({opentrue})
  8. ]
  9. arduino
  10. 复制代码npm run build // 打包结束后会出现下图

 

从体积能看到,这里已经达到了7MB大小了,是时候该做点什么了。

优化

拆分包

这里有一个自己的个人见解:如果不同模块使用的插件基本相同那就尽可能打包在同一个文件中,减少http请求,如果不同模块使用不同插件明显,那就分成不同模块打包。这是一个矛盾体。这里使用的是最小化拆分包。如果是前者可以直接选择返回'vendor'。

  1. scss
  2. 复制代码rollupOptions: {
  3. output: {
  4. manualChunks(id) {
  5. if (id.includes("node_modules")) {
  6. // 让每个插件都打包成独立的文件
  7. return id .toString() .split("node_modules/")[1] .split("/")[0] .toString();
  8. }
  9. }
  10. }
  11. }

去除debugger

  1. bash
  2. 复制代码npm i terser -D
  3. js
  4. 复制代码terserOptions: {
  5.   compress: {
  6.     drop_console: true,
  7.     drop_debugger: true
  8.   }
  9. }

CDN 加速

内容分发网络(Content Delivery Network,简称 CDN)就是让用户从最近的服务器请求资源,提升网络请求的响应速度。同时减少应用打包出来的包体积,利用浏览器缓存,不会变动的文件长期缓存。(不建议使用第三方cdn,这里做学习讨论使用)

  1. bash
  2. 复制代码npm i rollup-plugin-external-globals -D
  3. npm i vite-plugin-html -D
  4. html
  5. 复制代码<head>
  6.     <%- vuescript %>
  7. </head>
  8. css
  9. 复制代码import { createHtmlPlugin } from 'vite-plugin-html'
  10. rollupOptions: {
  11.   // 告诉打包工具 在external配置的 都是外部依赖项  不需要打包
  12.   external: ['vue'],
  13.   plugins: [
  14.     externalGlobals({
  15.       // "在项目中引入的变量名称""CDN包导出的名称,一般在CDN包中都是可见的"
  16.       vue: 'Vue'
  17.     })
  18.   ]
  19. }
  20. plugins: [
  21.     createHtmlPlugin({
  22.       minify: true,
  23.       inject: {
  24.         data: {
  25.           vuescript: '<script src="https://cdn.jsdelivr.net/npm/vue@3.2.37"></script>'
  26.         }
  27.       }
  28.     })
  29. ]

 

按需导入

仔细看上面那张图右下部分的模块,不知道你会不会感觉到奇怪,明明是同一个包,为什么既出现了lodash又出现了lodash-es。其实lodash-es 是 lodash 的 es modules 版本 ,是着具备 ES6 模块化的版本,体积小,而lodash是common.js版本。lodash最大的缺陷就是无法按需导入。

  1. js
  2. 复制代码import _ from 'lodash-es'// 你将会把整个lodash的库引入到项目
  3. import { cloneDeep } from 'lodash-es'// 你将会把引入cloneDeep引入到项目

项目中用到lodash的地方也不多,经过手动修改一下,看现在已经看不到lodash的库了。

文件压缩

  1. 复制代码npm install vite-plugin-compression -D
  2. js
  3. 复制代码// build.rollupOptions.plugins[]
  4. viteCompression({
  5.   verbose: true// 是否在控制台中输出压缩结果
  6.   disable: false,
  7.   threshold: 10240// 如果体积大于阈值,将被压缩,单位为b,体积过小时请不要压缩,以免适得其反
  8.   algorithm: 'gzip'// 压缩算法,可选['gzip'' brotliccompress ''deflate ''deflateRaw']
  9.   ext: '.gz',
  10.   deleteOriginFile: true // 源文件压缩后是否删除(我为了看压缩后的效果,先选择了true)
  11. })

当请求静态资源时,服务端发现请求资源为gzip的格式时,应该设置响应头 content-encoding: gzip 。因为浏览器解压也需要时间,所以代码体积不是很大的话不建议使用 gzip 压缩。

图片压缩

  1. bash
  2. 复制代码yarn add vite-plugin-imagemin -D

or

  1. bash
  2. 复制代码npm i vite-plugin-imagemin -D
  3. js
  4. 复制代码import viteImagemin from 'vite-plugin-imagemin'
  5. plugin: [
  6.     viteImagemin({
  7.       gifsicle: {
  8.         optimizationLevel7,
  9.         interlacedfalse
  10.       },
  11.       optipng: {
  12.         optimizationLevel7
  13.       },
  14.       mozjpeg: {
  15.         quality20
  16.       },
  17.       pngquant: {
  18.         quality: [0.80.9],
  19.         speed4
  20.       },
  21.       svgo: {
  22.         plugins: [
  23.           {
  24.             name'removeViewBox'
  25.           },
  26.           {
  27.             name'removeEmptyAttrs',
  28.             activefalse
  29.           }
  30.         ]
  31.       }
  32.     })
  33. ]

viteImagemin在国内比较难安装,容易出现报错,可以尝试一下下面几种解决方案。

viteImagemin报错
  1. 使用 yarn 在 package.json 内配置(推荐) "resolutions": { "bin-wrapper": "npm:bin-wrapper-china" }

  2. 使用 npm,在电脑 host 文件加上如下配置即可 199.232.4.133 raw.githubusercontent.com

  3. 使用 cnpm 安装(不推荐)

填坑

坑1

在优化过程中发现有什么rollupOption不生效,请检查vite版本。上述配置在vite4.0版本生效,如需升级,请前往官方迁移文档。

坑2

Uncaught TypeError: Failed to resolve module specifier "Vue". Relative references must start with either "/", "./", or "../".

图片

这里有可能是 vue-demi 引入了 vue,然而 rollup-plugin-external-globals 插件配置全局变量时不会处理 node_modules 下的依赖项,导致 vue-demi 还是通过 import 的方式与 node_modules 下的 vue 进行关联,而没有使用全局变量下的 vue,打包后 vue 已变成外部依赖项,vue-demi 自然无法找到 vue,所以就报错了。

vue-demi是哪里来的呢,我的项目是由于element-plus引用了vue-demi,所以此时解决方案就是将vue-demi也用cdn引入。

总结

到了这一步,整个文件夹已经完全瘦身了。从一开始的30MB到现在的11.8MB了。我们在项目里面放置了许多json数据(因为业务原因不能上传到服务器),json数据已经占了差不多5、6mb的原因,所以是一个单纯的项目并没有这么大。

 

 

配置
  1. js
  2. 复制代码// vite.config.js
  3. import { defineConfig } from 'vite'
  4. import { createHtmlPlugin } from 'vite-plugin-html'
  5. import viteImagemin from 'vite-plugin-imagemin'
  6. import externalGlobals from 'rollup-plugin-external-globals'
  7. import { visualizer } from 'rollup-plugin-visualizer'
  8. import viteCompression from 'vite-plugin-compression'
  9. // https://vitejs.dev/config/
  10. export default defineConfig({
  11.   plugins: [
  12.     visualizer({ opentrue }),
  13.     // 将下面的添加到plugin下
  14.     createHtmlPlugin({
  15.       minify: true,
  16.       inject: {
  17.         data: {
  18.           vuescript: '<script src="https://cdn.jsdelivr.net/npm/vue@3.2.25"></script>',
  19.           demiScript: '<script src="//cdn.jsdelivr.net/npm/vue-demi@0.13.7"></script>',
  20.           elementPlusScript: `
  21.             <link href="https://cdn.jsdelivr.net/npm/element-plus@2.2.22/dist/index.min.css" rel="stylesheet">
  22.             <script src="https://cdn.jsdelivr.net/npm/element-plus@2.2.22/dist/index.full.min.js"></script>
  23.           `,
  24.           echartsSciprt: '<script src="https://cdn.jsdelivr.net/npm/echarts@5.0.2/dist/echarts.min.js"></script>'
  25.         }
  26.       }
  27.     }),
  28.     viteImagemin({
  29.       gifsicle: {
  30.         optimizationLevel: 7,
  31.         interlaced: false
  32.       },
  33.       optipng: {
  34.         optimizationLevel: 7
  35.       },
  36.       mozjpeg: {
  37.         quality: 20
  38.       },
  39.       pngquant: {
  40.         quality: [0.80.9],
  41.         speed: 4
  42.       },
  43.       svgo: {
  44.         plugins: [
  45.           {
  46.             name: 'removeViewBox'
  47.           },
  48.           {
  49.             name: 'removeEmptyAttrs',
  50.             active: false
  51.           }
  52.         ]
  53.       }
  54.     })
  55.   ],
  56.   build: {
  57.     target: 'es2020',
  58.     minify: 'terser',
  59.     // rollup 配置
  60.     rollupOptions: {
  61.       output: {
  62.         chunkFileNames: 'js/[name]-[hash].js'// 引入文件名的名称
  63.         entryFileNames: 'js/[name]-[hash].js'// 包的入口文件名称
  64.         assetFileNames: '[ext]/[name]-[hash].[ext]'// 资源文件像 字体,图片等
  65.         manualChunks(id) {
  66.           if (id.includes('node_modules')) {
  67.             return 'vendor'
  68.           }
  69.         }
  70.       },
  71.       //  告诉打包工具 在external配置的 都是外部依赖项  不需要打包
  72.       external: ['vue''element-plus''echarts'],
  73.       plugins: [
  74.         externalGlobals({
  75.           vue: 'Vue',
  76.           'element-plus''ElementPlus',
  77.           echarts: 'echarts',
  78.           'vue-demi''VueDemi'
  79.         }),
  80.         viteCompression({
  81.           verbose: true// 是否在控制台中输出压缩结果
  82.           disable: false,
  83.           threshold: 10240// 如果体积大于阈值,将被压缩,单位为b,体积过小时请不要压缩,以免适得其反
  84.           algorithm: 'gzip'// 压缩算法,可选['gzip'' brotliccompress ''deflate ''deflateRaw']
  85.           ext: '.gz',
  86.           deleteOriginFile: false // 源文件压缩后是否删除
  87.         })
  88.       ]
  89.     },
  90.     terserOptions: {
  91.       compress: {
  92.         // 生产环境时移除console
  93.         drop_console: true,
  94.         drop_debugger: true
  95.       }
  96.     }
  97.   }
  98. })

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/338707?site
推荐阅读
相关标签
  

闽ICP备14008679号