From dfc12153030a1fee395e89b786288a2f29ae2d0e Mon Sep 17 00:00:00 2001 From: Vivek Date: Wed, 12 Aug 2026 18:38:54 +0530 Subject: [PATCH 1/5] fix: root the vendor specifier scan in the module graph The scan behind the vendor importmap walked the whole app directory and regex-scanned every file that survived a hardcoded list of name exclusions, with no reachability criterion at all. Two consequences, both measured on website/: scripts/generate-og.mjs imports playwright, which no page or component reaches and which jspm 401s on every cold analysis; and lib/samples.ts holds an import written inside a docs code sample, which the comment-stripping scanner could not tell from a real one, so drizzle-orm was resolved too. 21 of the 24 specifiers the pin path found in website were phantom. Root it at the browser-bound entry set instead, the same authorization gate the dev server uses to decide what it will serve at all, and read the specifiers from the graph's own blanked-mask scanner. A file nothing imports contributes nothing, so a build script, a tooling config, a test helper and an unreferenced module drop out by reachability rather than by name. The exclusion list is gone rather than extended: it was open-ended and had already gone stale in its own docblock. This also deletes the second, weaker vendor-specifier scanner. The importmap and the modulepreload hints now come from one implementation instead of two that disagreed, which is why website served a drizzle-orm importmap entry that got no matching preload hint. The pin and runtime paths stay deliberately asymmetric: the pin side applies no elision pruning, so it is a superset by construction, which is the relation prunePinToReachable needs to intersect a committed pin down to the runtime answer. Asserted directly now rather than left implicit. One gap found while wiring this up, fixed here: the graph dropped a dynamically-imported vendor entirely, so await import('dayjs') would have lost its importmap entry and failed to resolve when it ran. It gets its own edge class, since it belongs in the importmap but not in the preload set. Measured on the in-repo apps: website goes from 24 specifiers to none, so the install list is empty and the jspm round trip disappears rather than shrinking. examples/blog keeps dayjs on the pin side and drops it at runtime, the #170 property, unchanged. Closes #1399 --- .github/workflows/ci.yml | 8 + packages/server/AGENTS.md | 5 +- packages/server/index.d.ts | 2 +- packages/server/src/browser-entries.js | 64 +++ packages/server/src/dev.js | 78 +--- packages/server/src/module-graph.js | 119 +++++- packages/server/src/vendor.js | 183 ++++----- .../test/module-graph/bare-imports.test.js | 119 +++++- .../server/test/vendor/scan-parity.test.js | 106 +++++ packages/server/test/vendor/vendor.test.js | 385 +++++++----------- test/bun/vendor-scan.mjs | 110 +++++ test/bun/vendor-scan.test.mjs | 11 + 12 files changed, 763 insertions(+), 427 deletions(-) create mode 100644 packages/server/src/browser-entries.js create mode 100644 packages/server/test/vendor/scan-parity.test.js create mode 100644 test/bun/vendor-scan.mjs create mode 100644 test/bun/vendor-scan.test.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0de76d93b..4b672d17d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -295,6 +295,14 @@ jobs: # path under `npm test`. - name: webjs SQLite busy_timeout on Bun run: bun test/bun/sqlite-busy-timeout.mjs + # Vendor specifier scan on Bun (#1399): the importmap is now derived by + # walking the module graph from the browser-bound entries, so an app + # scaffolded with `--runtime bun` runs the whole analysis under Bun. A set + # that drifted between runtimes would serve a Bun author a different + # importmap from the same source. Also asserts the runtime set stays a + # subset of the pin set, the relation pinned/unpinned parity rests on. + - name: Vendor specifier scan on Bun + run: bun test/bun/vendor-scan.mjs # The Bun test MATRIX (#509): run the runtime-sensitive node:test suite # (core + server + cross-package test/) under Bun, file by file, classifying # each result. Documented Node-only files + Bun-test-runner-quirk files are diff --git a/packages/server/AGENTS.md b/packages/server/AGENTS.md index 7f423583c..36b8f7bcd 100644 --- a/packages/server/AGENTS.md +++ b/packages/server/AGENTS.md @@ -80,9 +80,10 @@ with metadata, Suspense, streaming) for HTML, or `api.js` / | `sitemap.js` | Sitemap helpers (#276). `sitemap(entries)` serializes an array of `{ url, lastModified?, changeFrequency?, priority? }` into spec-valid `` XML (XML-escaping each url, formatting `lastModified` as a W3C datetime, validating priority 0..1 + the changefreq enum, skipping a urlless entry); `sitemapIndex(sitemaps)` builds the `` for sharding a site past the 50k-URL limit. Both pure + dependency-free; the `app/sitemap.{js,ts}` default export returns the string, which `dev.js` serves as `application/xml`. Exported from `index.js` | | `stream.js` | Server-side stream-action builders (#248). `stream.append/prepend/before/after/replace/update/remove(target, content?)` compose the `` HTML (one `