es modules 本身不支持运行时排除模块,排除需在打包器配置层实现:webpack 用 externals 排除内置模块;vite/webpack 用 define 配合 dce 编译期剔除;通过 sideeffects 标注和 tree shaking 删除未用代码;rollup/vite 可用别名重定向至空模块。

在使用 Webpack、Vite 或 Rollup 等打包工具时,ES Modules(ESM)本身不提供运行时“排除模块”的能力,排除动作实际发生在打包器的配置层,而非 JavaScript 语法层面。关键是要让打包器在构建过程中跳过某些模块的解析、打包或生成代码——常见场景包括避免打包 Node.js 内置模块(如 fs、path)、第三方库中的非浏览器兼容代码,或按环境条件剔除调试/监控模块。
通过打包器配置 externals 排除(适用于 Webpack)
Webpack 的 externals 配置可将指定模块标记为“外部依赖”,即不将其打包进最终 bundle,而是在运行时从外部环境(如全局变量、CommonJS 模块、CDN)中获取。
- 若你用
import { readFileSync } from 'fs',但目标是浏览器环境,可这样排除:
module.exports = {
// ...
externals: {
fs: 'commonjs fs', // 保留 require('fs'),但不打包
path: 'commonjs path',
crypto: 'commonjs crypto'
}
};
- 对 ESM 形式导入(如
import * as fs from 'fs')同样生效,Webpack 会自动适配模块系统。 - 注意:若运行环境真没有
fs(比如浏览器),需确保代码逻辑不会执行到该分支,否则会报错。
用 define / replace 实现编译期条件剔除(通用且推荐)
更安全的方式是借助打包器的预定义常量(如 Vite 的 define、Webpack 的 DefinePlugin),配合 if (false) 或死代码消除(DCE)自动移除整个模块导入和调用。
- Vite 示例(vite.config.ts):
export default defineConfig({
define: {
'__DEVTOOLS__': JSON.stringify(false),
},
})
源码中写:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
if (__DEVTOOLS__) {
import('devtools-hook').then(hook => hook.install())
}
- 打包时,
if (false) { ... }被识别为不可达代码,Tree Shaking 会彻底删除该import()动态导入及其后续逻辑。 - 静态
import同样适用:if (false) { import './debugger.js' }不合法,但可改用动态导入 + 条件包裹。
借助 Tree Shaking 和无副作用标注精准控制
ES Modules 天然支持 Tree Shaking,但前提是模块被正确标记为“无副作用”(sideEffects: false),否则打包器不敢删除未显式使用的导入。
- 在
package.json中声明:
"sideEffects": false
- 或仅列出有副作用的文件:
"sideEffects": ["*.css", "index.js"] - 如果你自己写的工具模块(如
utils/log.js)只导出纯函数,且没修改全局状态或触发 I/O,就应设为无副作用——这样即使写了import { log } from './utils/log.js'却没调用log,它也会被完全剔除。 - 第三方库若未正确声明
sideEffects,可手动在 Webpack 中覆盖:
module.exports = {
resolve: {
alias: {
'some-heavy-lib': path.resolve(__dirname, 'shims/some-heavy-lib-stub.js')
}
}
}
然后在 stub 文件里只导出空对象或轻量替代实现。
按环境或构建命令动态切换模块路径(Rollup/Vite 常用)
利用打包器的插件或别名机制,在构建时将特定导入重定向到空模块或 mock 版本。
- Vite 别名示例:
resolve: {
alias: {
'@analytics/tracker': '/src/shims/analytics-stub.ts',
}
}
其中 analytics-stub.ts 可能只导出空函数:
export const track = () => {}
export const identify = () => {}
- 这样既保持类型和调用兼容,又彻底排除了原始分析 SDK 的代码体积和副作用。
- 适合 A/B 测试、灰度发布、或不同客户版本间功能裁剪。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










