Skip to content

feat(workspace-plugin): let export-maps-sync preserve hand authored asset subpaths - #36673

Open
Ray Knight (ArrayKnight) wants to merge 1 commit into
microsoft:masterfrom
ArrayKnight:fix/export-maps-sync-static-subpaths-36655
Open

feat(workspace-plugin): let export-maps-sync preserve hand authored asset subpaths#36673
Ray Knight (ArrayKnight) wants to merge 1 commit into
microsoft:masterfrom
ArrayKnight:fix/export-maps-sync-static-subpaths-36655

Conversation

@ArrayKnight

@ArrayKnight Ray Knight (ArrayKnight) commented Aug 31, 2026

Copy link
Copy Markdown

export-maps-sync rebuilds a project's entire exports map from its declared entry points and keeps nothing else, so any subpath the generator cannot derive from a source file — a compiled stylesheet, a raw .css source, a wildcard asset subpath — is silently deleted on the next nx sync, with no diagnostic. The first sign is a consumer's failed import. Measured on a package with 151 export keys, 4 of them asset subpaths: with subpathEntryPoints declared, sync still dropped exactly the two .css keys.

This adds metadata.exportMap.staticSubpaths — a list of keys the generator explicitly does not own. Only the keys are declared; the entries stay hand-authored in package.json and are read back verbatim on every sync, so there is no second copy of the paths to drift. Two hardening changes come with it: a declared key with nothing to preserve now throws, naming the key (the silent-deletion failure mode becomes a loud one), and key emission runs through one canonical ordering pass (. first, ./package.json last, the rest alphabetical). Eleven unit tests are added in the plugin's existing style; on the real workspace a second nx sync is a no-op and nx sync:check reports up to date before and after the change, so no existing package moves.

Fixes #36655.

Extracted from #36656 per maintainer request — each in-tree fix from that PR as an isolated change.

…sset subpaths

The sync generator rebuilds a project's whole `exports` map from its declared
entry points and keeps nothing else, so any subpath it cannot derive from a
source file is a subpath it silently deletes on the next `nx sync`. That is
fine for packages whose map is entirely TypeScript, and fatal for one shipping
a compiled stylesheet (`./styles.css`) or a raw `.css` source published for a
consumer's Tailwind `@source` scan (`./variants.css`) - today the only way to
keep those is to stay out of the generator's scope by staying `private`.

Adds `metadata.exportMap.staticSubpaths`: a list of export keys the generator
does not own. Only the keys are declared in `project.json`; the entries stay
hand authored in `package.json` next to the `files` array that ships them, and
are read back verbatim on every sync, so there is no second copy of the paths
to drift. A key with no matching entry, or one the generator already derives
from source, throws with the key named.

Key emission now runs through a single ordering pass - `"."` first,
`"./package.json"` last, everything else alphabetical - so static and generated
subpaths land in the same predictable place. Existing packages are unaffected:
their generated subpaths were already emitted sorted, and `nx sync:check`
reports the workspace up to date before and after.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013wmpBCYJpDJCLXcScCWz1i
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

1 participant