Repository navigation
Conversation
Collaborator
Author
|
Updated 4:05 AM PT - Oct 22nd, 2026
❌ @robobun, your commit b06bc9e has some failures in 🧪 To try this PR locally: bunx bun-pr 46223That installs a local version of the PR into your bun-46223 --bun |
Collaborator
Author
|
Status Reproduction on main (release build of
With this branch, steps 2 and 3 report The branch is rebased on main, which now has #46021 and #46001. The Notes of the description list what is open. |
`bun check <file>`, `bun --check` and `bun test --check` named the scripts of an HTML page by a join of each `src` text onto the folder of the page. A script that the bundler resolves (`./main` for main.ts, a folder, a tsconfig path) was not checked, and `./main.js` for main.ts was reported as not found. The check now asks the bundler's resolver, for the browser, with the tsconfig override of the run. A name that does not resolve is named as before. `bun build --check` passes the pages of its bundle, and only its graph names the scripts of those. Every resolver of a process reads one cache of directories, and an entry keeps what its first reader made of it. So a process that goes on after the check forgets what the check's resolvers put there (`DirectoryCacheScope`): the program reads those directories as it does without `--check`.
robobun
force-pushed
the
robobun/01ecf66e/check-page-scripts-resolve
branch
from
October 22, 2026 07:02
dd45cd8 to
b06bc9e
Compare
This was referenced Oct 23, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
bun check <file>,bun --checkandbun test --checkjoin a page'ssrctext onto its folder (imports_of_page,src/runtime/cli/check_command.rs:814)../mainformain.tsis not checked../main.jsis a falseTS6053.bun build --checkis right.Fix
--tsconfig-override). A name that does not resolve is named as before. For a bundle's page, only the graph names scripts (TypeChecked::pages).DirectoryCacheScope, on test --changed: forget what the module graph scan cached before the tests run #44835's map marks).test/cli/check/check.test.ts(46 new tests, 15 fail on main),entry-points.test.ts.Background
<script src>. The type checker gets an imported page's scripts from the hookscripts_of_page.package.json's main fields).both.tswhere the bundle holdsboth.tsx.Downsides
./mainis now checked. A page's script innode_modules, or one a build leaves external, is not.bun test --checkand--hot, three cache cases still differ from a run without--check(Notes, "The cache").Notes
A question for a maintainer. The check's resolver shares the directory cache of the process. See "The cache" below: the forgetting is exact when the check runs before the program's resolver exists. It leaves three cases open when something read the cache first. An owned cache for the check's resolver would close them. That is a larger change in
bun_resolver.Open after the self-review (7).
--watch, the scope ofbun --check page.html, a page that a plugin provides.Not taken: the type checker's own resolver for the scripts (the ask is the bundler's resolution).
Why this change. A maintainer asked for it in chat, with a script that runs one page through each command. No user reported it: the tracker has no issue about a page in
bun check.bun checkis in v1.4.3 (#44361), so each changed result below changes released behaviour.What each command does now. The commands that ask the resolver:
bun check <file>,bun --check <file>,bun --check page.html,bun test --check,bun build --no-bundle --check, abun build --checkwhose page is not in the bundle, and a check of the whole project when notsconfig.jsonis found (it then names every file below the working directory). Plainbun checkin a project with atsconfig.jsondoes not ask about pages and does not change../mainformain.ts,./appforapp/index.ts./main.jsformain.tsTS6053: File '<dir>/main.js' not found.main.tsis checked./bothwithboth.tsandboth.tsxboth.tsx, the order of the bundler@/aliasedwithpathsintsconfig.jsonor in--tsconfig-overridesrc/aliased.tsis checked#clientwithimportsinpackage.json, keyed onbrowserbrowserfile./server-only.tsthat thebrowserfield ofpackage.jsonmaps to another file, or tofalseserver-only.tsis checked./node_modules/dep/index.ts./client.scriptunder--loader .script:ts, through a page that a file importsbun --check page.html./missing.tsormissing.ts, no such fileTS6053TS6053./missing,./folder, a package that is not installed,app://x/main.jsdata:URL or a relative value that is longer than a path bufferpanic: range end index 4133 out of range for slice of length 4095. main since #46021: no panic./mainin a template that a file importswith { type: "text" }main.tsis checked: see the limitsbun build --check --target=bun server.ts: for a page of the bundle, the hook no longer names a second file beside the graph.onResolvemaps./generated.tstosrc/real.tsTS6053forgenerated.tssrc/real.tsis checked, noTS6053./virtual.tsunder a namespace, and a file of that name is on the disk--external ./main.ts, or a plugin answersexternal: true, and the file has a type errorTS2322, exit 1TS6053, exit 1The resolver.
bun_bundler::transpiler::resolver_with_optionsmakes the resolver thatTranspiler::initmakes, without the transpiler. It loads no environment and sets up no parser store, because the hook can run on a thread of the type checker. The set-up is the browser side ofbun build --target=bun: browser main fields and conditions, the tsconfig override of the run, no--conditions, nodevelopmentcondition.The cache. Every resolver of a process reads one cache of directories (
DirInfo::hash_map_instance(), and the listings ofRealFS). What an entry keeps depends on its first reader: the main fields of apackage.json, the real path of a link (not with--preserve-symlinks), the warnings (logged once), the listing, a directory that was not there. In every process that goes on after the check (Provided::ends_the_processis false:bun --check,bun test --check, a script,Bun.build), the first resolver of the check enters aDirectoryCacheScope. The scope is dropped when the check ends, once, and forgets every directory that was read since it was entered.BSSMapInner::markandforget_sincebelow it are the hunk of open #44835, which needs the same forbun test --changed. A first version forgot once per page: 800 imported pages then took 506 MB underbun --check. Now 40 MB, as on main.Eleven tests run a program with and without
--checkand compare the output:--main-fields,--preserve-symlinks,NODE_PRESERVE_SYMLINKS, apackage.jsonwarning, a package and a file that the program writes before it imports them, an auto-install range,bun test,bun run --sequentialand--parallelwithout atsconfig.json, and an import afterBun.build({ check: true }). With the drop of the scope made a no-op in a copy of the release binary, all eleven fail.Three cases still differ from a run without
--check, where something read the cache before the check (bun test --check,--hot,--watch). The check's resolver then writes into entries of listings that are older than its scope, and the scope cannot reach them.bun test --preserve-symlinks --checkwithout a path, when a test imports the module that a page names through a linked folder: the real path../DATAbesidedata.json:error: ENOENT reading ".../DATA.json"when the program imports./data.json.An owned cache for the check's resolver would close the class. The two maps are process-wide statics today.
Measured. Release builds of main
b1d4686174and of that commit plus this diff, on one machine.strace,perfandbloatyare not in the container. A ptrace syscall counter and aperf_event_opencounter of user instructions stand in.bun check main.tsandbun --check main.ts. Onlynewfstatatmoves, between 13 and 20 in both builds. Instructions: 29,169,145 and 29,510,836 at the median of 20 interleaved runs, inside the spread of 28.7M to 31.3M.openat, +18getdents64, +10close, +2read, forbun check server.ts(136 to 178) and forbun --check server.ts(211 to 245). Instructions ofbun check server.ts: 29,659,247 and 29,862,528, inside the spread.bun check, +24 forbun --check.bun --check40 MB in both builds.bun check33 MB and 35 MB.index.htmlis opened 1 time (main: 20), and the check makes 57 fewer file system calls (317 to 260).Bun.build({ check: true, target: "bun" }):index.htmlis opened 1 time per build (main: 2 for 1 importer, 11 for 10 importers).Bun.resolveSync("./x"): 7,237 and 7,239 instructions per call at the median of 30 interleaved runs. The diff adds no code on that path.bun check server.tsin a project withreferences, 10 runs, no report.bun --check server.tsthere, 10 runs: the report ofbun server.ts(678 bytes in 5 allocations), nothing more. A forgotten directory keeps its slot, as afterbust_dir_cache.size).bun_bundler::transpiler::resolver_with_options, the fieldTypeChecked::pages,Resolver::directory_cache_scopeandDirectoryCacheScope, and from test --changed: forget what the module graph scan cached before the tests run #44835BSSMapInner::mark,BSSMapInner::forget_since,BSSMapMark. No host function, no codegen entry.bun run rust:check-all x86_64-pc-windows-msvc aarch64-apple-darwin: 2 ok.Limits that stay.
.html(src/sema/driver/lib.rs). A page that a file imports by apathsalias, by#importsor by a workspace name is not followed. A page behind a link is read from the folder of the link. An.htmlfile that is imported as text is read as a page: for./mainin such a template, the check now reports the errors ofmain.ts, as it did before for./main.ts.bun build page.htmlwithout--productionand the dev server add thedevelopmentcondition. The check does not. A<script src>that needs a condition can name another file there.both.tsbeforeboth.tsx, nobrowserfield).<script src>by a bare name or an alias that does not resolve is skipped. A build saysCould not resolve.tsconfig.jsonnearest to the real file applies. If a checked file also imports it by the name of the link, it is checked under both names.--watch, and none for the scope ofbun --check page.html.Open pull requests on the same lines. #44835 has the map marks. #45060 rewrites the head of
pages_of. #45693 adds a field toTypeChecked. #46021 and #46001 are on main, and this branch is rebased on them: the path bounds of #46021 end the aborts that an earlier version of this diff had on asrcof 4,092 to 4,095 joined bytes and on a 4 KBtsconfig.jsonvalue.