Rollup 的 tree-shaking 仅作用于 ES 模块导入链,不处理 HTML 文件;HTML 中的 script 标签(无论外链、内联或动态加载)均不参与依赖分析,除非其代码被 JS 入口通过 import 显式引入。

Rollup 本身不处理 HTML 文件的 tree-shaking,它只对 JavaScript 模块做静态分析和消除;HTML 中的 <script> 标签引用的代码是否被摇掉,取决于这些脚本是否被 JS 模块图真正“导入”并参与依赖分析。
Rollup 的 tree-shaking 只作用于 ES 模块导入链
Rollup 不解析 HTML 内容,也不会把 <script src="main.js"></script> 当作模块依赖去追踪。它只从入口文件(如 src/index.js)开始,顺着 import 和 export 静态分析调用关系。HTML 里直接挂载的全局脚本、IIFE、或通过 document.createElement('script') 动态加载的代码,完全游离在 Rollup 的模块图之外,不会被 shake。
- ✅ 正确方式:让 HTML 引用的 JS 文件是 Rollup 的输出产物(如
dist/bundle.js),且该产物由 ES 模块构建而来 - ❌ 错误假设:在 HTML 里写
<script src="utils.js"></script>,指望 Rollup 自动删掉utils.js里未被index.jsimport 的函数 - ⚠️ 特别注意:
export * from './foo.js'会保留所有导出,即使下游只用了其中一个,也可能阻碍 shaking —— 改用具名重导出export { helperA } from './foo.js'
HTML 插件(如 @rollup/plugin-html)只是注入,不参与分析
像 @rollup/plugin-html 这类插件的作用,是读取 index.html 模板,把生成的 JS/CSS 路径自动填进去(比如把 <script type="module" src="/index.js"></script> 替换成 <script src="/bundle.abc123.js"></script>)。它不解析 HTML 里的 JS 内容,也不改变 Rollup 的依赖图。
- 它不会把 HTML 中内联的
<script>console.log('hi')</script>当作模块处理 - 它不会识别
<script src="legacy.js"></script>是否被用到,更不会删掉这行 - 如果你希望 HTML 中的内联脚本也被分析,必须先把它转成模块:抽成
inline.js,再在入口里import './inline.js'
真正减小体积的关键动作
tree-shaking 生效的前提是一整套协作机制,不是加个插件就自动变小:
立即学习“前端免费学习笔记(深入)”;
- 入口文件必须用
import/export,不能混用require或全局变量赋值 - 第三方库要提供 ESM 版本(检查
package.json中是否有"module": "dist/esm/index.js"),否则 Rollup 会 fallback 到 CJS,失去 shaking 能力 - 避免在入口或工具函数中无条件执行副作用代码(如顶层
localStorage.getItem()、new Worker()),Rollup 默认保守保留有副作用的语句 - 启用
treeshake: { moduleSideEffects: false }(慎用)可强制忽略模块副作用,但需确保你清楚每个依赖的行为
最常被忽略的一点:HTML 本身不参与打包体积优化,但它决定了你能否让所有逻辑都进入 Rollup 的模块图。如果仍有脚本绕过 import 直接挂在全局,那它们就永远在 tree-shaking 的雷达之外。



















