Answer to the Core Questions
1. Execution order for circular ES modules
Bun’s bundler performs a static topological sort of the dependency graph. If two ES modules import each other, Bun will emit them in an order that satisfies the graph, but the execution order during runtime can differ from Node’s lazy‑evaluation semantics. In practice, this means that a module may receive partially‑initialized exports from its peer if the peer hasn’t finished executing yet. The bundler does not guarantee identical runtime order to Node, so logic that relies on side‑effects during module initialization should be refactored to avoid circular imports or moved into a dedicated “init” function that is called after the bundle loads.
2. Detecting & mitigating CommonJS import‑limit failures
Bun enforces a hard cap of 200 CommonJS require calls per file in the current stable release. When the cap is exceeded, bun build --bundle aborts with an error that lists the file and the import count. To mitigate:
- Run
bun build --bundle yourFile.js locally and capture the error message to identify offending files.
- Refactor those files to reduce the number of
require statements – e.g., bulk‑import a module that re‑exports many symbols, or replace require with import where possible.
- If a third‑party CommonJS package is the source of many imports, consider marking it as external:
bun build --bundle --external:your-cjs-package. This tells the bundler to leave the import unresolved so the runtime loader handles it.
- As a last resort, split the file into multiple modules that each stay below the limit, then import the split modules.
After each change, re‑run the build to verify that the error disappears.
3. Dynamic imports with variable expressions
Bun’s current implementation requires a literal string for import(). The error message "Dynamic import argument must be a literal" is emitted when a variable is used. There is no open feature flag that relaxes this rule, and the Bun maintainers have stated that the limitation is intentional to keep static analysis tractable. Therefore, this restriction is effectively permanent for now. Workarounds include:
- Using a mapping object:
const modules = { foo: () => import('./foo.js'), bar: () => import('./bar.js') }; and calling modules[name]().
- Dynamic
require inside a new Function that returns a Promise, but this defeats bundler benefits and is not recommended for production code.
Recommended Diagnostic Detail
To fine‑tune the import‑limit workaround, please confirm the exact Bun version you are using (e.g., bun --version). The 200‑import cap is current for 0.5.x and 1.0.x releases; future releases may adjust the threshold.