Import attributes — macros, text, toml, file imports as first-class
Accept with scoped policy. Spec 00 promises Bun macros; this RFC redeems that promise.
Review verdict (2026-05-24)
Accept with scoped policy. Spec 00 promises Bun macros; this RFC redeems that promise.
Macro policy (decided 2026-05-24)
Required to be macros (compiler-enforced "no runtime read" guarantee):
- Route table (
scanRoutesoutput) — closes the spec 04 promise that production bundles contain noBun.Globcall. env.publicvalues inlined into the client bundle.- Client manifest (island name → chunk URL).
- AGENTS.md content hash for cache busting (the file itself stays generated at build time, but the hash gets inlined for the dev banner).
Optional (may be import-attribute or runtime read):
- SQL files (
with { type: "text" }preferred). - Email/HTML templates (
with { type: "text" }preferred). - TOML config blobs (
with { type: "toml" }preferred when the file is known at build time). - SQLite seed databases (
with { type: "sqlite" }).
Rule of thumb: anything the framework builds for you must be a macro; anything your app reads may be either.
--hot interaction
Macros re-evaluate on bun --hot when their input files change. This is verified by the smoke test in [[rfc-bun-hot-reload]]. If a macro depends on a file Bun's dep tracker doesn't follow, the developer adds the dep explicitly via import "./watched-file" with { type: "file" } in the macro source.
Testing
Macros are unit-tested by importing them in a build-time test harness (bun test with a fixture that runs Bun.build and asserts on the emitted output). [[14-testing]] gets a new section.
Summary
Bun supports five import attribute types: macro (build-time function evaluation), text (string literal), toml (parsed object), json (parsed object), file (path/URL after bundling), and sqlite (embedded DB). 00-overview already promises "Bun macros" but no Patties spec actually says where macros are allowed, what counts as a macro, or how the other import attributes fit. This RFC closes that gap.
Motivation
- Macros let route metadata, manifest generation, and AGENTS.md scaffolding (11) run at build time instead of boot. Concrete win: turn
scanRoutes()into a macro so the route table literally inlines, satisfying 08-config's "noBun.Globcalls in production bundle" guarantee with compiler-enforced certainty. with { type: "text" }for SQL files (09-plugins) and email templates beatsBun.file().text()because it's tree-shakeable.with { type: "toml" }forpatties.tomlstyle config beats parsing at runtime.
Proposal
- 04-build: document the supported import attribute types and require Patties' macros to be pure (no I/O at module top level besides FS reads in the macro file itself).
- 09-plugins: macros may be authored by plugin packages; plugin docs must list which macros they export.
- 13-conventions: ban runtime JSON/TOML reads when a static import attribute can replace them.
- 11-agents-md-generator: convert the generator's filesystem scan into a macro so AGENTS.md is regenerated on every build, not via a separate CLI step.
Sample:
import routes from "./_scanRoutes.ts" with { type: "macro" };
import schema from "./schema.sql" with { type: "text" };
import config from "./patties.toml" with { type: "toml" };
Trade-offs
- Macros run in a sandboxed build-time context — they cannot import runtime-only code. Easy to footgun.
- Errors in macros surface at build time with stack traces inside the bundler — harder to debug than a runtime throw.
Open questions
- Which existing spec touchpoints should require a macro vs. permit either? (Likely: route table = required, manifest = required, AGENTS.md = optional CLI for non-bundled flows.)
- Do macros run during
Bun.buildonly, or also underbun --hot? Test. - How do tests stub a macro's output (14-testing)?