# https://github.com/Menci/vite-plugin-top-level-await 项目说明书

生成时间：2026-06-14 20:49:49 UTC

## 目录

- [Plugin Overview & Build Pipeline Architecture](#page-1)
- [Bundle Analysis & AST Transformation](#page-2)
- [Configuration Options & Worker (IIFE/ES) Handling](#page-3)
- [Compatibility, Known Issues & Failure Modes](#page-4)

<a id='page-1'></a>

## Plugin Overview & Build Pipeline Architecture

### 相关页面

相关主题：[Bundle Analysis & AST Transformation](#page-2), [Configuration Options & Worker (IIFE/ES) Handling](#page-3)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/index.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/index.ts)
- [src/bundle-info.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/bundle-info.ts)
- [src/transform.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/transform.ts)
- [src/utils/make-node.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/utils/make-node.ts)
- [src/esbuild.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/esbuild.ts)
- [package.json](https://github.com/Menci/vite-plugin-top-level-await/blob/main/package.json)
- [README.md](https://github.com/Menci/vite-plugin-top-level-await/blob/main/README.md)
</details>

# Plugin Overview & Build Pipeline Architecture

## 概述与设计目标

`vite-plugin-top-level-await` 是一个针对 Vite 的构建期插件，其核心目标是将包含顶层 `await`（Top-Level Await, TLA）或顶层动态 `import()` 的 ES 模块转换为旧版本浏览器与某些 Web Worker 模式可以加载的兼容代码。资料来源：[package.json:1-1]()

根据 [README.md](README.md) 的描述，该插件的设计思路是：保留 Vite 默认的 `es2020` 构建目标（覆盖 Edge 88、Firefox 78、Chrome 87、Safari 14 等），而无需将 `build.target` 强制提升到 `esnext` 即可让 TLA 代码运行。资料来源：[src/index.ts:11-11]()

其转换的核心思想是：把模块顶层语句包裹到一个异步 IIFE 中，并将得到的 Promise 通过一个固定名字（默认 `__tla`）作为命名导出暴露，让所有依赖该模块的下游 chunk 显式 `await` 该 Promise，从而保持模块求值的因果顺序。

## 插件架构与构建管线

插件入口位于 `src/index.ts`，整体由 Rollup/Vite 钩子串联起来，关键生命周期节点如下：

- **插件元数据**：插件名为 `vite-plugin-top-level-await`，`enforce: "post"` 确保它在用户自定义插件之后运行。资料来源：[src/index.ts:31-32]()
- **`outputOptions` 钩子**：当处于 Worker 构建且目标格式为 `iife` 时，强制切换为 `es`，因为 IIFE 沙箱无法承载 TLA。资料来源：[src/index.ts:36-44]()
- **`generateBundle` 钩子**：这是核心转换阶段。插件利用一个内部子构建（`rollup({ plugins: [virtual(...)] })`）对 Rollup 已生成的 chunk 进行二次加工，包括解析 AST、构建依赖图、传播 `transformNeeded`、改写模块并交由 esbuild 重新生成目标语法。资料来源：[src/index.ts:45-66]()
- **`buildTarget` 与 `minify` 缓存**：插件把 Vite 的 `build.target` 与 `build.minify` 缓存到闭包变量，在子构建中复用。资料来源：[src/index.ts:23-28]()

构建流水线的整体形态可由下表时序图概括：

```mermaid
flowchart TD
    A[Vite/Rollup 主构建] --> B[生成 OutputBundle]
    B --> C[parseBundleAsts: SWC 解析每个 chunk]
    C --> D[parseBundleInfo: 构建依赖图 + 传播 transformNeeded]
    D --> E{模块是否含 TLA 或 dynamic import?}
    E -- 是 --> F[transformModule: AST 包装为 __tla Promise]
    E -- 否 --> G[保持原样]
    F --> H[esbuild.transform: 以 build.target 重新输出]
    G --> H
    H --> I[回写到 OutputBundle]
    I --> J[最终 Vite 产物]
```

依赖图传播逻辑位于 `src/bundle-info.ts`：当一个模块被标记为 `transformNeeded` 后，其所有反向依赖（`importedBy`）都会被加入 BFS 队列继续传播，确保任何消费了 TLA chunk 的模块也能正确处理对 `__tla` 的等待。资料来源：[src/bundle-info.ts:36-49]()

## 核心组件

- **`src/index.ts`**：插件主入口，负责插件定义、构建目标管理、Rollup 子构建与 esbuild 调用。
- **`src/bundle-info.ts`**：依赖图与传播逻辑所在地；导出 `parseBundleAsts` 与 `parseBundleInfo` 两个核心函数。
- **`src/transform.ts`**：对单个模块的 AST 进行 TLA 包装的关键改写逻辑；同时负责处理 import 重写、变量提升、函数/类声明转换等细节。
- **`src/utils/make-node.ts`**：SWC AST 节点的工厂方法集合（`makeIdentifier`、`makeStatement`、`makeAwaitExpression` 等），让改写阶段可读性更高。
- **`src/esbuild.ts`**：一个利用 Node `module._resolveFilename` 从 Vite 内部上下文加载其私有 esbuild 的小工具，避免插件直接绑定 esbuild 版本。资料来源：[src/esbuild.ts:4-10]()

插件的运行时依赖集中在 `package.json` 中：`@swc/core` 与 `@swc/wasm` 提供解析能力，`@rollup/plugin-virtual` 支撑子构建的虚拟模块机制，`uuid` 用于生成随机标识符。资料来源：[package.json:36-41]()

## 已知限制与社区问题

该插件处于活跃维护状态，但根据 issue 跟踪记录，仍存在以下需要注意的边界条件：

- **Vite 8 兼容性**：升级到 Vite 8 后，发布到 npm 的 `dist/index.js` 会找不到 `rollup` 模块，提示发布产物未正确打包。资料来源：[issue #76](https://github.com/Menci/vite-plugin-top-level-await/issues/76)
- **默认 target 覆盖**：插件在未显式设置 `build.target` 时会写入自己的 `DEFAULT_VITE_TARGET`，可能覆盖用户 Vite 配置中的默认值。资料来源：[src/index.ts:11-11]() 与 [issue #77](https://github.com/Menci/vite-plugin-top-level-await/issues/77)
- **chunk hash 失效**：`generateBundle` 中的代码改写不会触发 Vite 的 hash 重算，导致浏览器/CDN 缓存命中陈旧资源。资料来源：[issue #44](https://github.com/Menci/vite-plugin-top-level-await/issues/44)
- **source map 丢失**：子构建重新生成代码时未附加 `sourceMappingURL`，会破坏调试体验。资料来源：[issue #34](https://github.com/Menci/vite-plugin-top-level-await/issues/34)
- **Bun 运行时崩溃**：`src/esbuild.ts` 依赖 Node 内部 `Module._resolveFilename`，在 Bun 加载配置阶段会抛 `virtualModule.require is not a function`。资料来源：[issue #68](https://github.com/Menci/vite-plugin-top-level-await/issues/68)
- **函数提升被破坏**：`function` 声明会被转换为函数表达式并赋给 `let`，从而失去 hoisting 行为，可能导致循环依赖代码出错。资料来源：[src/transform.ts:34-44]() 与 [issue #71](https://github.com/Menci/vite-plugin-top-level-await/issues/71)
- **初始化顺序错乱**：TLA 与 deferred export 在 `__tla` 的 `Promise.all` 中调度，依赖紧耦合的模块可能在 `__tla` 解析前就访问导出值。资料来源：[issue #74](https://github.com/Menci/vite-plugin-top-level-await/issues/74)

## See Also

- Configuration & Options Reference — `promiseExportName` 与 `promiseImportName` 的语义
- TLA Transformation Deep Dive — `transformModule` 的 AST 改写细节
- Worker Build Mode — IIFE 模式与 ES 模式的兼容策略
- Vite Compatibility Matrix — 与 Vite 2.x 至 Vite 7/8 的版本对应关系

---

<a id='page-2'></a>

## Bundle Analysis & AST Transformation

### 相关页面

相关主题：[Configuration Options & Worker (IIFE/ES) Handling](#page-3)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/bundle-info.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/bundle-info.ts)
- [src/transform.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/transform.ts)
- [src/find.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/find.ts)
- [src/swc.d.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/swc.d.ts)
- [src/utils/make-node.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/utils/make-node.ts)
- [src/index.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/index.ts)
- [src/esbuild.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/esbuild.ts)
</details>

# Bundle Analysis & AST Transformation

## 概述

`vite-plugin-top-level-await` 的核心工作分为两个紧密耦合的阶段：**包级依赖分析**（Build-time Dependency Analysis）与 **AST 改写**（Source-level Transformation）。两者均在 Rollup 的 `generateBundle` 钩子中执行，借助 SWC 完成解析与打印，再借助 esbuild 把改写后的 ES2022 代码转译到目标平台。分析阶段判定哪些 chunk 必须被改写以及它们之间的依赖拓扑；改写阶段把 `await` 与动态 `import()` 包裹进一个异步 IIFE，并通过 `__tla` Promise 沿依赖图向后传播初始化顺序（资料来源：[src/index.ts:1-30]()）。

## 1. 包级依赖分析 (Bundle Analysis)

### 1.1 核心数据模型

分析阶段维护 `ModuleInfo` 类型，包含四类字段：

| 字段 | 类型 | 含义 |
|------|------|------|
| `imported` | `string[]` | 当前模块直接 `import` / `export from` 的相对模块名 |
| `importedBy` | `string[]` | 反向依赖（哪些模块引用了当前模块） |
| `withTopLevelAwait` | `boolean` | 是否包含顶层 `await` 表达式 |
| `transformNeeded` | `boolean` | 是否需要被本插件改写 |

资料来源：[src/bundle-info.ts:12-17]()

### 1.2 两遍扫描算法

`parseBundleInfo` 通过两个 Pass 完成依赖图构建（资料来源：[src/bundle-info.ts:33-80]()）：

- **Pass 1**（正向）：遍历每个 chunk 的 AST，识别 `ImportDeclaration` 与 `ExportNamedDeclaration` 的 `source`，解析得到相对模块名并写入 `imported`；同时为被引用方填充 `importedBy`。最后调用 `findHighestPattern` 判定是否存在 `TopLevelAwait` 或 `DynamicImport` 模式，进而决定 `transformNeeded` 与 `withTopLevelAwait`（[src/find.ts]() 提供模式识别）。
- **Pass 2**（反向 BFS 传播）：以所有 `transformNeeded` 模块为种子，对反向图传播。任何引用了被改写 chunk 的上游 chunk 都必须也参与改写——因为后者导出的值现在是在异步包装器内初始化的，导入方必须 `await __tla` 才能读到正确的值。

```mermaid
flowchart LR
  A[Rollup generateBundle] --> B[parseBundleAsts<br/>SWC.parse]
  B --> C[Pass 1<br/>正向依赖图]
  C --> D[findHighestPattern]
  D --> E[Pass 2<br/>反向 BFS 传播]
  E --> F[transformNeeded 集合]
  F --> G[transformModule per chunk]
```

## 2. AST 改写 (AST Transformation)

### 2.1 改写入口

`transformModule(code, ast, moduleName, bundleInfo, options)` 接收原始源码、AST、模块名、依赖图与配置，返回改写后的 AST。它通过 `RandomIdentifierGenerator` 生成不会与用户代码冲突的随机标识符，避免与导出名碰撞（资料来源：[src/transform.ts:78-79]()）。

### 2.2 导出类型归一化

Rollup 输出顶层通常只有一条 `export {}` 声明，但部分插件（例如 `@vitejs/plugin-legacy`）会注入额外的顶层导出。改写器把所有顶层导出归一化为变量赋值 + 末尾 `export { ... }` 列表：

- `ExportDefaultExpression` → 生成随机名赋值，`exportMap["default"] = identifier`。
- `ExportDefaultDeclaration` 若带 `identifier`，先通过 `expressionToDeclaration` 转为声明；否则赋给随机变量。
- `ExportDeclaration`（函数/类声明）移除 `export` 关键字，声明留在原位，记录到 `exportMap`。
- 不带 `source` 的 `ExportNamedDeclaration`（`export { a as b }`）保留 specifier。
- 带 `source` 的 `ExportNamedDeclaration`（`export { a } from "x"`）复制为新的 `ImportDeclaration`，再添加转发导出。

资料来源：[src/transform.ts:86-150]()

### 2.3 `__tla` Promise 包装

所有原本的顶层语句被包裹到一个 `Promise.all([...]).then(async () => { ... })` 中：

- 对每个被 `importedBy` 标记为 `transformNeeded` 的导入，注入 `import { __tla as __tla_i } from "./..."`，并把 `(() => { try { return __tla_i; } catch {} })()` 加入 `Promise.all` 数组。
- 在 IIFE 内按原顺序执行用户代码，导出变量替换为 `let` 声明 + 赋值。
- 当前 chunk 若没有 `importedBy`（即入口），则仅作为语句执行 `__tla`；否则把 `__tla` 自身加入导出列表，供上游 `await`。
- 名称 `__tla` 可通过 `options.promiseExportName` 自定义。

资料来源：[src/transform.ts:165-180](), [src/transform.spec.ts:25-90]()

### 2.4 已知改写副作用

- **函数提升被破坏**：`function foo() {}` 原先提升的声明，会变成 `let foo; ... foo = function ...`，导致声明前对 `foo.bar` 的赋值失败（[Issue #71](https://github.com/Menci/vite-plugin-top-level-await/issues/71)）。
- **初始化顺序问题**：依赖 `export { GREEN }` 在导入方立刻可读的项目（如 Remix、模块联邦）可能拿到 `undefined`，因为 `import` 取到的是已被包裹到异步块中的变量绑定（[Issue #72](https://github.com/Menci/vite-plugin-top-level-await/issues/72), [Issue #74](https://github.com/Menci/vite-plugin-top-level-await/issues/74)）。
- **hash 不更新**：`generateBundle` 阶段替换 chunk 代码不会重算 hash，导致 CDN 缓存命中旧资源（[Issue #44](https://github.com/Menci/vite-plugin-top-level-await/issues/44)）。

## 3. AST 节点构造工具

`src/utils/make-node.ts` 集中了所有 SWC 节点的工厂函数：`makeIdentifier`、`makeVariablesDeclaration`、`makeAssignmentStatement`（对 `ObjectPattern` 自动包裹一层括号以避免 `{a} = b` 被解析为块语句）、`makeImportSpecifier`、`makeAwaitExpression`、`makeImportDeclaration` 等。SWC 类型由 `src/swc.d.ts` 通过 `export * from "@swc/core"` 统一对外暴露（资料来源：[src/utils/make-node.ts:30-110](), [src/swc.d.ts:1]()）。

## 4. 插件集成入口

`src/index.ts` 将上述模块串联：

- 以 `enforce: "post"` 注册，确保在用户其它插件之后再执行。
- 默认目标 `DEFAULT_VITE_TARGET` 硬编码为 `["es2020", "edge88", "firefox78", "chrome87", "safari14"]`，与 Vite 默认值保持一致——当用户未在 `vite.config.ts` 显式设置 `build.target` 时会被该默认值覆盖（[Issue #77](https://github.com/Menci/vite-plugin-top-level-await/issues/77)）。
- `buildRawTarget(code)` 调用 esbuild 把包裹了 `__tla` 的 ES2022 代码再次转译到目标平台；`src/esbuild.ts` 中的 `requireFrom` 借助 `module._resolveFilename` 从 Vite 安装路径解析 esbuild，避免把 esbuild 列为自身依赖，Bun 环境下因 `module.require` 不存在会失败（[Issue #68](https://github.com/Menci/vite-plugin-top-level-await/issues/68)）。
- 在 Worker 上下文且请求 IIFE 输出时，会再次调用 `rollup({ plugins: [virtual(...)] })` 将 ESM 包装为单文件 IIFE。

资料来源：[src/index.ts:1-95](), [src/esbuild.ts:1-15]()

## 已知限制

- 不存在 `include` / `exclude` 选项，插件会强制改写所有命中条件的 chunk，放大 bundle 体积（[Issue #73](https://github.com/Menci/vite-plugin-top-level-await/issues/73)）。
- Vite 7 的 `esbuildOptions` 弃用、Vite 8 兼容、Bun 兼容性均在跟踪（[#70](https://github.com/Menci/vite-plugin-top-level-await/issues/70), [#76](https://github.com/Menci/vite-plugin-top-level-await/issues/76)）。
- 在混合 CSS/TS 项目中 `importedBy` 可能读到 `undefined`，建议确认 chunk 图已正常收敛（[Issue #33](https://github.com/Menci/vite-plugin-top-level-await/issues/33)）。

## See Also

- [Configuration & Options](./Configuration-and-Options.md) — `Options` 接口与 `promiseExportName` 等字段。
- [Worker & IIFE Packaging](./Worker-and-IIFE-Packaging.md) — 浏览器扩展、Service Worker 场景。
- [Plugin Integration](./Plugin-Integration.md) — 在 `vite.config.ts` 中的接入方式。

---

<a id='page-3'></a>

## Configuration Options & Worker (IIFE/ES) Handling

### 相关页面

相关主题：[Plugin Overview & Build Pipeline Architecture](#page-1), [Bundle Analysis & AST Transformation](#page-2)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/options.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/options.ts)
- [src/index.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/index.ts)
- [src/esbuild.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/esbuild.ts)
- [src/swc.js](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/swc.js)
- [src/bundle-info.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/bundle-info.ts)
- [package.json](https://github.com/Menci/vite-plugin-top-level-await/blob/main/package.json)
</details>

# 配置选项与 Worker（IIFE / ES）处理机制

本页说明 `vite-plugin-top-level-await` 的 `Options` 配置项、默认编译目标回退、Worker 上下文中的 IIFE / ESM 分支判断，以及 SWC 与 esbuild 的运行时解析逻辑。这些点与社区中频繁出现的"覆盖 Vite 默认 target"（[issue #77](https://github.com/Menci/vite-plugin-top-level-await/issues/77)）、"Worker 不可用"（[issue #57](https://github.com/Menci/vite-plugin-top-level-await/issues/57)）、"Bun 不支持 module.require"（[issue #68](https://github.com/Menci/vite-plugin-top-level-await/issues/68)）等讨论高度相关。

## 一、`Options` 配置接口

插件通过 `topLevelAwait(options?: Options)` 接收用户配置，并在内部将用户值与 `DEFAULT_OPTIONS` 浅合并：构造函数中 `resolvedOptions` 同时包含 `...DEFAULT_OPTIONS` 与 `...(options || {})`，保证用户未提供的字段有合理默认（[src/index.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/index.ts)）。

`Options` 接口定义于 `src/options.ts`，并通过 `export type { Options } from "./options"` 重新导出（[src/index.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/index.ts)）。结合 `DEFAULT_OPTIONS` 与上下文可以看出，选项至少覆盖以下行为维度：

- **transform 触发条件**：控制对哪些模块执行 `__tla` 异步包装；
- **Promise 导出形态**：决定输出文件是否同步 `export let __tla`；
- **Worker 模式**：允许构建阶段把 Worker 也转换为单文件产物，从而在 Firefox 等仍不支持 Worker 内 TLA 的环境中兼容运行。

> 社区诉求：issue #73 请求新增 `include / exclude` 选项以限制仅对特定包应用转换，避免 bundle 膨胀。该特性尚未在 `src/options.ts` 中实现。

## 二、默认 Target 与回退策略

插件自身维护一份 Vite 兼容的默认 target：

```ts
const DEFAULT_VITE_TARGET: ViteTarget =
  ["es2020", "edge88", "firefox78", "chrome87", "safari14"];
```
([src/index.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/index.ts))

当用户在 `vite.config.ts` 中显式设置 `build.target` 时，该值通过 `configResolved(config)` 写入内部 `buildTarget`，并在 `buildRawTarget()` 中作为 esbuild 的转换目标使用：

```ts
await esbuild.transform(code, {
  minify,
  target: buildTarget as string | string[],
  format: "esm"
});
```
([src/index.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/index.ts))

如果用户没有显式设置 target，插件会**使用 `DEFAULT_VITE_TARGET`**，而不是 Vite 自身的默认值——这也是 issue #77 中反映的"插件覆盖 Vite 默认 targets"现象的根因。

## 三、Worker（IIFE / ES）分支处理

Worker 处理由两个内部标志位驱动：

```ts
let isWorker = false;
let isWorkerIifeRequested = false;
```
([src/index.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/index.ts))

`outputOptions(options)` 钩子根据当前 Rollup 输出格式与 Worker 标志决定处理路径：当 `isWorker && options.format === "iife"` 成立时，插件将采用不同的代码生成策略——因为 IIFE 不支持顶层 `await`，必须把模块包裹成 Promise 并通过 `__tla` 同步导出引用（参见 README 的"Note"部分示例代码）。Worker 之外的非 IIFE 路径则按 ESM 正常生成。

构建目标 `buildTarget` 与 `minify` 在 `configResolved` 阶段锁定，随后在 `buildRawTarget()` 中复用，确保 Worker 与主 bundle 使用相同的编译目标。

## 四、运行时依赖：esbuild 与 SWC

### esbuild：通过 Vite 解析

`src/esbuild.ts` 使用 Node 的 `Module._resolveFilename` 从 Vite 自身的安装位置加载 `esbuild`，避免重复安装：

```ts
const contextModulePath = Module._resolveFilename(contextModuleName, self);
const virtualModule = new Module(contextModulePath, module);
virtualModule.filename = contextModulePath;
virtualModule.paths = Module._nodeModulePaths(path.dirname(contextModulePath));
return virtualModule.require(wantedModuleName);
```
([src/esbuild.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/esbuild.ts))

该实现依赖 Node 的 `module.require`，因此在 Bun 运行时会出现 `virtualModule.require is not a function`（issue #68）。

### SWC：原生优先 + WASM 回退

`src/swc.js` 通过环境变量控制加载策略：

```js
if (process.env.VITE_TLA_FORCE_WASM === "true") throw new Error("Force using @swc/wasm");
SWC = require("@swc/core");
} catch (e) {
  if (process.env.VITE_TLA_FORCE_NATIVE === "true") throw e;
  SWC = require("@swc/wasm");
}
```
([src/swc.js](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/swc.js))

## 五、配置决策流程图

```mermaid
flowchart TD
  A[调用 topLevelAwait options] --> B[合并 DEFAULT_OPTIONS]
  B --> C[configResolved 读取 buildTarget]
  C --> D{用户设置 build.target?}
  D -- 是 --> E[使用用户 target]
  D -- 否 --> F[使用 DEFAULT_VITE_TARGET]
  E --> G[输出阶段 outputOptions]
  F --> G
  G --> H{isWorker && format === 'iife'?}
  H -- 是 --> I[Worker IIFE 包装路径]
  H -- 否 --> J[普通 ESM 路径]
  I --> K[buildRawTarget esbuild 转换]
  J --> K
  K --> L[输出 generateBundle]
```

## 六、常见兼容性问题与对策

| 问题 | 触发条件 | 来源 / 应对 |
|------|---------|------------|
| 默认 target 被覆盖 | 用户未设置 `build.target` | 插件使用 `DEFAULT_VITE_TARGET` ([src/index.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/index.ts))，issue #77 |
| Vite 7 `esbuildOptions` 已废弃 | 使用旧字段 | 插件改用 Vite 自带 esbuild ([src/esbuild.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/esbuild.ts))，issue #70 |
| Bun 启动报错 | Bun 不支持 `module.require` | 用 Node 或强制 `VITE_TLA_FORCE_NATIVE`，issue #68 |
| Worker 不能转换 TLA | Worker 使用 IIFE 格式 | 通过 `outputOptions` 分支处理 ([src/index.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/index.ts))，issue #57 |

`peerDependencies` 仅声明 `vite: ">=2.8"`，但当前 `devDependencies` 已升至 `vite ^7.0.5`，而 issue #76 反映 Vite 8 下出现 `Cannot find module 'rollup'`——使用最新 Vite 时需要确认插件的 `rollup` 解析链是否已被新版本替代。

## See Also

- 插件主页：[README.md](https://github.com/Menci/vite-plugin-top-level-await/blob/main/README.md)
- Issue #77：[Plugin overwrite Vite's default targets](https://github.com/Menci/vite-plugin-top-level-await/issues/77)
- Issue #68：[Bun doesn't support module.require](https://github.com/Menci/vite-plugin-top-level-await/issues/68)
- Issue #57：[How to use in vite dev mode with chrome extension service-worker](https://github.com/Menci/vite-plugin-top-level-await/issues/57)
- Issue #76：[Support vite 8](https://github.com/Menci/vite-plugin-top-level-await/issues/76)

---

<a id='page-4'></a>

## Compatibility, Known Issues & Failure Modes

### 相关页面

相关主题：[Bundle Analysis & AST Transformation](#page-2), [Configuration Options & Worker (IIFE/ES) Handling](#page-3)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/index.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/index.ts)
- [src/transform.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/transform.ts)
- [src/bundle-info.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/bundle-info.ts)
- [src/options.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/options.ts)
- [src/swc.js](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/swc.js)
- [src/esbuild.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/esbuild.ts)
- [src/utils/make-node.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/utils/make-node.ts)
- [package.json](https://github.com/Menci/vite-plugin-top-level-await/blob/main/package.json)
</details>

# 兼容性、已知问题与故障模式

## 概述

`vite-plugin-top-level-await` 通过 Rollup 子编译 + esbuild 转换 + SWC AST 重写三阶段流水线，把代码包裹在 `Promise.all([...]).then(async () => { ... })` 中以模拟顶层 `await` 语义。由于该流水线深度介入 Vite 的 `outputOptions`、`generateBundle` 与 `writeBundle` 钩子，并依赖 Vite 内部传递的 `esbuild`、`rollup` 实例，因此兼容性问题集中在 Vite 版本边界、宿主运行时以及被改写后不再等价的 JavaScript 语义上。本页按"版本兼容 → 语义故障 → 构建管线故障 → 运行环境故障"四个维度梳理已知问题，每一项均可在源码中找到根因或触发点。

## Vite 版本兼容性矩阵

插件在 `package.json` 中将 `vite` 声明为 `">=2.8"` 的 peer 依赖，并使用 `^7.0.5` 作为 devDependency。资料来源：[package.json]()。

| Vite 版本 | 状态 | 关键问题 | 资料来源 |
|-----------|------|----------|----------|
| 2.8 – 5.x  | 可用 | 主流稳定组合 | [package.json]() |
| 6.x       | 兼容性回归（[#61](https://github.com/Menci/vite-plugin-top-level-await/issues/61)、[#66](https://github.com/Menci/vite-plugin-top-level-await/issues/66)） | 6.2.0 构建产物空白 | [src/index.ts]() |
| 7.x       | `optimizeDeps.esbuildOptions` 弃用警告（[#70](https://github.com/Menci/vite-plugin-top-level-await/issues/70)） | Vite 改用 Rolldown | [src/esbuild.ts]() |
| 8.x       | `Cannot find module 'rollup'`（[#76](https://github.com/Menci/vite-plugin-top-level-await/issues/76)） | Vite 8 移除或重命名 `rollup` 包 | [package.json]() |

**Vite 默认目标被覆盖**：插件在 `src/index.ts` 中硬编码了 `DEFAULT_VITE_TARGET = ["es2020", "edge88", "firefox78", "chrome87", "safari14"]`，并在用户未配置 `build.target` 时直接覆盖 Vite 自身默认值。资料来源：[src/index.ts:16-18]() 与 [src/index.ts:60-65]()（[#77](https://github.com/Menci/vite-plugin-top-level-await/issues/77)）。

## 语义层面的故障模式

### 函数提升（Hoisting）被破坏

`src/transform.ts` 把模块体改写为 `let __tla = (async () => { ... })()` 形式，原本由 `function` 声明带来的提升语义消失。例如：

```ts
foo.bar = 42;
export function foo() {}
```

会被改写为 `let foo; let __tla = (async () => { foo.bar = 42; foo = function ... })();`，导致 `foo.bar = 42` 在 `foo` 赋值之前执行。资料来源：[src/transform.ts]()（[#71](https://github.com/Menci/vite-plugin-top-level-await/issues/71)）。

### 初始化顺序错乱

`src/bundle-info.ts` 通过 BFS 沿反向依赖图传播 `transformNeeded` 标记；任何被改写的模块都会向上游强制要求 `await __tla`，从而改变值可见的时机。若某个 chunk 漏报 `__tla`（例如 Remix 中异步 import 未被识别 [#72](https://github.com/Menci/vite-plugin-top-level-await/issues/72)），下游读取就会得到 `undefined`，表现为 `Cannot read properties of undefined (reading 'GREEN')`。资料来源：[src/bundle-info.ts:60-80]()（[#74](https://github.com/Menci/vite-plugin-top-level-await/issues/74)）。

### `importedBy` 字段缺失

`src/bundle-info.ts` 中 `bundleInfo[moduleName]` 可能在跨 chunk 解析时为 `undefined`，从而触发 `Cannot read properties of undefined (reading 'importedBy')`（[#33](https://github.com/Menci/vite-plugin-top-level-await/issues/33)）。资料来源：[src/bundle-info.ts:48-56]()。

## 构建管线层面的故障模式

### 文件哈希与内容不同步

`src/index.ts` 在 `generateBundle` 钩子中改写 chunk 源码，但 Vite 此前已基于原始内容计算哈希并写入 `OutputChunk`。缓存层因此复用旧哈希指向新内容。资料来源：[src/index.ts]()（[#44](https://github.com/Menci/vite-plugin-top-level-await/issues/44)）。

### Source Map 丢失

由于插件 `enforce: "post"`、并在 `writeBundle` 之前插入了一次独立的 esbuild → SWC 转换，原始 chunk 的 `//# sourceMappingURL=` 注释可能在新代码中错位或丢失。资料来源：[src/index.ts]()`（[#34](https://github.com/Menci/vite-plugin-top-level-await/issues/34)）。

### SWC NAPI 转换失败

`src/swc.js` 默认加载原生 `@swc/core`，失败时回落到 `@swc/wasm`。当 NAPI 层遇到无法转换的字符串（Rust `String` → napi string），会抛出 `[vite-plugin-top-level-await] Failed to convert rust String into napi string`（[#58](https://github.com/Menci/vite-plugin-top-level-await/issues/58)）。可通过设置 `VITE_TLA_FORCE_WASM=true` 强制使用 wasm 规避。资料来源：[src/swc.js]()。

## 运行环境与宿主兼容

### Bun 不支持 `module.require`

`src/esbuild.ts` 通过 Node 内部 `Module._resolveFilename` 配合 `virtualModule.require()` 读取 Vite 自带的 `esbuild`。Bun 运行时未实现 `Module._require`，因此报 `TypeError: virtualModule.require is not a function`（[#68](https://github.com/Menci/vite-plugin-top-level-await/issues/68)）。资料来源：[src/esbuild.ts:6-12]()。

### Service Worker / Chrome 扩展

`src/index.ts` 暴露 `outputOptions` 钩子，会根据 `isWorker` 标志调整 `format`，但并未对 Chrome Extension Manifest V3 的 Service Worker 场景提供专门配置（[#57](https://github.com/Menci/vite-plugin-top-level-await/issues/57)）。资料来源：[src/index.ts]()。

### 全量改写带来的体积膨胀

由于依赖图任意节点上的 TLA 都会沿 `importedBy` 反向传播，目前没有 `include/exclude` 选项做选择性转换，导致整包体积上升（[#73](https://github.com/Menci/vite-plugin-top-level-await/issues/73)）。资料来源：[src/options.ts]()、`[src/bundle-info.ts]()`。

```mermaid
flowchart LR
    A[用户源码含 TLA / 动态 import] --> B{parseBundleInfo}
    B --> C[沿 importedBy 反向传播]
    C --> D{chunk 是否被改写}
    D -->|是| E[插入 __tla Promise.all]
    D -->|否| F[原样输出]
    E --> G[generateBundle 钩子]
    G --> H[esbuild 转 es2020]
    H --> I[哈希与 source map 错位风险]
    I --> J[最终产物]
```

## See Also

- [README.md](https://github.com/Menci/vite-plugin-top-level-await/blob/main/README.md) — 插件基础使用与配置项
- [src/options.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/options.ts) — `promiseExportName` 等可调参数
- [src/bundle-info.ts](https://github.com/Menci/vite-plugin-top-level-await/blob/main/src/bundle-info.ts) — 反向依赖传播算法

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Doramagic 踩坑日志

项目：Menci/vite-plugin-top-level-await

摘要：发现 18 个潜在踩坑项，其中 5 个为 high/blocking；最高优先级：安装坑 - 来源证据：Breaks with Nuxt's `renderer.mjs` that generated bypassing Vite。

## 1. 安装坑 · 来源证据：Breaks with Nuxt's `renderer.mjs` that generated bypassing Vite

- 严重度：high
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Breaks with Nuxt's `renderer.mjs` that generated bypassing Vite
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/Menci/vite-plugin-top-level-await/issues/64 | 来源讨论提到 npm 相关条件，需在安装/试用前复核。

## 2. 安装坑 · 来源证据：Bun doesn't support module.require

- 严重度：high
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Bun doesn't support module.require
- 对用户的影响：可能阻塞安装或首次运行。
- 证据：community_evidence:github | https://github.com/Menci/vite-plugin-top-level-await/issues/68 | 来源讨论提到 node 相关条件，需在安装/试用前复核。

## 3. 安装坑 · 来源证据：Code broken when used with Remix

- 严重度：high
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Code broken when used with Remix
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/Menci/vite-plugin-top-level-await/issues/72 | 来源讨论提到 npm 相关条件，需在安装/试用前复核。

## 4. 安装坑 · 来源证据：Support vite 8

- 严重度：high
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Support vite 8
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/Menci/vite-plugin-top-level-await/issues/76 | 来源讨论提到 node 相关条件，需在安装/试用前复核。

## 5. 运行坑 · 来源证据：Code relying on function hoisting is broken

- 严重度：high
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个运行相关的待验证问题：Code relying on function hoisting is broken
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/Menci/vite-plugin-top-level-await/issues/71 | 来源类型 github_issue 暴露的待验证使用条件。

## 6. 安装坑 · 来源证据：How to use in vite dev mode with chrome extension service-worker

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：How to use in vite dev mode with chrome extension service-worker
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/Menci/vite-plugin-top-level-await/issues/57 | 来源讨论提到 npm 相关条件，需在安装/试用前复核。

## 7. 安装坑 · 来源证据：Plugin overwrite Vite's default targets

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Plugin overwrite Vite's default targets
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/Menci/vite-plugin-top-level-await/issues/77 | 来源讨论提到 node 相关条件，需在安装/试用前复核。

## 8. 安装坑 · 来源证据：Skipped array elements cause a crash

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Skipped array elements cause a crash
- 对用户的影响：可能阻塞安装或首次运行。
- 证据：community_evidence:github | https://github.com/Menci/vite-plugin-top-level-await/issues/65 | 来源讨论提到 node 相关条件，需在安装/试用前复核。

## 9. 安装坑 · 来源证据：Vite 7 - esbuildOptions deprecated

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Vite 7 - esbuildOptions deprecated
- 对用户的影响：可能影响升级、迁移或版本选择。
- 证据：community_evidence:github | https://github.com/Menci/vite-plugin-top-level-await/issues/70 | 来源类型 github_issue 暴露的待验证使用条件。

## 10. 安装坑 · 来源证据：[vite-plugin-top-level-await] Failed to convert rust String into napi string

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：[vite-plugin-top-level-await] Failed to convert rust String into napi string
- 对用户的影响：可能阻塞安装或首次运行。
- 证据：community_evidence:github | https://github.com/Menci/vite-plugin-top-level-await/issues/58 | 来源讨论提到 node 相关条件，需在安装/试用前复核。

## 11. 安装坑 · 来源证据：vite-plugin-top-level-await breaks initialization ordering (hoisting + deferred exports)

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：vite-plugin-top-level-await breaks initialization ordering (hoisting + deferred exports)
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/Menci/vite-plugin-top-level-await/issues/74 | 来源讨论提到 npm 相关条件，需在安装/试用前复核。

## 12. 能力坑 · 能力判断依赖假设

- 严重度：medium
- 证据强度：source_linked
- 发现：README/documentation is current enough for a first validation pass.
- 对用户的影响：假设不成立时，用户拿不到承诺的能力。
- 证据：capability.assumptions | github_repo:464408338 | https://github.com/Menci/vite-plugin-top-level-await | README/documentation is current enough for a first validation pass.

## 13. 维护坑 · 来源证据：The component cannot be displayed correctly.

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个维护/版本相关的待验证问题：The component cannot be displayed correctly.
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/Menci/vite-plugin-top-level-await/issues/69 | 来源类型 github_issue 暴露的待验证使用条件。

## 14. 维护坑 · 维护活跃度未知

- 严重度：medium
- 证据强度：source_linked
- 发现：未记录 last_activity_observed。
- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。
- 证据：evidence.maintainer_signals | github_repo:464408338 | https://github.com/Menci/vite-plugin-top-level-await | last_activity_observed missing

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 证据：downstream_validation.risk_items | github_repo:464408338 | https://github.com/Menci/vite-plugin-top-level-await | no_demo; severity=medium

## 16. 安全/权限坑 · 存在评分风险

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：风险会影响是否适合普通用户安装。
- 证据：risks.scoring_risks | github_repo:464408338 | https://github.com/Menci/vite-plugin-top-level-await | no_demo; severity=medium

## 17. 维护坑 · issue/PR 响应质量未知

- 严重度：low
- 证据强度：source_linked
- 发现：issue_or_pr_quality=unknown。
- 对用户的影响：用户无法判断遇到问题后是否有人维护。
- 证据：evidence.maintainer_signals | github_repo:464408338 | https://github.com/Menci/vite-plugin-top-level-await | issue_or_pr_quality=unknown

## 18. 维护坑 · 发布节奏不明确

- 严重度：low
- 证据强度：source_linked
- 发现：release_recency=unknown。
- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。
- 证据：evidence.maintainer_signals | github_repo:464408338 | https://github.com/Menci/vite-plugin-top-level-await | release_recency=unknown

<!-- canonical_name: Menci/vite-plugin-top-level-await; human_manual_source: deepwiki_human_wiki -->
