Repository navigation
fix: publish only what consumers need, without the development condition - #560
Merged
Merged
Conversation
Plugins had no `files` field, so npm shipped everything not in .npmignore: rozenite.config.ts (dev-host fixtures and flows), tests, vite/tsconfig files, and for expo-atlas-plugin 4k+ installed test fixtures (about 6 MB). Publish an explicit allowlist instead: dist, CHANGELOG.md, and for plugins whose ./sdk export has a development condition, sdk.ts and src minus tests. require-profiler-plugin also keeps src/metro/setup.js, which its Metro integration hands to Metro by path.
@rozenite/tools and @rozenite/web had no `files` field and shipped their src, tsconfig*.json and build scripts. Drop test artifacts from the others: tsc declaration stubs for tests in lynx, plugin-bridge and testing, tsbuildinfo caches in agent-bridge and test files in the src that @rozenite/ui ships for Tailwind source scanning.
The plugin template had no `files` field, so every generated plugin would publish its rozenite.config.ts, tests and build configuration. rozenite build adds the ./sdk export (development condition -> sdk.ts) on its own when sdk.ts appears, so the allowlist includes sdk.ts and src up front.
Sixteen packages had a `development` condition in `exports` pointing at TypeScript source (`./src/index.ts`, `./react-native.ts`, `./sdk.ts`). It exists for this workspace (tsconfig customConditions, the playground's webpack conditionNames), but webpack, Rspack and Vite also turn it on in dev mode, and for agent-bridge, agent-sdk, agent-shared, lynx-dev, metro, middleware and repack the target was not in the tarball: a consumer's dev build failed with 'Failed to resolve entry for package' / "Can't resolve". For the plugins' ./sdk it resolved to .ts under node_modules instead. Repeat `exports` without the condition under `publishConfig.exports`; pnpm pack and pnpm publish (which changeset publish uses) apply it.
With the development condition gone from the published exports, plugins no longer need to ship sdk.ts and src to keep its target from dangling: their allowlist is now dist and CHANGELOG.md (plus src/metro/setup.js for require-profiler-plugin, which hands it to Metro by path). tsc --incremental writes dist/*.tsbuildinfo whenever typecheck runs before a pack, and release:check does exactly that, so exclude them from every package that publishes dist.
metro and repack listed a `templates` directory in `files` that does not exist, and middleware exported a TEMPLATE_DIR pointing at a nonexistent entry-point.ejs. Nothing in the repository reads it (the CLI has its own TEMPLATE_DIR).
rozenite build added `development: ./sdk.ts` to a plugin's ./sdk export. Anyone publishing such a plugin either shipped sdk.ts and src to keep the target from dangling or broke dev builds that enable the condition (webpack, Rspack, Vite). The managed export is now just types and default; a development condition the author wrote themselves is preserved, which is how the workspace plugins keep theirs. The plugin template therefore publishes only dist.
Each publishable package now owns a package-contents test that packs the built package the way pnpm publish does and checks the tarball with inspectPackedPackage from @rozenite/test-utils/packaging: - every exports/main/module/types/react-native/bin target, for every condition, is in the tarball; - the published exports equals the source exports minus `development`; - no rozenite.config.*, test, fixture or build-configuration file ships; - no shipped module imports a file that was left out. It runs as part of the package's own test task, so test:affected runs it whenever the package or something it depends on changes, and it builds only what that package already needs. @rozenite/web gets a test script that runs just this guard: its existing webpack suite was never wired up and fails on an unhandled rejection.
Replace the sixteen copies of exports under publishConfig.exports with a beforePacking hook in the root .pnpmfile.cjs that removes the development condition from every package's exports. Verified for both entry points: pnpm pack, and a real pnpm publish against a local registry that records the PUT body (publishConfig.exports removed from the package for the test). changeset publish runs pnpm publish from the package directory, so the workspace pnpmfile applies. pnpm records the file in the lockfile as pnpmfileChecksum. The plugins' ./sdk exports also drop their development: ./sdk.ts. Nothing resolved it in the workspace: agent-sdk maps the plugin SDKs to dist declarations in its tsconfig and to source through a Vite alias, and the network-activity e2e tsconfig clears customConditions. The package-contents guard still asserts that the published exports equal the source exports minus development.
…onfig.exports rozenite build wrote development: ./sdk.ts into the managed ./sdk export from 1.10.0 until the previous commit stopped it, so plugins generated since then still carry it and publish a target they do not ship. Drop that exact value on the next build; any other development value was written by the author and is kept. Authors who hide a development condition with publishConfig.exports would lose ./sdk or ./metro from the published package when those appear, because only exports was managed. When publishConfig.exports exists, write the managed entries there too (never with development) and report it as updated; a package without one is left alone.
npm does not include CHANGELOG.md on its own, so the allowlists added earlier left it out of the seventeen libraries, the CLI and electron-app that were already on one. List it everywhere a CHANGELOG.md exists; the plugin template has none.
Track .pnpmfile.cjs as a global Turborepo input, so editing the hook that strips the development condition re-runs every package-contents test, and strip the condition inside export arrays too.
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.
Description
Published packages now ship only what consumers need, and their
exportsresolve in every bundler mode.filesallowlists: every publishable package has an explicitfilesfield.distandCHANGELOG.md.require-profiler-pluginalso shipssrc/metro/setup.js, which its Metro integration loads by path.distplus what their exports point at.@rozenite/uikeepssrcfor Tailwind's@source, plusfonts/,fonts.cssandstyles.css.rozenite.config.ts), tests, fixtures, configs andtsbuildinfono longer ship.No
developmentcondition in published manifests. A root.pnpmfile.cjsbeforePackinghook strips it from every package'sexportsonpnpm packandpnpm publish;changeset publishusespnpm publish. The workspace keeps the condition, so tsconfigcustomConditionsand the playground still resolve to source../sdkexports dropdevelopment: './sdk.ts'as well../sdkstill points atdist/sdk/sdk.jsandsdk.d.ts, which ship as before.CLI:
rozenite buildno longer writesdevelopment: './sdk.ts'into a plugin's./sdkexport, and removes that legacy value from existing plugins. An author's owndevelopmentvalue is kept. If a plugin haspublishConfig.exports, the managed entries are synced into it. Plugins created withrozenite generatepublish["dist"].Dead references removed: the
templatesentries inmetroandrepack, andTEMPLATE_DIRinmiddleware, all pointed at files that don't exist.Guard: every publishable package has a
package-contentstest, built oninspectPackedPackagein@rozenite/test-utils. It runspnpm packand checks that:exports,main,module,types,react-nativeandbintarget, for every condition, is in the tarball;exportsequal sourceexportsminusdevelopment;workspace:dependency leaks;rozenite.config.*, test, fixture,tsbuildinfoor build config ships;.pnpmfile.cjsis a global Turborepo input, so editing the hook re-runs every guard.Docs:
agents/package-creation.mddescribes the allowlist, thedevelopmentpolicy and the guard.Related Issue
Closes #559
Context
Published size, all 33 packages, rebuilt from scratch on both sides:
.tgzexpo-atlas-plugindrops from 43 MB to 295 kB, because 4,222 Metro test fixtures no longer ship. Every package now ships itsCHANGELOG.md.The
developmentbug. Before, a consumer project using webpack 5 in development mode could not resolveagent-bridge,agent-shared,agent-sdk,metro,repack,middlewareorlynx-dev. Vite 7 dev threwERR_RESOLVE_PACKAGE_ENTRY_FAIL. Plugin/sdkimports andvite-pluginresolved to.tssource insidenode_modules. After this change, everything resolves todist.Why a pnpm hook. It replaces 16 hand-copied
publishConfig.exportsmaps. pnpm records the hook's checksum in the lockfile, so editing it needs apnpm install; otherwise frozen installs fail loudly.npm publishwould ignore the hook, but releases go throughchangeset publish, which usespnpm publish.Behaviour note. In the playground's on-device
e2e:networkrun,@rozenite/{network-activity,storage}-plugin/sdknow resolves to the builtdistinstead ofsdk.ts.docs/agents/network-activity-e2e.mdalready says to rebuild the plugin before each run.Not changed, noted:
@rozenite/web's.d.ts.mapfiles point atsrc, which isn't published. Editors fall back to the.d.ts, as forlynx,plugin-bridgeandtesting.packages/web/src/__tests__/webpack.test.tswas never wired up onmain, and fails with "DefaultToolLauncher must be mocked". Web'stestscript now runs only the guard.Testing
git fetch origin main && pnpm checks:affected && pnpm test:affected: passed, 72 test tasks. The guard was also run uncached across all 35 test tasks; the slowest guard took about 16 s against a 120 s timeout.dist:developmentconditions in any packed manifest.requireandimport;sdkentries,tools, the Metro, Re.Pack and webpack integrations,vite-pluginandlynx/rspeedy;rozenite --helpandrozenite skills list.dist.pnpm publish, andchangeset publish --no-git-tagfor all 33 packages, against a local mock registry. The published manifests have nodevelopment.files, a droppeddist/sdk, a shippedtsbuildinfo, a stale export, and the hook disabled.rozenite buildacross all plugins leaves everypackage.jsonunchanged.