Serverless 无服务器架构把服务器运维的负担交给了云厂商,开发者只需要关注函数代码本身。但这种模式对构建工具提出了新的要求:函数需要频繁部署、冷启动要尽量快、产物体积要尽可能小。Webpack 5 在这个时间点发布,带来了持久化缓存、模块联邦、更好的 Tree Shaking 等一系列特性,恰好命中了 Serverless 场景的痛点。本文将围绕这些新特性,结合函数计算的实际部署需求,讲清楚如何在 Serverless 架构下用好 Webpack 5。

为什么 Serverless 场景需要重新审视构建工具
先理解 Serverless 对构建产物的特殊要求。传统的 Node 应用部署在常驻服务器上,启动一次可以服务成千上万个请求,依赖体积大一点、启动慢一点影响并不明显。但函数计算完全不同:实例会随着流量伸缩,缩容到零之后再有请求进来就要经历冷启动,而冷启动时间直接受代码包体积和依赖加载速度的影响。
一个典型的例子是:函数代码本身可能只有几十 KB,但 node_modules 打包进去之后轻松超过 50 MB。云厂商通常对代码包有大小限制(比如阿里云函数计算压缩后限制 100 MB,AWS Lambda 解压后限制 250 MB),超限直接部署失败。这就要求构建工具能做精细的依赖分析,把真正用到的代码打进产物,没用的全部剔除。
Webpack 4 时代的构建还有一个问题:每次部署都要全量构建,大型项目构建一次几分钟很常见。Serverless 的迭代节奏快,一天可能发布几十次,构建时间累积起来非常可观。Webpack 5 的持久化缓存正是为解决这个问题而设计的。
持久化缓存:让函数构建从分钟级降到秒级
Webpack 5 移除了原本实验性的 cache 配置项,重新设计了文件系统缓存。开启之后,Webpack 会把模块解析结果、代码生成结果、依赖图等信息序列化到磁盘上,二次构建时只重新编译真正变化的部分,其余直接从缓存恢复。官方数据显示缓存命中时构建速度可以提升 60% 到 90%。
配置方式很简单,在 webpack 配置中加上:
module.exports = {
// 开发环境使用内存缓存,生产环境落到磁盘
cache: {
type: 'filesystem',
// 缓存目录,Serverless CI 环境中建议放到独立目录便于复用
cacheDirectory: path.resolve(__dirname, '.webpack_cache'),
buildDependencies: {
// 配置文件变化时缓存自动失效
config: [__filename]
}
}
};在 Serverless 的 CI 流水线里,配合缓存目录的上传与还原,可以做到只在依赖真正变化时才触发昂贵的全量编译。需要注意 buildDependencies 的设置:如果 package.json 或 webpack 配置变了,缓存必须失效,否则可能打包出过期产物。这一点在多人协作的函数仓库中尤其重要,配置错了会导致偶发的线上问题,排查起来非常困难。
另一个细节是缓存版本管理。Webpack 会根据自身版本、loader 版本、配置内容生成缓存标识,升级 Webpack 后旧缓存会自动失效,不需要手动清理。但如果你在流水线里缓存了 .webpack_cache 目录,建议在升级构建镜像时同步清空一次,避免磁盘空间被历史缓存吃光。
模块联邦:多个函数应用共享依赖的正确姿势
Serverless 架构下,应用往往被拆成多个独立的函数或多个独立的站点(比如主站、活动页、管理后台)。这些应用之间共享组件和依赖,传统做法是发 npm 包,每次更新都要各应用升级重新发布。Webpack 5 的模块联邦(Module Federation)提供了运行时共享的能力,对 Serverless 场景特别有价值。
比如主站已经打包了 React 和一套 UI 组件,活动页可以直接在运行时引用主站暴露的模块,自己不再打包 React:
// 主站 webpack 配置,作为容器暴露模块
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'host',
filename: 'remoteEntry.js',
exposes: {
'./Button': './src/components/Button',
'./utils': './src/utils/format'
},
shared: {
react: { singleton: true, eager: true },
'react-dom': { singleton: true, eager: true }
}
})
]
};
// 活动页作为消费者,远程加载主站的模块
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'remote',
remotes: {
host: 'host@https://cdn.ipipp.com/remoteEntry.js'
},
shared: {
react: { singleton: true },
'react-dom': { singleton: true }
}
})
]
};这里的关键是 shared 配置中的 singleton 选项。React 这类库对单实例有强要求,如果两个应用各自加载了一份 React,会出现 Hooks 报错等诡异问题。设为 singleton: true 后运行时只会保留一份。版本协商机制会优先使用满足版本范围的最高版本,避免重复下载。
对函数计算来说,模块联邦更直接的收益是减少函数代码包体积。公共依赖被抽到 CDN 上独立部署,函数包里只保留业务代码和远程引用逻辑,冷启动时按需拉取。配合 CDN 边缘缓存,实际加载延迟完全可接受。
针对函数计算的完整构建配置实战
最后给一份可以直接用于 Node 函数计算的 webpack 5 生产配置。核心思路有三点:用 externals 把云厂商 SDK 和大依赖排除出包、用持久化缓存加速重复构建、关掉一切生产环境不需要的功能。
const path = require('path');
const nodeExternals = require('webpack-node-externals');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
mode: 'production',
target: 'node14', // 按函数运行时选择
entry: './src/handler.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.js',
library: {
type: 'commonjs2' // 函数计算通过 require 加载入口
},
// 函数运行时通常不支持 sourceMap 文件服务,直接去掉
devtoolModuleFilenameTemplate: info => ''
},
// 排除 node_modules,依赖走函数层或镜像安装
externals: [nodeExternals()],
cache: {
type: 'filesystem',
cacheDirectory: path.resolve(__dirname, '.webpack_cache'),
buildDependencies: { config: [__filename] }
},
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: { drop_console: true } // 去掉日志减小体积
}
})
]
},
stats: 'errors-warnings'
};几个配置项值得展开说明。target: 'node14' 是 Webpack 5 的新写法,可以直接指定运行时版本,Webpack 会据此决定是否 polyfill 某些语法,避免打出浏览器专用的兼容代码。externals 使用 webpack-node-externals 把所有 node_modules 排除,是因为函数计算支持依赖层(Layer)机制,把依赖单独打包成层可以复用,业务代码迭代时不用重复上传几百 MB 的依赖。
如果是前端页面跑在 Serverless 静态托管上,还要注意 Tree Shaking 的增强。Webpack 5 支持了对嵌套的导出做无用代码消除,还能分析 package.json 中的 sideEffects 字段。确保你的组件库在 package.json 里正确声明了 sideEffects: false,配合 optimization.usedExports,能把没用到的工具函数整棵剔除,产物体积往往能降 20% 以上。
部署环节还有一个小技巧:函数计算的代码包是先压缩再上传的,可以在 CI 中使用 gzip 压缩级别 9 的 tar 包,同时把 dist 目录里的 .map 文件分离出来上传到错误监控平台,代码包里不带 sourceMap。这样既保留了线上报错的可定位性,又把代码包压到最小,冷启动加载时间进一步缩短。
总结一下,Webpack 5 的持久化缓存解决了 Serverless 高频发布的构建效率问题,模块联邦解决了多应用依赖重复打包的问题,加上更精细的 Tree Shaking 和 Node target 支持,它确实是目前 Serverless 场景下最合适的构建工具之一。如果你还在用 Webpack 4 构建函数,升级之后配合好缓存与依赖分层,构建部署体验会有质的提升。
Webpack 5Serverless模块联邦修改时间:2026-09-07 08:58:46