Repository navigation
build: move to node and npm, and remove code nothing reaches - #14
Merged
Merged
Conversation
Bun was chosen because npm could not install this tree at all, crashing with "Cannot read properties of null (reading 'edgesOut')". That turned out to be one dependency, not the tree: npm installs cleanly with vitest removed and crashes in #loadPeerSet with it present, because vitest 4 declares a large optional-peer set that npm's arborist cannot walk. Vitest 5 does not have the problem, so the fix is an upgrade rather than a workaround. What forced the question was the container build failing with "Cannot find package 'tsx:'". vite.config.ts passes virtualRouteConfig as a path, so the router generator loads that TypeScript file through tsx — a Node loader. The fix on Bun was to install Node beside it, which is two runtimes to work around one plugin. It also failed only intermittently, depending on whether the generator's cache re-ran, so the build worked on one machine and not the next. Node is what an adopter already has, and nothing runs a JavaScript runtime in production anyway — the deployed artifact is static files behind nginx. This is a build-time choice only. Two things npm surfaced that bun had absorbed silently: - @vitest/coverage-v8 was pinned to 4.0.17 while vitest was ^4.1.11, a real conflict - vitest 3 would also have installed, but carries a moderate path traversal advisory covering 2.1.0-beta.1 to 4.1.10. Downgrading would have introduced a vulnerability the repo did not have packageManager, the Dockerfile, CI, the hooks and the docs all follow. new:screen runs under tsx, which the tree already carries. No --legacy-peer-deps anywhere: it hides exactly the kind of conflict found here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A 250-line code generator from the starter template, creating a screen directory tree plus optional page and api folders. This is a single-screen reference client and the scope is deliberately chat and nothing else, so a generator for screens nobody should be adding is a trap rather than a convenience. Its default parent was also app/(_authenticated), a route group deleted with sign-in, so its output would not have compiled. Its runner had just been changed from bun to tsx, which meant depending on a package the tree only carries transitively, through the router generator. Deleting it removes that too. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A whole-graph sweep with knip. Unused exports go from 35 to 20, unused
types from 7 to 0, and the 20 that remain are all src/components/ui —
vendored shadcn kept as a complete API, which the knip gate excludes on
purpose. Tree-shaking already drops them from the bundle.
**The recording half of audio-utils was dead.** setupAudioRecording,
setupAudioVisualization and stopRecording had no callers — chat-input has
its own recording code — and removing them orphaned four private helpers
and an interface in turn. 374 lines to 93. What survives is playback:
playTTS, stopAudio, pauseAudio, resumeAudio.
**The per-screen query layer was empty scaffolding.** queries.ts and
mutations.ts were `export const X = {} as const` with a TODO, re-exported
through two barrels and a misspelled `componets/` directory. The
queryClient and its MutationCache stay — that part is real and is where
the first thing needing caching or invalidation plugs in — but the empty
files are gone, and a comment now says why nothing uses it yet: chat
streams into the Zustand store rather than being cached, and it is the
only live endpoint.
`OnRequestError` was a React component returning an empty `<div>`, used as
a MutationCache onError callback. The element went nowhere and only the
logging ever had an effect. Now a plain function.
**Telemetry left two modules and a dependency behind.** getBrowserInfo and
getFingerprintId were re-exported by a barrel and called by nothing; they
fed device identity into analytics that no longer exist.
@fingerprintjs/fingerprintjs, 648 KB, existed only for the second.
**ConfigProvider's React context had no consumer.** Nothing called
useConfig — everything reads getConfig() directly — so the context, the
hook and the Provider wrapper are gone. What remains is the effect that
applies theme variables, which was always its real job.
Also dropped: the dead half of qa-utils (QUESTION_ANIMAL_SCOPE and the
only function that read it), STUB_LOCATION, and `export` on seven symbols
used only inside their own file.
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.
The tail of #13. Those three commits were pushed after it merged, so they missed it.
Bun → Node and npm
Bun was chosen because npm could not install this tree at all, crashing with
Cannot read properties of null (reading 'edgesOut').That was one dependency, not the tree. npm installs cleanly with vitest removed and crashes in
#loadPeerSetwith it present — vitest 4 declares a large optional-peer set npm's arborist cannot walk. Vitest 5 does not have the problem, so the fix is an upgrade rather than a workaround.What forced the question was the container build failing with
Cannot find package 'tsx:'.vite.config.tspassesvirtualRouteConfigas a path, so the router generator loads that TypeScript file throughtsx— a Node loader. The fix on Bun was to install Node beside it: two runtimes to work around one plugin. It also failed only intermittently, depending on whether the generator's cache re-ran, so the build worked on one machine and not the next.Nothing runs a JavaScript runtime in production — the artifact is static files behind nginx — so this is a build-time choice only.
Two things npm surfaced that Bun had absorbed silently:
@vitest/coverage-v8was pinned to4.0.17againstvitest@^4.1.11, a real conflict2.1.0-beta.1–4.1.10. Downgrading would have added a vulnerabilityNo
--legacy-peer-depsanywhere: it hides exactly this kind of conflict.packageManager, the Dockerfile, CI, the hooks and the docs all follow.Dead code
A whole-graph sweep. Unused exports 35 → 20, unused types 7 → 0; the 20 remaining are all vendored shadcn kept as a complete API, which tree-shaking drops from the bundle anyway.
audio-utils.tswas dead — no callers, and removing it orphaned four private helpers and an interface in turn. 374 lines → 93. Playback survivesexport const ChatScreenQueries = {} as constwith a TODO, behind two barrels and a misspelledcomponets/directory. ThequeryClientand itsMutationCachestay; that part is real, and it is where the first thing needing caching or invalidation plugs inOnRequestErrorwas a React component returning an empty<div>, used as aMutationCacheonError callback. Only the logging ever had an effectgetBrowserInfo,getFingerprintIdand@fingerprintjs/fingerprintjsConfigProvider's React context had no consumer — nothing calleduseConfig, since everything readsgetConfig()directly. The effect that applies theme variables remains, which was always its real jobapp/(_authenticated)— a route group deleted with sign-in, so its output would not have compiledNet −439 / +38 across 20 files.
Verified
Clean worktree with
npm ci: lint, typecheck, knip, 23 tests, coverage, build, route-tree guard. The image builds--no-cacheonnode:22-alpineand serves — routes fall back, missing files 404,config.jsonisno-store, and the app renders under a strict CSP.🤖 Generated with Claude Code