Repository navigation
Conversation
|
Updated 8:34 AM PT - Oct 16th, 2026
✅ @robobun, your commit cfd71cc21274867055a98210c5fc7976bee696d2 passed in 🧪 To try this PR locally: bunx bun-pr 45502That installs a local version of the PR into your bun-45502 --bun |
|
Status: draft. One maintainer decision is open (see below). Reproduced on 1.4.3 and on main. The open decision: this changes a default. A bundle that is not next to its database ( Related: #38275 is an older proposal for the same defect. It conflicts with main. It also covers names from the loader map ( |
The sqlite loader does not copy the database. An import that got the loader from its .sqlite name became a module that holds the absolute path of the database on the build machine. The import now stays as written once its resolved loader is known, like the attribute form, and the build warns. The rule runs at the four sites that resolve an import record.
53b655f to
155abf5
Compare
Problem
bun build --target=bunbundlesimport db from "./db.sqlite"(notypeattribute) asimport.meta.require("/abs/path/on/build/machine/db.sqlite", { type: "sqlite" }).db. The bundle opens the build folder's database.resolve_import_records(src/bundler/bundle_v2.rs) keeps a sqlite import external only by its attribute, before resolution. A loader from the file name comes later, soget_ast(src/bundler/ParseTask.rs) printssource.path.text.Fix
.sqliteimport prints as written, and the build warns..sqlitename: the bundle runs like the source.test/bundler/bundler_bun.test.ts(10 of 19 new tests fail on main). More in Notes.Background
Downsides
src/todist/) now fails at run time. Before, it opened the build path. The same sites can warn only.export *).onResolve-declined record, +2,304 bytes of.text.Notes
The decision this PR needs
import db from "./db.sqlite"is printed as written and the build prints a located warning.with { type: "sqlite" }) and--external '*.sqlite'give the external output today.What changes
import,import { db },import * as,require(),import(),require.resolve()andexport { x } fromof a.sqlitefile (any case, also through#imports, a package subpath,Bun.build({ files }), or after anonResolveplugin declined): printed as written, in ESM, CommonJS,--bytecodeand--compileoutput."./db.sqlite" is not bundled: the program opens it at run time, relative to the bundlewith the noteadd with { type: "sqlite" } to this import to state that, or with { type: "sqlite", embed: "true" } to embed the database. For--compileit saysrelative to the working directory.Bun.build()puts it inlogsonly.require("./db.sqlite")returns{ __esModule, db, default }, as the runtime does. It returned theDatabase.import { db }works (it failed the build).Databaseat run time, as they do without the bundler.import { users }) fails at run time, not at build time.embed(the module key is the path only: bundler: key modules by (path, loader) so one file under two import attributes is two modules #41834, Carry import attributes through the parser, printer, bundler and runtime; add the bytes loader #40836).What does not change (still the absolute path, as on main)
--loader .db:sqlite, bunfig,Bun.build({ loader })). The runtime does not have the map, and the printer puts atypeonly on an import statement of ESM output.onResolveplugin returns a path for, or that anonLoadfilter matches. A nativeonBeforeParseplugin keeps today's output for every database (the check is coarse).export * froma database: a star re-export of an external in a module that is not the entry point hits bundler: name the namespace of an external export * in a non-entry module #41220.module.exports = require("./db.sqlite")shim: the redirect would print the loader of the shim (bundler: no spuriouswith { type: ... }on external hoisted frommodule.exports = require(...)#35692).bun build --app, the dev server) and thebun test --changedscan. The prerender runs the bundle where it was built, and the scan needs the graph edge.To use the "sqlite" loader, set target to "bun".external, a plugin'sexternal: true, anothertypeattribute and a loader-map entry for.sqlitego first.Known limits of "printed as written"
#db, tsconfigpaths, a package) is resolved again at run time.__dirnameandimport.meta.dirof the source are still inlined as build paths.--compile --assetdoes not make the import find an embedded copy (bun build --compile: require() of an embedded JSON file asset evaluates it as JavaScript #44095).export { x } from "./db.sqlite" with { type: "sqlite" }still warns: the parser drops the attribute of a re-export.Measurements (release builds of main at 8ba82c3, without and with this change)
cmp $0xf,jenot taken), 0 calls added on that path (objdump). 1,801 hits on a 301-module fixture (gdb counter).onResolveplugin declined: +12 instructions, 0 calls (objdump).Path::loadercalls 29 -> 29 on an 84-record plugin fixture (gdb counter)..sqliteimport adds 2 on both..text+2,304 bytes,.rodata+0 (size -A). File size unchanged.JSBundlerPlugin__exports 15 -> 15. 0 host functions. No codegen change.get_astis unchanged.ResolveImportRecordCtx(a slice and au32). Per build: 1boolonBundleV2.module.exports = require("some-ext")shim, a 301-module fixture,scripts/build.ts, a test fixture) in esm, cjs and--splitting, for target bun and browser. The same 8 of 42 builds fail on both./proc/<pid>/iounder gdb). Opens ofdb.sqlite1 -> 0 (gdb catch syscall).Cannot find module './db.sqlite'. It printed the build row before. A--compilebinary started from the database's directory still works.strace,perf,valgrindandbloatyare not installed here. The counts come from gdb, objdump,sizeand getrusage.Self-review (48 concerns)
itBundledtests, tests for explicit configuration and forbun build --app.run_resolversites stay. Without them a build with a catch-allonResolveplugin keeps the absolute path.Credit
onLoadcheck come from bundler: keep sqlite imports external when the loader comes from the extension or loader map #38275. That PR also covers loader-map names and prints thetypeon an externalrequire()andimport(). The two are compared in bundler: keep sqlite imports external when the loader comes from the extension or loader map #38275 (comment).Suites run with the debug build
test/bundler/bundler_bun.test.tsandtest/cli/test/test-changed.test.ts(52 pass). 10 of the 19 new bundler tests fail on main at 8ba82c3 and on 1.4.2. The other 9 are guards: they pin what stays bundled and what goes first.bundler_plugin,bundler_loader,bundler_barrel,bundler_cjs2esm,bundler_edgecase,esbuild/importstarandbundler_compile: 673 pass. 1 test inbundler_compile(does not run a synchronous full GC) hit its 5 s timeout under the local ASAN debug build. It has no database.bun build --appwith a server page that imports../db.sqlitewithout the attribute: exit 0 and the prerendered page has the row of the build, on main and on this branch. Run by hand: the bake production suite does not fit its 5 s default under the local debug build.no test proof · iteration 0 · platform-specific test(s) that do not run on this machine, deferring to CI, which covers all platforms: test/cli/test/test-changed.test.ts