fix(vite-config): publish compiled JS instead of raw TypeScript sources - #1
Merged
Merged
Conversation
The package mapped its export subpaths straight at ./src/*.ts. Inside the monorepo pnpm links the package, so Node's realpath lands outside node_modules and type stripping is allowed. Every consumer installing from the registry instead resolved to a path under node_modules, where Node refuses to strip types, and loading any preset from a vite.config.ts failed with ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING. The package now emits dist/ with tsc (ESM + declarations) and points exports there. Subpath names are unchanged, so no consumer import has to change and the per-package workarounds (NODE_OPTIONS="--import tsx", --configLoader runner) can be dropped. Type-checking the sources for the first time surfaced two latent bugs, fixed here as well: useSWC: true threw "require is not defined" (bare require() in an ES module, now createRequire), and dts.outDir/dts.rollupTypes were silently ignored because vite-plugin-dts v5 renamed them to outDirs/bundleTypes. Wire the build into the release flow so this cannot regress: prepack rebuilds dist, `pnpm release` builds before changeset publish, and CI's packaging check is now scripts/verify-packaging.mjs, which packs every public package and asserts that each exports/main/types target exists in the tarball and is not raw TypeScript. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates @eventuras/vite-config to publish compiled JavaScript + declaration files from dist/ (instead of exporting raw src/*.ts), preventing Node’s ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING for registry consumers. It also tightens the release/CI flow to ensure packages are built before publishing and adds a repo-wide packaging verifier to catch manifest/export issues before release.
Changes:
- Build and publish
@eventuras/vite-configfromdist/with updatedexportsand TS config for ESM + declarations. - Fix ESM
requireusage for the optional SWC React plugin and alignvite-plugin-dtsoption names with v5. - Add
scripts/verify-packaging.mjsand wire it into CI and the root scripts; ensurepnpm releasebuilds before publishing.
Reviewed changes
Copilot reviewed 11 out of 12 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/verify-packaging.mjs | New script to pack each public workspace package and validate manifest targets exist in the tarball and aren’t raw TS sources. |
| pnpm-lock.yaml | Lockfile updates for added workspace/dev dependencies (notably for config/vite-config). |
| package.json | Adds verify:packaging script; updates release to build before changeset publish. |
| config/vite-config/tsconfig.json | Enables emitting JS + declarations into dist/ with NodeNext ESM settings. |
| config/vite-config/src/vanilla-lib.ts | Switches relative import specifier to .js to match emitted/published output. |
| config/vite-config/src/react-lib.ts | Uses createRequire for SWC plugin loading in ESM; updates .js specifier; updates dts option names. |
| config/vite-config/src/next-lib.ts | Switches relative import specifier to .js to match emitted/published output. |
| config/vite-config/README.md | Documents Node/Vite/TS requirements and the historical type-stripping failure + guidance. |
| config/vite-config/package.json | Repoints exports to dist/*.js with matching types; publishes only dist; adds build/prepack scripts and dev deps. |
| .github/workflows/release.yml | Notes that pnpm release builds before publishing, preventing publishing without compiled output. |
| .github/workflows/ci.yml | Replaces inline pack check with pnpm verify:packaging. |
| .changeset/heavy-donkeys-smoke.md | Changeset documenting the publish-from-dist change and the two related fixes. |
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| const relative = posix.normalize(target.replace(/^\.\//, '')); | ||
|
|
||
| if (/\.(c|m)?tsx?$/.test(relative) && !relative.endsWith('.d.ts')) { |
Comment on lines
+81
to
+82
| ` ERROR ${pkg.name}: exports "${target}" points at TypeScript source. ` + | ||
| `Node cannot strip types under node_modules — publish compiled JS instead.` |
- verify-packaging: treat .d.mts and .d.cts as declaration output, not raw TypeScript sources. The previous check only exempted .d.ts, so a NodeNext package emitting .d.mts would have failed verification for valid output. - verify-packaging: name the offending manifest field (exports/main/module/ types/bin) in the error instead of always saying "exports". - vite-config: make prepack tool-agnostic. It ran `pnpm run` and `rm -rf`, so `npm pack`/`npm publish` depended on pnpm being on PATH and on a POSIX shell. Now `npm run` (npm always ships with Node) and a Node-based clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.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.
Problem
@eventuras/vite-configmapped its export subpaths straight at./src/*.ts:That works inside origo — pnpm links the package, so Node's realpath lands outside
node_modulesand built-in type stripping is allowed. It breaks for every consumer installing from the registry, where the realpath isnode_modules/.pnpm/@eventuras+vite-config@…/node_modules/@eventuras/vite-config/src/vanilla-lib.ts:Node's restriction is deliberate and permanent. Reported from losol/historia#1, where it takes down the whole Docker image build; consumers are currently forced into per-package workarounds (
NODE_OPTIONS="--import tsx",vite build --configLoader runner).Change
pnpm buildrunstscand emitsdist/— ESM + declarations, no bundling. Runtime deps stay real deps.dist/*.jswith matching"types": "./dist/*.d.ts","files": ["dist"]. Subpath names are unchanged (./base,./react-lib,./vanilla-lib,./next-lib) — no consumer import changes.'./externals.ts'to'./externals.js'.rewriteRelativeImportExtensionsalone is not enough: TS 6.0.3 rewrites the JS emit but not the declaration emit, sonext-lib.d.tswould have shipped an import of./react-lib.ts, a file that isn't published. Verified with a minimal repro.getRuntimeDependencyExternals()still reads the consumer'spackage.jsonviaprocess.cwd()— nothing resolves relative to the config package.Two latent bugs found by type-checking the sources for the first time
useSWC: truethrewrequire is not defined— a barerequire()inside an ES module. NowcreateRequire, keeping the SWC plugin lazily loaded.dts.outDiranddts.rollupTypeswere silently ignored: vite-plugin-dts v5 renamed them tooutDirs/bundleTypes. The preset's own option names are unchanged.Release flow
prepackrebuildsdist;pnpm releasebuilds beforechangeset publish(the release workflow never built at all, sopackages/*had the same exposure).scripts/verify-packaging.mjs, which packs every public package and asserts eachexports/main/types/bintarget is in the tarball and is not raw TypeScript. Negative-tested: it flags both"./src/base.ts"and a target missing fromfiles.Verification
Run outside the monorepo, so no workspace symlink hides the bug —
npm packed the built package into scratch projects (Node 24.18, Vite 8.2,"type": "module"), in both npm-flat and pnpm virtual-store layouts:vite buildwith./vanilla-lib,./base,./react-lib,./next-libnode— noNODE_OPTIONS, no--configLoader runnertsc --noEmitimporting all four entrypoints + their exported typesuseSWC: true.tsexport added back to the installed packageERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING— the scratch setup does reproduce the bugpnpm build,pnpm lint,pnpm verify:packagingin origoAlso confirmed the runtime dep externalization survives the move to
dist/: the scratch project'szodstays an external import.Sweep
Only
config/vite-configexported raw.ts.@eventuras/typescript-configships JSON,@eventuras/eslint-configships plain.js, and all ofpackages/*already exportdist. There is nolibs/in this repo.verify-packaging.mjsnow enforces this for anything added later.Release
Changeset included, minor → 0.3.0. Once published, historia bumps
@eventuras/vite-configinpackages/vipps,packages/payload-vipps-authandpackages/notitia-templatesand drops its workarounds.Note for consumers: the declaration step needs TypeScript 6 — vite-plugin-dts v5 requires the TS JS Compiler API, which TS 7 no longer ships by default. Documented in the README; hit this while testing.
🤖 Generated with Claude Code