Vite 项目 Node 包压缩优化:提升扩展程序性能
2025-03-08 14:15:16
优化 Vite 项目中 Node 包的压缩,提升扩展程序性能
最近在开发一个钱包扩展程序,打包特定 Node 包时,扩展程序变得异常缓慢。为了使用交易构建器之类的功能,又必须打包这个包。 这个问题有点棘手,接下来我们好好分析一下。
问题根源:为什么会慢?
导致速度变慢的罪魁祸首,很可能就是 "@bitgo/utxo-lib"
这个包。即使已经有了 dist
文件夹,其中可能包含未经优化的 CommonJS 模块。 包含大量的代码、未使用的模块以及可能存在的性能瓶颈,都可能显著增加扩展程序的体积和加载时间。
解决方法
既然找到了问题所在, 咱们看看有哪些办法可以解决这个问题。下面是几种不同的方法,根据情况可以一起用。
1. 优化 @bitgo/utxo-lib
包
最直接的方法就是优化这个包。可以从下面几个地方着手:
a. Tree Shaking (摇树优化)
看看 @bitgo/utxo-lib
包是否支持 Tree Shaking。如果支持,Vite 可以自动移除未使用的代码,大大减小打包体积。检查 package.json
中的 "sideEffects"
字段,看看它是否设置为 false
,或者是一个文件路径数组,这表示该软件包支持 tree-shaking。
- 如果
"sideEffects"
为true,或者不存在,你可以试试修改一下node_modules/@bitgo/utxo-lib/package.json
. 但要注意的是, 直接改动node_modules
的内容不是一个长期可行的做法.
b. 手动优化(如果可以的话)
如果你对 @bitgo/utxo-lib
的代码很熟悉, 尝试找出哪些部分真正被用到,手动创建一个只包含必要代码的更小版本。
c. 找找有没有替代方案
- 更轻量的库: 如果实在优化不了,试试搜索有没有更轻量级的替代库,实现类似的功能。
2. 调整 Vite 配置
对 vite.config.js
进行微调,也有可能解决一部分问题。
a. build.minify
选项
确认你的vite.config.js
文件中 build.minify
设置为了 true
。Vite 默认使用 esbuild 进行压缩,速度很快,效果也不错。
// vite.config.js
export default defineConfig({
// ...
build: {
// ...
minify: true, // 确保这个是 true
// ...
},
});
b. 使用不同的压缩器 (进阶)
Vite 默认的 esbuild
通常效果就很好. 如果你愿意折腾,也可以尝试用 terser
。 Terser 压缩效果通常更好, 但速度会慢一点.
// vite.config.js
export default defineConfig({
// ...
build: {
// ...
minify: 'terser', // 改成 terser
terserOptions: {
// Terser 压缩选项 (可以进一步微调)
compress: {
drop_console: true, // 移除 console.log 语句 (生产环境推荐)
drop_debugger: true // 移除 debugger 语句 (生产环境推荐)
}
},
},
});
记得先安装 Terser:
npm install terser --save-dev
# 或者
yarn add terser -D
c. 代码分割 (Code Splitting)
Vite 的代码分割功能是默认启用的. 它会试着把你的代码分割成更小的 chunk, 这可以提高加载速度, 尤其是初始加载。 在你的 rollupOptions
配置中:
preserveModules: true
: 此选项会将每个模块打包到其自己的文件中。preserveModulesRoot: 'src'
: 用于确定放置非入口模块的相对根目录。
你当前的配置看起来已经很不错了, 但是有时候,Vite 的自动分割可能不是最优的。可以手动配置试试。 比如说, 你确定 @bitgo/utxo-lib
主要用在 background 脚本里, 就可以尝试手动指定:
// vite.config.js
export default defineConfig({
// ...
build: {
// ...
rollupOptions: {
// ...
output: {
// ...
manualChunks(id) {
if (id.includes('@bitgo/utxo-lib')) {
return 'bitgo-utxo-lib'; // 专门给它一个 chunk
}
}
},
},
},
});
这个 manualChunks
函数能让你手动控制哪些模块放在哪个 chunk 里。
d. 审查resolve.alias
你用resolve.alias
重定向了一些模块,比如'stream', 'crypto' 和 'buffer'到浏览器的兼容版本。如果 @bitgo/utxo-lib
没有直接使用 Node.js 的这些内置模块,只是它的某些依赖用了,就可以考虑移除这些别名,或更精确地配置它们。
3. 其他优化建议
a. 异步加载
如果 @bitgo/utxo-lib
的某些功能不是立即需要的,可以考虑用动态导入 (import()
) 来异步加载。 这样能显著提升初始加载速度。
// 某个需要用到 utxo-lib 功能的模块里
async function doSomethingWithUtxoLib() {
const { someFunction } = await import('@bitgo/utxo-lib');
// 使用 someFunction ...
}
b. 使用 Web Workers
如果 @bitgo/utxo-lib
执行的是计算密集型任务,而且不直接操作 DOM, 考虑把它放到 Web Worker 里。Web Workers 在单独的线程运行, 不会阻塞主线程,可以提升用户界面的响应速度。
// main.js (或者 content script)
const worker = new Worker('worker.js');
worker.postMessage({ /* ... 数据 ... */ });
worker.onmessage = (event) => {
// 处理 worker 返回的结果
};
// worker.js
import { someFunction } from '@bitgo/utxo-lib'; // 在 worker 里导入
self.onmessage = (event) => {
const result = someFunction(event.data);
self.postMessage(result);
};
###4. 使用 pre-bundled 依赖项(针对本项目情况)
由于@bitgo/utxo-lib
有一个 dist
文件夹,它 可能 已经包含了为浏览器构建的预构建版本。 可以检查 dist
文件夹,寻找看起来像已经打包好的文件(例如, utxo-lib.min.js
, index.umd.js
或类似的文件)。
如果是这样,可以直接引用这个预构建版本:
-
找到预构建文件: 查看
@bitgo/utxo-lib
的dist
文件夹。 -
修改导入方式: 如果你的代码里是这样导入的:
import { /* ... */ } from '@bitgo/utxo-lib';
尝试改成这样 (假设预构建文件叫
utxo-lib.min.js
):import { /* ... */ } from '@bitgo/utxo-lib/dist/utxo-lib.min.js';
或者在vite.config中增加 alias配置项
'@bitgo/utxo-lib': path.resolve(__dirname, 'node_modules/@bitgo/utxo-lib/dist/utxo-lib.min.js')
- 处理 CommonJS: 如果预构建的文件仍然是 CommonJS 格式,Vite 应该会自动处理它, 把 CommonJS 转成 ES Modules.
但为了保险, 可以在构建时,用 rollup 插件将@bitgo/utxo-lib
预构建文件从CommonJS转换到ESM。
npm install @rollup/plugin-commonjs --save-dev
然后在 vite.config.js
:
import { defineConfig } from 'vite';
import { nodePolyfills } from 'vite-plugin-node-polyfills';
//增加这一行
import commonjs from '@rollup/plugin-commonjs';
// ... 其他导入
export default defineConfig({
plugins: [
// ...其他插件
commonjs({
include: ['node_modules/@bitgo/utxo-lib/dist/**']
})
]
})
5. 处理bitcoin-ops/evals.json
(根据项目情况)
项目中还用到了bitcoin-ops/evals.json
的别名. 确保路径是正确的, 如果还是不行可以内联文件。
将 src/utils/bitcoin-ops-evals.json
文件的内容直接复制到一个 JavaScript 文件中, 然后再使用它, 就避免文件系统查找:
例如:创建一个 src/utils/bitcoinOps.js
:
// src/utils/bitcoinOps.js
export const bitcoinOpsEvals = {
// ... 这里粘贴 evals.json 的内容 ...
};
在代码里,这样导入:
import { bitcoinOpsEvals } from '@/utils/bitcoinOps';
把这几种方法结合起来,应该就能大大减少扩展程序的体积, 解决卡顿的问题了! 加油!