Doramagic 项目包 · 项目说明书

vite-plugin-top-level-await 项目

将代码转换为兼容普通浏览器顶层 await 语法的 Vite 插件。

Plugin Overview & Build Pipeline Architecture

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

章节 相关页面

继续阅读本节完整说明和来源证据。

概述与设计目标

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

根据 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-awaitenforce: "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
  • buildTargetminify 缓存:插件把 Vite 的 build.targetbuild.minify 缓存到闭包变量,在子构建中复用。资料来源:src/index.ts:23-28

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

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:依赖图与传播逻辑所在地;导出 parseBundleAstsparseBundleInfo 两个核心函数。
  • src/transform.ts:对单个模块的 AST 进行 TLA 包装的关键改写逻辑;同时负责处理 import 重写、变量提升、函数/类声明转换等细节。
  • src/utils/make-node.ts:SWC AST 节点的工厂方法集合(makeIdentifiermakeStatementmakeAwaitExpression 等),让改写阶段可读性更高。
  • 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
  • 默认 target 覆盖:插件在未显式设置 build.target 时会写入自己的 DEFAULT_VITE_TARGET,可能覆盖用户 Vite 配置中的默认值。资料来源:src/index.ts:11-11issue #77
  • chunk hash 失效generateBundle 中的代码改写不会触发 Vite 的 hash 重算,导致浏览器/CDN 缓存命中陈旧资源。资料来源:issue #44
  • source map 丢失:子构建重新生成代码时未附加 sourceMappingURL,会破坏调试体验。资料来源:issue #34
  • Bun 运行时崩溃src/esbuild.ts 依赖 Node 内部 Module._resolveFilename,在 Bun 加载配置阶段会抛 virtualModule.require is not a function。资料来源:issue #68
  • 函数提升被破坏function 声明会被转换为函数表达式并赋给 let,从而失去 hoisting 行为,可能导致循环依赖代码出错。资料来源:src/transform.ts:34-44issue #71
  • 初始化顺序错乱:TLA 与 deferred export 在 __tlaPromise.all 中调度,依赖紧耦合的模块可能在 __tla 解析前就访问导出值。资料来源:issue #74

See Also

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

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

Bundle Analysis & AST Transformation

vite-plugin-top-level-await 的核心工作分为两个紧密耦合的阶段:包级依赖分析(Build-time Dependency Analysis)与 AST 改写(Source-level Transformation)。两者均在 Rollup 的 generateBundle 钩子中执行,借助 SWC 完成解析与打印,再借助 esbuild 把改写后的...

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 1.1 核心数据模型

继续阅读本节完整说明和来源证据。

章节 1.2 两遍扫描算法

继续阅读本节完整说明和来源证据。

章节 2.1 改写入口

继续阅读本节完整说明和来源证据。

概述

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 类型,包含四类字段:

字段类型含义
importedstring[]当前模块直接 import / export from 的相对模块名
importedBystring[]反向依赖(哪些模块引用了当前模块)
withTopLevelAwaitboolean是否包含顶层 await 表达式
transformNeededboolean是否需要被本插件改写

资料来源:src/bundle-info.ts:12-17

1.2 两遍扫描算法

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

  • Pass 1(正向):遍历每个 chunk 的 AST,识别 ImportDeclarationExportNamedDeclarationsource,解析得到相对模块名并写入 imported;同时为被引用方填充 importedBy。最后调用 findHighestPattern 判定是否存在 TopLevelAwaitDynamicImport 模式,进而决定 transformNeededwithTopLevelAwaitsrc/find.ts 提供模式识别)。
  • Pass 2(反向 BFS 传播):以所有 transformNeeded 模块为种子,对反向图传播。任何引用了被改写 chunk 的上游 chunk 都必须也参与改写——因为后者导出的值现在是在异步包装器内初始化的,导入方必须 await __tla 才能读到正确的值。
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
  • 不带 sourceExportNamedDeclarationexport { a as b })保留 specifier。
  • sourceExportNamedDeclarationexport { 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)。
  • 初始化顺序问题:依赖 export { GREEN } 在导入方立刻可读的项目(如 Remix、模块联邦)可能拿到 undefined,因为 import 取到的是已被包裹到异步块中的变量绑定(Issue #72, Issue #74)。
  • hash 不更新generateBundle 阶段替换 chunk 代码不会重算 hash,导致 CDN 缓存命中旧资源(Issue #44)。

3. AST 节点构造工具

src/utils/make-node.ts 集中了所有 SWC 节点的工厂函数:makeIdentifiermakeVariablesDeclarationmakeAssignmentStatement(对 ObjectPattern 自动包裹一层括号以避免 {a} = b 被解析为块语句)、makeImportSpecifiermakeAwaitExpressionmakeImportDeclaration 等。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)。
  • buildRawTarget(code) 调用 esbuild 把包裹了 __tla 的 ES2022 代码再次转译到目标平台;src/esbuild.ts 中的 requireFrom 借助 module._resolveFilename 从 Vite 安装路径解析 esbuild,避免把 esbuild 列为自身依赖,Bun 环境下因 module.require 不存在会失败(Issue #68)。
  • 在 Worker 上下文且请求 IIFE 输出时,会再次调用 rollup({ plugins: [virtual(...)] }) 将 ESM 包装为单文件 IIFE。

资料来源:src/index.ts:1-95, src/esbuild.ts:1-15

已知限制

  • 不存在 include / exclude 选项,插件会强制改写所有命中条件的 chunk,放大 bundle 体积(Issue #73)。
  • Vite 7 的 esbuildOptions 弃用、Vite 8 兼容、Bun 兼容性均在跟踪(#70, #76)。
  • 在混合 CSS/TS 项目中 importedBy 可能读到 undefined,建议确认 chunk 图已正常收敛(Issue #33)。

See Also

  • Configuration & Options — Options 接口与 promiseExportName 等字段。
  • Worker & IIFE Packaging — 浏览器扩展、Service Worker 场景。
  • Plugin Integration — 在 vite.config.ts 中的接入方式。

资料来源:src/bundle-info.ts:12-17

Configuration Options & Worker (IIFE/ES) Handling

本页说明 vite-plugin-top-level-await 的 Options 配置项、默认编译目标回退、Worker 上下文中的 IIFE / ESM 分支判断,以及 SWC 与 esbuild 的运行时解析逻辑。这些点与社区中频繁出现的"覆盖 Vite 默认 target"(issue 77)、"Worker 不可用"(issue 57)、"Bun 不支持 mod...

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 esbuild:通过 Vite 解析

继续阅读本节完整说明和来源证据。

章节 SWC:原生优先 + WASM 回退

继续阅读本节完整说明和来源证据。

配置选项与 Worker(IIFE / ES)处理机制

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

一、`Options` 配置接口

插件通过 topLevelAwait(options?: Options) 接收用户配置,并在内部将用户值与 DEFAULT_OPTIONS 浅合并:构造函数中 resolvedOptions 同时包含 ...DEFAULT_OPTIONS...(options || {}),保证用户未提供的字段有合理默认(src/index.ts)。

Options 接口定义于 src/options.ts,并通过 export type { Options } from "./options" 重新导出(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:

const DEFAULT_VITE_TARGET: ViteTarget =
  ["es2020", "edge88", "firefox78", "chrome87", "safari14"];

(src/index.ts)

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

await esbuild.transform(code, {
  minify,
  target: buildTarget as string | string[],
  format: "esm"
});

(src/index.ts)

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

三、Worker(IIFE / ES)分支处理

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

let isWorker = false;
let isWorkerIifeRequested = false;

(src/index.ts)

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

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

四、运行时依赖:esbuild 与 SWC

esbuild:通过 Vite 解析

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

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)

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

SWC:原生优先 + WASM 回退

src/swc.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)

五、配置决策流程图

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),issue #77
Vite 7 esbuildOptions 已废弃使用旧字段插件改用 Vite 自带 esbuild (src/esbuild.ts),issue #70
Bun 启动报错Bun 不支持 module.require用 Node 或强制 VITE_TLA_FORCE_NATIVE,issue #68
Worker 不能转换 TLAWorker 使用 IIFE 格式通过 outputOptions 分支处理 (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

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

Compatibility, Known Issues & Failure Modes

vite-plugin-top-level-await 通过 Rollup 子编译 + esbuild 转换 + SWC AST 重写三阶段流水线,把代码包裹在 Promise.all([...]).then(async () = { ... }) 中以模拟顶层 await 语义。由于该流水线深度介入 Vite 的 outputOptions、generateBundle ...

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 函数提升(Hoisting)被破坏

继续阅读本节完整说明和来源证据。

章节 初始化顺序错乱

继续阅读本节完整说明和来源证据。

章节 importedBy 字段缺失

继续阅读本节完整说明和来源证据。

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

概述

vite-plugin-top-level-await 通过 Rollup 子编译 + esbuild 转换 + SWC AST 重写三阶段流水线,把代码包裹在 Promise.all([...]).then(async () => { ... }) 中以模拟顶层 await 语义。由于该流水线深度介入 Vite 的 outputOptionsgenerateBundlewriteBundle 钩子,并依赖 Vite 内部传递的 esbuildrollup 实例,因此兼容性问题集中在 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#666.2.0 构建产物空白src/index.ts
7.xoptimizeDeps.esbuildOptions 弃用警告(#70Vite 改用 Rolldownsrc/esbuild.ts
8.xCannot find module 'rollup'#76Vite 8 移除或重命名 rolluppackage.json

Vite 默认目标被覆盖:插件在 src/index.ts 中硬编码了 DEFAULT_VITE_TARGET = ["es2020", "edge88", "firefox78", "chrome87", "safari14"],并在用户未配置 build.target 时直接覆盖 Vite 自身默认值。资料来源:src/index.ts:16-18src/index.ts:60-65#77)。

语义层面的故障模式

函数提升(Hoisting)被破坏

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

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

会被改写为 let foo; let __tla = (async () => { foo.bar = 42; foo = function ... })();,导致 foo.bar = 42foo 赋值之前执行。资料来源:src/transform.ts#71)。

初始化顺序错乱

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

`importedBy` 字段缺失

src/bundle-info.tsbundleInfo[moduleName] 可能在跨 chunk 解析时为 undefined,从而触发 Cannot read properties of undefined (reading 'importedBy')#33)。资料来源:src/bundle-info.ts:48-56

构建管线层面的故障模式

文件哈希与内容不同步

src/index.tsgenerateBundle 钩子中改写 chunk 源码,但 Vite 此前已基于原始内容计算哈希并写入 OutputChunk。缓存层因此复用旧哈希指向新内容。资料来源:src/index.ts#44)。

Source Map 丢失

由于插件 enforce: "post"、并在 writeBundle 之前插入了一次独立的 esbuild → SWC 转换,原始 chunk 的 //# sourceMappingURL= 注释可能在新代码中错位或丢失。资料来源:src/index.ts`(#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)。可通过设置 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)。资料来源:src/esbuild.ts:6-12

Service Worker / Chrome 扩展

src/index.ts 暴露 outputOptions 钩子,会根据 isWorker 标志调整 format,但并未对 Chrome Extension Manifest V3 的 Service Worker 场景提供专门配置(#57)。资料来源:src/index.ts

全量改写带来的体积膨胀

由于依赖图任意节点上的 TLA 都会沿 importedBy 反向传播,目前没有 include/exclude 选项做选择性转换,导致整包体积上升(#73)。资料来源:src/options.tssrc/bundle-info.ts

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

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

失败模式与踩坑日记

保留 Doramagic 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。

high 来源证据:Breaks with Nuxt's `renderer.mjs` that generated bypassing Vite

可能增加新用户试用和生产接入成本。

high 来源证据:Bun doesn't support module.require

可能阻塞安装或首次运行。

high 来源证据:Code broken when used with Remix

可能增加新用户试用和生产接入成本。

high 来源证据:Support vite 8

可能增加新用户试用和生产接入成本。

Pitfall Log / 踩坑日志

项目: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

来源:Doramagic 发现、验证与编译记录