Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
c64f08c
chore: merge main for the RSC CSS forwarding fix
owjs3901 Oct 4, 2026
5fd383b
chore: merge the updated deterministic numbering stack
owjs3901 Oct 4, 2026
187261f
fix(plugin-utils): report config failures and inheritance cycles
owjs3901 Oct 4, 2026
a2dcd45
fix(plugin-utils): match literal packages and normalize project roots
owjs3901 Oct 4, 2026
0e5d730
fix(plugin-utils): resolve inherited aliases and complete source graphs
owjs3901 Oct 4, 2026
349f4ce
fix(plugin-utils): remap compiled MDX diagnostics through source maps
owjs3901 Oct 4, 2026
7f99ae8
feat(plugin-utils): export shared plugin integration helpers
owjs3901 Oct 4, 2026
c85701e
fix(extractor): parse compiled MDX with real source identities
owjs3901 Oct 4, 2026
13b033b
fix(wasm): skip source maps and surface located resolver failures
owjs3901 Oct 4, 2026
4ca51f9
fix(vite-plugin): align roots and compiled MDX without changing RSC f…
owjs3901 Oct 4, 2026
bdbdc91
fix(webpack-plugin): reuse rooted graphs and bundler conditions
owjs3901 Oct 4, 2026
f4674eb
fix(webpack-plugin): isolate loader resolution and map MDX errors
owjs3901 Oct 4, 2026
d2a0aab
fix(rsbuild-plugin): complete rooted setup and shared CSS splitting
owjs3901 Oct 4, 2026
2755f02
fix(bun-plugin): preserve source dependency edges and module loaders
owjs3901 Oct 4, 2026
951d858
fix(bun-plugin): compile project MDX before extraction
owjs3901 Oct 4, 2026
3e6d1bc
fix(bun-plugin): align runtime roots conditions and debug defaults
owjs3901 Oct 4, 2026
362476c
test(next-plugin): align shared regex and canonical config mocks
owjs3901 Oct 4, 2026
d2ee4cc
docs(plugins): explain compiled and consumer-extracted library contracts
owjs3901 Oct 4, 2026
f631df9
chore: record patch releases for plugin core fixes
owjs3901 Oct 4, 2026
e4bb458
fix(plugin-utils): opt in to compiled MDX graph discovery
owjs3901 Oct 4, 2026
c1cfdbb
fix(webpack-plugin): normalize loader entry resources before prewarm
owjs3901 Oct 4, 2026
e81d7f3
test(vite-plugin): isolate watched config diagnostics
owjs3901 Oct 4, 2026
fd269ce
chore: record plugin CI recovery patch releases
owjs3901 Oct 4, 2026
a16a469
fix(plugin-utils): number MDX only for compiler-owning callers
owjs3901 Oct 4, 2026
6615744
fix(vite-plugin): prepare complete library CSS before optimization
owjs3901 Oct 4, 2026
394a049
test(bun-plugin): cover internal setup and source callbacks completely
owjs3901 Oct 4, 2026
abaf1b5
docs(vite-plugin): describe complete aggregate CSS and located limits
owjs3901 Oct 4, 2026
d05fac1
feat(plugin-utils): prepare graph sources with shared selection alias…
owjs3901 Oct 4, 2026
9a4fef7
docs(plugin-utils): define prepared graph and resolver option contracts
owjs3901 Oct 4, 2026
e46ae77
feat(plugin-utils): prepare synchronous resolver modules and remap er…
owjs3901 Oct 4, 2026
059972c
docs(plugin-utils): explain prepared resolver mapping and importing-s…
owjs3901 Oct 4, 2026
9cc58a2
feat(plugin-utils): resolve ordered alias candidate arrays
owjs3901 Oct 4, 2026
21b1a12
docs(plugin-utils): specify ordered alias candidates and terminal errors
owjs3901 Oct 4, 2026
03d8e84
fix(plugin-utils): place alias integration in the committed resolver
owjs3901 Oct 4, 2026
e8abf15
fix(plugin-utils): make import edges parser independent
owjs3901 Oct 5, 2026
179fa6d
fix(wasm): preserve source types for compiled MDX modules
owjs3901 Oct 5, 2026
a6a094d
fix(plugins): guard definitely used untransformed MDX exports
owjs3901 Oct 5, 2026
28dc9a1
fix(wasm): preserve explicit ignored alias module semantics
owjs3901 Oct 6, 2026
93846b9
test(extractor): cover ignored object serialization and style paths
owjs3901 Oct 6, 2026
fce47fe
fix(plugins): preserve ordered native alias descriptor options
owjs3901 Oct 6, 2026
76a5918
fix(plugin-utils): resolve aliased directory package entries
owjs3901 Oct 6, 2026
c4e8c2e
docs(plugins): explain ignored aliases and guarded MDX boundaries
owjs3901 Oct 6, 2026
c07d6c4
feat(plugin-utils): expose deterministic raw import request evidence
owjs3901 Oct 6, 2026
2346328
fix(plugins): watch build-time module resolution inputs
owjs3901 Oct 6, 2026
25156db
fix(extractor): compile React development JSX runtime calls
owjs3901 Oct 6, 2026
b70c419
fix(plugin-utils): resolve packaged tsconfig extends with owned TypeS…
owjs3901 Oct 7, 2026
bdf0c63
fix(plugins): preserve build generations and reject mixed consumers
owjs3901 Oct 8, 2026
e38b74b
merge: integrate updated deterministic numbering base
owjs3901 Oct 8, 2026
dfaf6ec
fix(test): qualify CI Bun coverage with runtime-bound provenance
owjs3901 Oct 8, 2026
ea82d3c
fix(webpack-plugin): resolve loaders from the installed package
owjs3901 Oct 8, 2026
03cd867
fix(test): retain native coverage for deleted loaded modules
owjs3901 Oct 8, 2026
ce92138
fix(plugin-utils): enumerate physical production source candidates
owjs3901 Oct 8, 2026
e884e40
fix(test): preserve producer failure context and lifecycle
owjs3901 Oct 8, 2026
56031cb
fix(test): bound final coverage capture with producer timeout
owjs3901 Oct 9, 2026
9f5f4a6
fix(plugin-utils): add dormant physical resolver closure
owjs3901 Oct 9, 2026
5d61c3f
fix(plugins): release owned WASM extraction outputs
owjs3901 Oct 9, 2026
e3277f5
fix(test): dispose completed watch observation deadlines
owjs3901 Oct 9, 2026
d979780
fix(plugin-utils): certify closed manifest frontiers before DAG reuse
owjs3901 Oct 9, 2026
4d1661c
fix(plugin-utils): reserve complete production identity unions once
owjs3901 Oct 9, 2026
0840bcb
fix(plugin-utils): define dormant nonphysical identity list policy
owjs3901 Oct 9, 2026
c91e404
fix(webpack-plugin): add dormant returned-config manifest registry
owjs3901 Oct 10, 2026
abddd63
fix(plugin-utils): add dormant scoped extraction ID store
owjs3901 Oct 10, 2026
d63b0f5
fix(vite-plugin): scope production numbering and recover watch inputs
owjs3901 Oct 11, 2026
bdcfbf3
fix(vite-plugin): derive numbering-store errno from the host filesystem
owjs3901 Oct 11, 2026
d2c0e01
fix(test): report every native coverage gap with exact counts
owjs3901 Oct 11, 2026
15b7dd8
fix(vite-plugin): cover native numbering-store rewrite failures
owjs3901 Oct 11, 2026
d5141b3
fix(plugins): recover production landing preparation
owjs3901 Oct 14, 2026
f38fc62
fix(vite-plugin): omit proven no-op numbering candidates
owjs3901 Oct 14, 2026
5595a58
chore: merge updated deterministic-numbering base
owjs3901 Oct 14, 2026
b7a1716
chore: merge main and reconcile compiler-mode guards
owjs3901 Oct 14, 2026
cfa32c0
perf(plugin-utils): scope production resolution snapshots to local di…
owjs3901 Oct 16, 2026
919ef1b
chore: merge main and drain Bun Tailwind watchers
owjs3901 Oct 16, 2026
eb22d08
fix(vite-plugin): scope script reservations to entry reachability
owjs3901 Oct 16, 2026
e97cf29
fix(vite-plugin): reserve configured root closure before extraction
owjs3901 Oct 17, 2026
6bab638
test(vite-plugin): load landing config through bundled public loader
owjs3901 Oct 17, 2026
eb8caeb
fix(test-harness): reconstruct native coverage across equivalent reloads
owjs3901 Oct 17, 2026
6ec8691
perf(plugins): reuse preparation inputs and bound watch work
owjs3901 Oct 18, 2026
30e64c3
merge: main 103b7d39 into fix/plugin-core
owjs3901 Oct 20, 2026
052ff05
merge: main 7188d5ff into fix/plugin-core
owjs3901 Oct 20, 2026
2234c27
merge: main 770aaac5 into fix/plugin-core
owjs3901 Oct 21, 2026
7d9c41b
merge: update PR #755 with main
sisyphus-dev-ai Oct 22, 2026
0779f55
fix(plugins): keep unprepared Markdown unreadable
owjs3901 Oct 23, 2026
822a59f
fix(webpack): normalize reserved entry resources
owjs3901 Oct 23, 2026
14bd683
test(webpack): verify installed loader rule identities
owjs3901 Oct 23, 2026
d15aa8f
test(extractor): cover rejected and ignored imported modules
owjs3901 Oct 23, 2026
4693074
refactor(extractor): isolate parser diagnostic mapping
owjs3901 Oct 23, 2026
d7f8bde
perf(plugins): reduce compiled guard allocations
owjs3901 Oct 23, 2026
85caa27
perf(webpack): avoid excluded adapter entry scans
owjs3901 Oct 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
7 changes: 7 additions & 0 deletions .changepacks/changepack_log_adapter_framework_entries.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"changes": {
"packages/webpack-plugin/package.json": "Patch"
},
"note": "Avoid scanning excluded framework entry directories when an adapter supplies the complete production extraction inventory, preserving generic entry closure and explicitly included packages. No new build errors.",
"date": "2026-10-23T00:00:00.000Z"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"changes": {
"packages/plugin-utils/package.json": "Patch"
},
"note": "Reduce temporary allocations while preserving compiled-source guard facts, scope analysis and diagnostics. No new build errors.",
"date": "2026-10-23T00:00:00.000Z"
}
7 changes: 7 additions & 0 deletions .changepacks/changepack_log_imported_source_diagnostics.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"changes": {
"bindings/devup-ui-wasm/package.json": "Patch"
},
"note": "Exercise unsupported child grammars and ignored styled imports without changing resolver behavior. Isolate parser diagnostic coordinate mapping and verify real malformed generated source retains generated coordinates without authored edit remapping. No new build errors.",
"date": "2026-10-21T00:00:00.000Z"
}
13 changes: 13 additions & 0 deletions .changepacks/changepack_log_plugin_core.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"changes": {
"bindings/devup-ui-wasm/package.json": "Patch",
"packages/plugin-utils/package.json": "Patch",
"packages/vite-plugin/package.json": "Patch",
"packages/webpack-plugin/package.json": "Patch",
"packages/rsbuild-plugin/package.json": "Patch",
"packages/bun-plugin/package.json": "Patch",
"packages/next-plugin/package.json": "Patch"
},
"note": "Use bundler project roots and active export conditions for build-time module resolution, resolve inherited tsconfig paths and dotted module specifiers, transform modern modules and compiled MDX, match included packages literally, and refresh empty theme declarations. Skip unrequested source maps, surface resolver faults before stylesheet mutation, and report WASM panic locations. Malformed or cyclic configuration, resolver failures, requested graph/prewarm failures and disabled Rsbuild shared splitting now stop builds with context; optional numbering fallback warns about its deterministic impact. Bun defaults to compact names and retains imported build-time dependency watch edges. Webpack and Rsbuild defer package manifest syntax or shape failures until their entries reach the importing file; discovery without entries still fails closed. Rsbuild releases the shared build engine after a failed build, and generated, output and project-root directories are no longer numbered as sources. Bun follows local barrels and prepares only demanded Markdown before replaying detection and extraction, restoring valid MDX imports after the main merge; failed preparation retains its located cause and cannot produce a successful untransformed build.",
"date": "2026-10-01T00:00:00.000Z"
}
10 changes: 10 additions & 0 deletions .changepacks/changepack_log_plugin_core_ci.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": {
"packages/plugin-utils/package.json": "Patch",
"packages/vite-plugin/package.json": "Patch",
"packages/webpack-plugin/package.json": "Patch",
"packages/rsbuild-plugin/package.json": "Patch"
},
"note": "Keep raw MDX out of static import graphs unless the caller compiles MDX before extraction, preserving Next production prewarm behavior while MDX-aware plugins opt in. Normalize Webpack inline-loader entry resources before filesystem lookup and skip virtual or pitch-only entries without swallowing real I/O failures. Isolate watched-config regression diagnostics while preserving the prior theme on invalid configuration. No new build-error category is introduced.",
"date": "2026-10-01T00:00:00.000Z"
}
7 changes: 7 additions & 0 deletions .changepacks/changepack_log_plugin_core_mdx.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"changes": {
"bindings/devup-ui-wasm/package.json": "Patch"
},
"note": "Extract compiled MDX with its real source filename, including JSX-preserving alias imports and exact static computations. Raw or invalid MDX and unsupported extraction extensions now produce located build errors instead of untransformed styling placeholders.",
"date": "2026-10-01T00:00:00.000Z"
}
11 changes: 11 additions & 0 deletions .changepacks/changepack_log_unprepared_markdown_parity.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": {
"packages/plugin-utils/package.json": "Patch",
"packages/next-plugin/package.json": "Patch",
"packages/bun-plugin/package.json": "Patch",
"packages/vite-plugin/package.json": "Patch",
"packages/webpack-plugin/package.json": "Patch"
},
"note": "Keep unprepared Markdown unreadable during Next and Webpack evaluation as on main, while preserving strict compiler-cache guards for preparation-owning adapters. Use neutral portable test scratch paths. Actual compiled-MDX evaluation remains separate work. No new build errors.",
"date": "2026-10-21T00:00:00.000Z"
}
7 changes: 7 additions & 0 deletions .changepacks/changepack_log_webpack_entry_resources.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"changes": {
"packages/webpack-plugin/package.json": "Patch"
},
"note": "Normalize Webpack entry loader requests before physical class-slot reservation, retaining bare packages and invalid-resource errors. Verify relocated public require/import entries use the installed source/source/CSS loaders and share the consumer WASM identity. No new build errors.",
"date": "2026-10-21T00:00:00.000Z"
}
137 changes: 130 additions & 7 deletions bindings/devup-ui-wasm/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,100 @@
# @devup-ui/wasm

The Devup UI compiler as a Node.js WebAssembly module. It is the engine the
build plugins (`@devup-ui/vite-plugin`, `next-plugin`, `webpack-plugin`,
`rsbuild-plugin`, `bun-plugin`) call; most projects never import it directly.
Build-time CSS extraction bindings used by the Devup UI bundler plugins.

## Extraction boundaries

`codeExtract` generates a source map. `codeExtractWithoutSourceMap` skips map
generation, including when a module resolver is installed; its `map` getter is
`undefined`. Both functions return transformed source and watched dependencies.

`setModuleResolver` accepts a synchronous `(specifier, importer)` callback.
Return `{ path: string, code: string }` for a resolved module, or
`{ ignored: true }` for an explicitly ignored native alias. An ignored result
has no source/path and never reads `path`, `code` or `sourceType` getters.
`null` and `undefined` mean ordinary unresolved imports. Thrown exceptions, property-getter
and reflection failures, and missing/non-string fields instead fail extraction:

```text
/src/App.tsx:1:1: module resolver cannot use `./tokens` at build time: original cause
```

The importer includes transitive importers. The resolver contract does not
provide an import span, so this boundary reports `1:1` rather than guessing a
position from source text. The first resolver fault takes precedence over the
extractor's unresolved-module fallback and is checked **before** sheet updates.
The previous stylesheet contribution therefore survives a failed re-extraction.
Class/file numbering performed inside extraction is not rolled back.

Ignored imports are empty CommonJS modules, not renamed or virtual files. Missing
named values are `undefined`, defaults follow the existing CommonJS interop, and
namespace/require values are empty objects. No ignored file becomes a watched
dependency or is sent through the parser. The `ignored` discriminator must be
`true` or absent; malformed discriminators retain the same located resolver-fault
priority and previous-sheet preservation as malformed file results.

## Panic diagnostics

WASM initialization installs this binding's own `std::panic::set_hook`, with no
additional dependency or feature flag. It reports Rust's panic payload and
`file:line:column` location to `console.error` before the trap. A failing host
console does not replace the original panic. This is diagnostic reporting, not
panic recovery: with `panic=abort`, a panic still traps and the instance should
be discarded. Normal resolver/configuration failures use fallible JS errors.

Owned binding code does not unwrap user input or explicitly panic. Sheet mutex
poisoning is recovered, and no resolver callback is called while holding a sheet
lock or a thread-local resolver borrow. Panics originating in downstream crates
remain outside this binding's recovery contract.

## Verification

From the repository root:

```sh
cargo test -p devup-ui-wasm boundary_ -- --nocapture
```

After rebuilding `pkg` with this package's `bun run build`, run from the
repository root:

```sh
node bindings/devup-ui-wasm/boundary-regressions.mjs
node bindings/devup-ui-wasm/ignored-alias-regressions.mjs
```

This standalone runner loads the real generated JS and WASM, outside Bun's
coverage mocks. It exercises both extraction exports, map skipping with and
without resolution, unresolved null/undefined, valid resolved dependencies,
callback exceptions, getters, proxy reflection, malformed fields and hostile
exception objects. Every fault case verifies the previous sheet is unchanged.
Native tests cover every branch of the internal fault-precedence helper.

## Explicit Compiler Source Type

Both extraction functions accept an optional ninth argument after
`import_aliases`: `sourceType?: 'compiled-mdx'`. Use it for project-compiled MDX
under a custom extension, without changing the real filename:

```ts
const output = codeExtract(
'src/page.mdown', compiledCode, '@devup-ui/react', 'df',
true, false, false, {}, 'compiled-mdx',
)
```

The value means JavaScript with JSX, not TypeScript or raw Markdown. Omission
keeps filename-derived parsing, including compiled JavaScript/JSX for `.md` and
`.mdx`. Unknown extensions without an override fail with a located error even
when the source has no styling import. Invalid source-type values also fail
before stylesheet publication.

Resolved modules may return `{ path, code, sourceType: 'compiled-mdx' }`. The
child's own type reaches imported constants, reexports, stylesheet evaluation
and stripping caches; it never inherits the importing file's override. This
includes an ordinary TSX file importing a constant after JSX in compiled `.md`
or `.mdown`. Parser/source-type failures preserve the previous stylesheet.
Existing imported-value coordinate limitations remain owned by #757.
It is built from the Rust crates in `libs/` (`extractor`, `sheet`, `css`) with
`wasm-pack build --target nodejs`, so it loads with `require`/`import` in Node
and Bun, not in a browser.
Expand Down Expand Up @@ -36,12 +127,17 @@ Everything is exported from `pkg/index.js` (types in `pkg/index.d.ts`).
| `setDebug(debug)`, `isDebug()` | Readable class names instead of base-37 ones, with repeated declarations kept (the tests run this way). |
| `setModuleResolver(resolver)` | `(specifier, importer) => ({ path, code })`: how imports are resolved, so imported stylesheets are evaluated and imported constants inlined. |
| `setAtomHoist(threshold)`, `importFileRoutes(routes)` | Moves atoms used by `threshold` routes or more into the shared sheet. Call before `codeExtract`. |
| `exportSheet`, `exportClassMap`, `exportFileMap`, `exportCanonicalMap` and the matching `import*` functions | Save the collected state and load it into another process, as a bundler does between its server and client builds. |
| `exportSheet`, `exportClassMap`, `exportFileMap`, `exportCanonicalMap`, `exportReservationState` and the matching `import*` functions | Save an owner's collected state, including the reservation phase and miss count, across synchronous engine resets. |
| `reserveClassSlots(rows, package, singleCss, importMainCssInCode, importMainCssInCss, importAliases)` | Reserve class/file counter slots without publishing CSS. Rows are `[filename, code, cssDir]` or `[filename, code, cssDir, 'compiled-mdx']`; compiled sources keep their real filenames. |
| `getUnreservedClassSlotCount()` | Count new live allocator keys after reservation, excluding repeated keys. |
| `getSuppressedReservationRowCount()` | Count failed rows suppressed by the latest reservation batch, independently of live misses. An empty or successful retry batch reports zero. |
| `resetBuildState()` | Reset build-scoped engine state before a fresh build or owner restore. |

## State

The module keeps its state, the sheet, class maps, theme, prefix and debug flag,
in one global per process. Two consequences:
in one global per process. Integrations reset and restore their owned
snapshots at synchronous operation boundaries. Two consequences:

- Register the theme, shorthands, prefix and resolver before the first
`codeExtract`, and extract the files of one build in one process.
Expand All @@ -52,13 +148,22 @@ in one global per process. Two consequences:
theme-token and Tailwind definition registries, and imported stylesheet caches. Call
only at a quiescent test boundary, never in a resolver callback or between
environments of a build that intentionally share state. Native caches reset
on the calling thread.
on the calling thread. Opaque reservation snapshots must be restored with the
matching sheet and allocator maps, not imported into another owner's maps.

`resetBuildState()` remains the separate production build boundary. It clears
allocator bookkeeping, maps/routes, atom threshold/plan, prefix, sheet and resolver,
but leaves CSS theme-key configuration, shorthands and debug for the next build's
configuration path to overwrite. It is not an alias for the full testing reset.

Scratch reservation failures are row-local: new class, variable, keyframe and
other shared allocator keys, and extraction-time file inserts, are rolled back
before the next row. The deterministic FILE inventory preseeded for the batch
is retained, including failed rows. A later successful retry appends slots without
renumbering existing keys. Suppression is captured in the opaque reservation
snapshot and cleared by `resetBuildState`; it never changes the live-miss query.
This rollback applies to scratch reservation only, not failed real transforms.

Rust tests use hidden `css::test_state::TestStateGuard` and
`extractor::test_state::TestStateGuard` support compiled into dependencies so
dependent-crate tests can restore owned snapshots on normal exit, nesting and
Expand All @@ -75,6 +180,24 @@ values must be literals, theme tokens or constants`` (the location is included
whenever the problem has one). A `.css.ts` stylesheet that throws while it runs
reports that exception.

## License
After rebuilding the bindings, run the real project-compiler/WASM matrix:

```sh
node bindings/devup-ui-wasm/source-type-regressions.mjs
```

The same JS runner also uses the installed `@mdx-js/mdx` compiler, resolved through
`@mdx-js/loader` in `apps/landing` (no added dependency). Both default `_jsx`
output and `jsx: true` output are extracted under real `.mdx` and `.md` filenames.
It checks CSS, the relevance gate, source-map filename identity and rejection of
raw Markdown. Compiled MDX is parsed as JSX JavaScript, not TSX. Its source-map
coordinates refer to compiler output; bundler integrations must compose input
maps to recover Markdown positions, or identify diagnostics as compiled MDX.

Focused native MDX verification:

```sh
cargo test -p extractor mdx_ -- --nocapture
```

Apache-2.0
Loading
Loading