如何在webpack等打包工具中排除指定函数不打入特定bundle?
问题解答
这个需求完全可以实现,不需要把公共逻辑拆分到客户端、服务端两个子类里,同一份源码就能输出两份内容有差异的构建产物,下面是可直接落地的方案:
方案1:webpack原生能力实现(零额外依赖,最稳定)
利用webpack内置的全局常量注入+生产环境Tree Shaking死代码消除能力,不需要自定义注释规则,构建时会自动把永远不会执行的代码从产物中完全剔除:
- 首先在不同构建目标的webpack配置中,通过
DefinePlugin注入全局构建标识:// 客户端构建配置 const webpack = require('webpack') module.exports = { mode: 'production', // 必须开启生产模式,默认启用Tree Shaking // 其余构建配置... plugins: [ new webpack.DefinePlugin({ 'process.env.BUILD_TARGET': JSON.stringify('client') }) ] } // 服务端构建配置 const webpack = require('webpack') module.exports = { mode: 'production', // 其余构建配置... plugins: [ new webpack.DefinePlugin({ 'process.env.BUILD_TARGET': JSON.stringify('server') }) ] } - 业务代码中把服务端专属逻辑放在构建标识判断块内即可:
class SomeClass { constructor(arg1, arg2) { // 双端通用初始化逻辑 } commonFunction(arg1) { // 双端通用逻辑 } } // 仅服务端构建会保留该段代码,客户端构建时会被完全剔除 if (process.env.BUILD_TARGET === 'server') { SomeClass.prototype.serverOnly = function(serverArg) { // 服务端专属逻辑,比如调用Node原生API、操作服务端资源等 } }
客户端打包时,webpack会静态分析出process.env.BUILD_TARGET === 'server'恒为false,整个if块的代码会被当做死代码完全删除,最终产物里不会存在任何serverOnly相关的代码;服务端构建时则会正常保留该方法,完全符合预期。
方案2:自定义注释标记实现(匹配示例中的注释写法)
如果你希望直接通过/* webpack-dont-pack */这类注释标记需要剔除的代码,不需要写环境判断块,可以写一个极简的自定义webpack loader,在JS代码解析阶段处理AST:
- 客户端构建时启用该loader,服务端构建时不启用
- loader内部通过JS解析器(比如@babel/parser、acorn)将代码转成AST,遍历所有类方法、函数声明节点,识别到节点前置注释包含你自定义的
webpack-dont-pack标记时,直接将该节点从AST中移除 - 把处理后的AST转回JS代码交给后续webpack构建流程即可
该方案可以1:1实现你举例的注释标记效果,业务代码不需要额外包裹判断逻辑。
其他打包工具适配
如果你使用Rollup、Vite、esbuild等其他打包工具,实现逻辑完全一致:
- 可以用工具自带的全局常量注入能力配合Tree Shaking做死代码消除,和webpack原生方案效果一致
- 也可以通过工具的插件接口,实现自定义注释标记的代码剥离能力
注意事项
- 所有代码剔除逻辑必须是构建时静态处理,不要依赖运行时判断,否则代码还是会被打包进产物,只是运行时不执行,达不到体积优化、代码隔离的效果
- 只要开启生产模式的默认优化配置,死代码消除不会残留冗余代码,剔除效果和手动删除代码完全一致
内容的提问来源于stack exchange,提问作者Joseph Terribile
相关产品推荐
相关产品推荐

