Node.js Serverless 瘦身指南:用 esbuild 榨干发布包的每一 KB
在 Serverless 架构中,发布包(Deployment Package)的体积直接关系到两个核心指标:部署速度和冷启动时间。对于 AWS Lambda、阿里云函数计算等平台,过大的压缩包会导致云端解压耗时大幅增加。
传统的 zip -r node_modules 方案往往会将大量无用的依赖(如测试脚本、文档、甚至是未被使用的子依赖)打包进去,导致体积动辄几十甚至上百 MB。本文将教你如何利用 esbuild 这款高性能构建工具,实现发布包的极致优化。
为什么选择 esbuild?
- 极速编译:比 Webpack 快 10-100 倍,极大地缩短 CI/CD 流程。
- 原生 Tree Shaking:能有效剔除未被引用的代码。
- 单文件输出:将所有依赖打入一个 JS 文件,减少文件系统 IO 寻址。
核心配置策略
要实现最小化打包,我们需要在 esbuild 的配置中重点关注以下几个参数。
1. 基础打包配置
首先,我们需要开启 bundle 和 minify。
const esbuild = require('esbuild');
esbuild.build({
entryPoints: ['src/index.ts'],
bundle: true, // 开启打包,将依赖合并
minify: true, // 压缩代码,剔除空格、注释、缩短变量名
platform: 'node', // 目标平台
target: 'node18', // 根据你的运行环境设定
outfile: 'dist/index.js',
sourcemap: false, // 生产环境建议关闭,或使用 hidden 模式
}).catch(() => process.exit(1));
2. 精确设置 External(外部依赖)
这是优化体积最关键的一步。有些库是不需要打进包里的:
- 运行时已内置的库:如 AWS SDK(在 Lambda 环境中已内置)。
- 二进制 Native 模块:如
sharp、canvas、pg-native。esbuild 无法直接打包这些 C++ 模块,应将其排除并通过 Layer 或重新安装的方式处理。
external: [
'aws-sdk', // AWS Lambda 已内置
'@aws-sdk/*', // v3 版本的 SDK
'sqlite3', // 含有原生二进制,建议排除
'fsevents' // 仅开发环境需要
],
3. 树摇优化(Tree Shaking)
esbuild 默认对 ESM 模块开启 Tree Shaking。如果你的依赖项使用的是 CommonJS,可以通过以下方式强制优化:
- 尽量使用支持 ESM 的第三方库。
- 在
package.json中配置sideEffects: false(如果你是库作者)。 - 即使是 CJS,esbuild 也会尝试进行简单的死代码删除。
进阶优化技巧
处理 CJS 兼容性问题
部分旧的 Node.js 库依赖 __dirname 或 __filename。由于 esbuild 将所有内容打成一个文件,这些变量会失效。
解决方案:使用 define 注入环境变量,或者使用 esbuild 插件修复路径。
define: {
'process.env.NODE_ENV': '"production"',
},
banner: {
js: "import { createRequire } from 'module'; const require = createRequire(import.meta.url);",
},
结合 Serverless Framework 使用
如果你使用 Serverless Framework,可以直接集成 serverless-esbuild 插件,它会自动处理上述逻辑:
# serverless.yml
plugins:
- serverless-esbuild
custom:
esbuild:
bundle: true
minify: true
external:
- 'aws-sdk'
exclude:
- '*' # 排除 node_modules 目录进入最终的 zip
避坑指南
- 动态 Require:如果代码中存在
require('./langs/' + lang)这种动态加载,esbuild 无法静态分析。你需要使用loader配置或者手动将这些资源文件放入发布包。 - Native Modules:如
prisma、bcrypt等。这些库必须在目标运行环境(如 Linux)下安装。建议通过 Docker 构建,并将这些依赖放在external中,最后在dist目录下运行npm install --production。 - Top-level Await:虽然 esbuild 支持,但请确保你的 Node.js 运行时版本(14.8+)也支持。
总结
通过 esbuild,一个典型的 Node.js Serverless 项目包体积通常能从 80MB (node_modules) 锐减至 500KB - 2MB (Single File)。这不仅节省了存储成本,更让你的函数响应速度有了质的飞跃。
建议实践: 先开启 bundle 和 minify,观察运行结果。如果报错提示找不到模块,再通过 external 排除特定库。追求极致的你,甚至可以配合压缩工具(如 Brotli)进一步处理静态资源。