Vite性能优化指南 ✅

目录

1️⃣ 树摇
2️⃣ 分包
3️⃣ 多入口打包
4️⃣ 其他优化手段


树摇

“树摇”这玩意并非某个构建工具的专利,应该说基于ESM模块化开发的项目都有能力进行树摇。详细的分析可见煮啵的另一篇文章中的最后一小节,最核心的原因是CJS的require本质上是一个运行时的函数。此处只介绍树摇带来的具体效果:

// utils/index.js
export function util1() {
    console.log('util1')
}
export function util2() {
    console.log('util2')
}

// main.js 入口文件
import { util1 } from './utils/index.js
console.log(util1)

这样的代码在打包后会摒弃未被使用的util2,只保留被使用的util1。但如果用CJS模块化进行改写:

// utils/index.js
exports.util1 = () => console.log('util1')
exports.util2 = () => console.log('util2')

// main.js 入口文件
const { util1 } = require('./utils/index.js')

这种写法在打包后,即使util2未被使用,但也会带打包产物中被保留。


分包

在PDD的三面中被狠狠拷打🤯
“分包”即所谓的“代码分割”。常用的实现分包的方法有两种:通过修改Vite配置文件进行分包,或者通过动态导入语法import()进行代码分割。

通过修改Vite配置文件

设想一下:在我们的项目中引入了lodash,在进行分包前,lodash相关的代码会和业务代码一起被打包到同一个chunk中,且chunk的命名是通过哈希的方法来生成的,只要业务代码发生改动,那么chunk的命名几乎就会改变。
问题是,每一次更新我们修改的只是业务代码,lodash这些第三方包的代码我们肯定是不会改动的,但是每一次更新(甚至是每一次刷新)浏览器都得重新请求一次lodash的代码。因为lodash所在的chunk的名称会随版本的更新而变化,对这个chunk的请求浏览器走不了缓存。
所以我们的需求很简单:有没有办法让lodash被打包到一个单独的chunk中,后续浏览器只在第一次加载的时候请求这个chunk即可,后续都读缓存,以提高响应速度?有的兄弟,有的🤓🤓,以下介绍最基本的分包方法(详细的配置可见rollup的文档):

// vite.config.js
import { defineConfig } from "vite";
export default defineConfig({
	build: {
        minify: false,  // 取消默认的压缩行为,方便观察打包产物
        rollupOptions: {
            output: {
                manualChunks: (id, { getModuleInfo }) => {
                	// getModuleInfo可以查看当前模块的信息
                    if (id.includes('node_modules/lodash')) 
       					return "vendor/lodash"
                }
            }
        }
    },
})

通过import()动态导入

import()动态导入也是实现代码分割的方法,这种优化本质上是借助Promise实现的,详细的分析见煮啵的另一篇博文的最后一章。import动态导入常用于实现路由懒加载(组件按需引入)。以React为例,见以下Demo:

// LazyComponent.tsx
export default function LazyComponent() {
  return <div>LazyComponent</div>;
}

// App.tsx
import { lazy } from "react";
// 动态(按需)引用懒加载组件
const LazyComponent = lazy(() => import("./LazyComponent/index"));
const App = () => {
  return (
    <div>
      <div>App</div>
      <LazyComponent />
    </div>
  );
};
export default App;

之后不管是Chrome控制台还是本地打包产物,都可以看见LazyComponent组件相关的代码被抽离为一个单独的chunk。


多入口打包

多入口打包允许你将一个项目拆分为多个独立的入口文件(如前台index.html后台admin.html),每个入口生成单独的依赖图和资源包。这种优化方法更适合多页面应用MPA,不适合常见的SPA应用。~~煮啵用的是在是不多。~~假设现在前端股工程的目录如下:
App/
|—src
|——scriptA.js # 脚本A
|——scriptB.js # 脚本B
|——utils.js # 工具函数
|—indexA.html # 入口A
|—indexB.html # 入口B
|—vite.config.js
代码如下:

// utils.js
export function sayHello() {
    console.log('Hello')
}
export function sayGoodbye() {
    console.log('Goodbye')
}

// scriptA.js
import { sayHello } from "./utils";
function scriptA() {
    console.log("scriptA is running");
    sayHello();
}
scriptA();

// scriptB.js
import { sayHello, sayGoodbye } from "./utils";
function scriptB() {
    console.log("scriptB is running");
    sayHello();
    sayGoodbye();
}
scriptB();

// vite.config.js
export default defineConfig({
    build: {
        minify: false,  // 取消默认的压缩行为,方便观察打包后的产物
        rollupOptions: {
            input: {
                scriptA: path.resolve(__dirname, 'src/indexA.html'),
                scriptB: path.resolve(__dirname, 'src/indexB.html'),
            },
        }
    },
})

此时Vite会以scriptA.js和scriptB.js这两个文件为入口,打包的产物有三个脚本文件,分别为:

// scriptA-HashCode.js
import { s as sayHello } from "./index-BVlMXCZJ.js";
function scriptA() {
  console.log("scriptA is running");
  sayHello();
}
scriptA();

// scriptB-HashCode.js
import { s as sayHello, a as sayGoodbye } from "./index-BVlMXCZJ.js";
function scriptB() {
  console.log("scriptB is running");
  sayHello();
  sayGoodbye();
}
scriptB();

// index-HashCode.js
(function polyfill() {
	// ...额外的与Vite相关的代码。
})()
function sayHello() {
  console.log("Hello");
}
function sayGoodbye() {
  console.log("Goodbye");
}
export {
  sayGoodbye as a,
  sayHello as s
};

此处Vite已进行了默认的优化。默认情况下被引用了至少两次的文件,会被打成一个独立的包。因为sayHello被多次复用,在构建中次函数所属的文件会被单独抽离出来。如果sayHello只在一处被调用,那么打包后它会在调用处的chunk中被声明。


其他优化手段

图片转Base64

关于Base64的分析见煮啵另一篇博文的最后一章。Vite默认将小于4KB的图片转为Base64格式,也可以自己手动调整:

// vite.config.js
export default {
  build: {
    assetsInlineLimit: 4096, // 调整阈值
  },
};

开启资源压缩

Vite默认 (没有手动配过,一直用的是默认) 使用 Terser 压缩 JS,ESBuild 压缩 CSS:

// vite.config.js
export default {
  build: {
    minify: 'terser', // 或 'esbuild'(更快但压缩率略低)
    terserOptions: {  // 自定义 Terser 配置
      compress: { drop_console: true },
    },
  },
};

暂时只想到这么多。后续有新的再来补充🧊

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值