build: ESM only — remove CJS artifacts, require branches and types-cjs - #3318
Merged
Conversation
…-cjs mirror Node >= 22.12 loads ESM through require() natively, and Node 20 is EOL, so the second module graph bought nothing but a build matrix a third larger, a dual-types pipeline (sync-dual-types.mjs), and three flat CJS builds in signals whose tiers had to be kept in step with the ESM ones by hand. Runtime packages (signals, solid-js, web + subpaths, universal, h, html) now declare engines.node >= 22.12 and publish ESM only. Exports maps lose their import/require split — the import branch's entries are spliced in at its position, so condition order (and therefore which types a node16 TS consumer sees) is unchanged. `main` points at the ESM server entry. Guards replacing the CJS coverage: - signals dist test require()s each tier's core + engine in a child Node and checks it is the same instance import yields (vitest's module runner would give import its own copy, so the probe spawns real Node), and scans every shipped module for a top-level await — the one thing that breaks require(esm). - web's export-conditions test walks the require hops web → solid-js → signals per tier onto the ESM files, and loads the chain through a real CJS require. - test-integration's import smoke test now also require()s every public specifier (fails on ERR_REQUIRE_ASYNC_MODULE); the packaged-types fixture moves from module: Node16 to NodeNext, the setting under which TS type-checks require() of ESM. Build-time tooling (@solidjs/babel-plugin, @solidjs/compiler's napi loader) is unchanged. Co-authored-by: Claude via Cursor <noreply@cursor.com> Co-authored-by: Cursor <cursoragent@cursor.com>
🦋 Changeset detectedLatest commit: a39415c The changes in this PR will be included in the next version bump. This PR includes changesets to release 11 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Coverage Report for CI Build 34330546237Coverage remained the same at 71.851%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
Member
Author
|
ryansolid
added a commit
that referenced
this pull request
Sep 9, 2026
Bump seroval and seroval-plugins from ~1.5.4 to ~1.6.7 (still minor-locked) in the root, solid-js and @solidjs/web. Seroval 1.6 ships bundled declarations with no extensionless relative imports, so the TS2834 gap in the NodeNext-CJS packaged-types fixture is closed: it now type-checks all 13 public @solidjs/web specifiers, including server-functions/*, serialization/* and frames/*. The 34 regenerated hydration harness artifacts reflect seroval 1.6's inline helper text only (tab indentation; the async-iterator helper rewritten with method shorthand and braceless single-statement bodies) — same logic, and the parity/truncated-stream specs replay them green. @rollup/plugin-commonjs was referenced by no rollup config after #3318. Verified: full build + every suite, type tests, test-integration (import + require(esm) walk, packaged types), compiler runtime harness; examples/rendering streaming mode smoke-tested in prod and dev builds (true streaming, hydration, client navigation, zero console errors). Co-authored-by: Cursor <cursoragent@cursor.com>
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.
Summary
All runtime packages publish ESM only and declare
engines.node >= 22.12. Every.cjsartifact, everyrequirebranch in the exports maps, thetypes-cjs/declaration mirrors and thesync-dual-types.mjspipeline are gone.Why now. Node 20 is EOL (2026-04); every supported Node
require()s ESM natively (unflagged in 22.12). Every other runtime Solid targets (Bun, Deno, workers, Tauri, SolidTV's bundled output, OpenTUI) is ESM-native and never read the CJS files. The dual build existed for Jest, which Solid 2 neither documents nor ships tooling for. Keeping it cost a build matrix a third larger and — as the observe-tier PR showed — a second set of per-tier artifacts (node.cjs/node.dev.cjs/node.observe.cjs) that had to be kept honest by hand.Resolution is unchanged. Each
{ import: X, require: Y }pair collapses to X's entries atimport's position, so condition order is preserved:browserstill precedesnode,developmentstill precedesobserve, and a node16/nodenext TS consumer still finds the server types under thenodekey before the top-level client ones. A CJS host resolves the same files through the same conditions.What replaces the CJS coverage
packages/signals/tests/dist-artifacts.test.ts(renamed fromdist-cjs-artifacts): for each tier, spawns a real Node thatrequire()s the core and engine entries and checks they are the same instanceimport()yields (vitest's module runner would handimportits own copy, so the probe cannot run in-process). Also scans every shipped module for a top-levelawait— the one thing that makesrequire(esm)throw.packages/web/test/server/exports-server-conditions.spec.tsx: therequirewalk@solidjs/web → solid-js → @solidjs/signalslands on the same ESM file per tier (prod / development / observe), and the chain actually loads through a CJSrequirewithDEVdefined in dev and undefined in prod.packages/test-integration/test-imports.mjs: every public specifier (now including/attribution,/serialization,/frames*,/rich-args) is loaded through bothimport()andrequire();ERR_REQUIRE_ASYNC_MODULEfails the run.packages/test-integration/fixtures/packaged-types/nodenext-cjs(wasnode16-cjs): the packed-types check for a CommonJS TS project moves tomodule: NodeNext, the setting under which TS type-checksrequire()of ESM. Passes against the packed tarballs.Consumer impact
require("solid-js")keeps working.module: "NodeNext"(TS 5.8+);Node16reports TS1479..cjspaths have nothing to map to.Out of scope
@solidjs/babel-pluginand@solidjs/compiler's napi loader are build-time tooling loaded by Babel/Node tooling, not runtime artifacts; unchanged.Size budget unchanged (ESM artifacts are byte-identical). Full
pnpm test,test:integration, andscripts/sizepass.