Serve @cardstack/base modules from the host bundle - #6087
Conversation
The virtual network's shimAsyncModule resolves the module through a lazy import(), so Vite emits it as its own chunk and a loader import of `@cardstack/base/date/day` is answered from the bundle instead of a fetch of realm-server-transpiled source. The host test helper imports DayField statically for the same reason. Base modules import host tools as `@cardstack/boxel-host/tools/*`, which the virtual network shims at runtime; the Vite alias gives the bundler the same mapping so a bundled base module resolves them too. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Same shape as date/day: a lazy shimAsyncModule entry and a static import in the host test helper. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5d86c7e5b1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| virtualNetwork.shimAsyncModule({ | ||
| id: '@cardstack/base/date/day', | ||
| resolve: () => import('@cardstack/base/date/day'), |
There was a problem hiding this comment.
Register base shims before the base-realm import map
In NetworkService.configureVirtualNetwork, the @cardstack/base/ realm mapping is installed before shimExternals, so registering either of these shims resolves its ID to the real base-realm URL. PackageShimHandler.handle only considers requests under PACKAGES_FAKE_ORIGIN, meaning loader imports of these IDs bypass the resolver and continue fetching the realm-server-transpiled modules; the new chunks therefore provide no offline or network-independent fallback. Register these shims before that realm import map or update the handler to serve mapped realm URLs.
Useful? React with 👍 / 👎.
| export { default as DayField } from '@cardstack/base/date/day'; | ||
| export { default as MonthField } from '@cardstack/base/date/month'; |
There was a problem hiding this comment.
Keep host test base imports behind the loader
When the date-time tests request DayField or MonthField, these static re-exports are evaluated directly by the host build rather than via loader.import, so the tests no longer exercise either newly added virtual-network shim and can pass even when those shims fall through to the realm server. This is also a host-side static value import from the base realm, which the repository explicitly requires to remain loader-mediated.
AGENTS.md reference: AGENTS.md:L235-L237
Useful? React with 👍 / 👎.
Same shape as date/day: a lazy shimAsyncModule entry and a static import in the host test helper. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Same shape as date/day: a lazy shimAsyncModule entry and a static import in the host test helper. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Same shape as date/day: a lazy shimAsyncModule entry and a static import in the host test helper. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Same shape as date/day: a lazy shimAsyncModule entry and a static import in the host test helper. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Same shape as date/day: a lazy shimAsyncModule entry and a static import in the host test helper. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Status
Work in progress, not ready for review. The PR is complete when every
@cardstack/basemodule is served from the host bundle; the checklist below tracks progress. One commit per converted module, so the pattern is visible in the diff.Goal
Importing
@cardstack/base/*in the host resolves to code the host build already carries, instead of a per-module fetch of realm-server-transpiled source. Base does not change between deploys, so each of those fetches is a round trip for bytes the build could have included.How
shimExternals(app/lib/externals.ts) registers each base module withvirtualNetwork.shimAsyncModule({ id, resolve: () => import(...) }), the mechanism that already serves runtime-common and boxel-ui to card code. The lazyimport()lets Vite emit each module as its own chunk, so a loader import of that identifier is answered from the bundle.@cardstack/boxel-host/tools/*and@cardstack/boxel-host/commands/*toapp/tools/, mirroring the virtual network's runtime shim, so a bundled base module that imports host tools resolves them at build time.tests/helpers/base-realm.ts) imports each converted module statically instead of throughloader.import, so the suite exercises the bundled copy.Progress
Served from the bundle:
date/day,date/month,date/month-day,date/month-year,date/year,date/week,date/quarterStill loaded through the loader by the test helper (next candidates):
time,time/time-range,time/duration,time/relative-timestring,number,boolean,big-integer,email,ethereum-address,phone-number,text-area,markdown,rich-markdown,color,code-ref,realm,enum,searchable,base64-imagedate,datetime,datetime-stamp,date-range-fieldcards-grid,workspace,process-card,remix-card,system-card,skill,file-apicard-apiThen everything else under
packages/base, at which point the per-module entries collapse into one@cardstack/base/prefix shim with the same lazyimport().Shape during the transition
A bundled module's
../card-apiimport is bundled with it, while the rest of the host still loads card-api through the loader, so two copies of card-api exist until card-api itself is served from the bundle. TheIntegration | date-time fieldstests build a card through the loader's card-api with the bundled fields as field types, which is where a class-identity mismatch would surface first.🤖 Generated with Claude Code