The vendor chunk was a single ~1MB blob (react + tanstack-query +
framer-motion + jodit + emoji-mart + react-icons + howler + zustand +
json5 all merged), forcing every cold load to wait on the slowest of
those modules before the page could interactivate. Split it into
domain-specific chunks so HTTP/2 multiplexing can pull them in
parallel and CF can cache each independently:
- vendor-pixi (pixi.js + pixi-filters — when rollup actually splits;
currently inlined into the umbrella renderer chunk
because nitro-renderer is its sole importer)
- vendor-audio (howler)
- vendor-emoji (@emoji-mart — heaviest at ~430KB, only used in chat
so a longer-term win is making it lazy)
- vendor-editor (jodit + @react-page — admin-only news editor)
- vendor-react (react / react-dom / scheduler / error-boundary)
- vendor-motion / vendor-query / vendor-icons / vendor-state /
vendor-json5
- nitro-renderer-{avatar,communication,room,assets} — heaviest
renderer packages get their own chunks when imported directly
(the umbrella @nitrots/nitro-renderer still hosts the rest)
Also add a `<link rel=preconnect>` for challenges.cloudflare.com so
the Turnstile JS handshake doesn't pay an extra TLS round-trip on
the first paint.
Net effect: roughly the same total bytes shipped on a cold load, but
they fetch in parallel instead of sequentially, and a warm second
visitor only re-downloads the chunks whose code actually changed.
Restoring `yarn start` from "takes forever" back to seconds.
A previous session had symlinked `public/nitro-assets` and `public/swf`
to a sibling `Nitro-Files/` tree (~177k files) so Vite could serve them
through `publicDir`. The cost was massive: chokidar tried to install a
watcher on every file at startup and the dev server hung for minutes
on Windows. Upstream `duckietm/Nitro-V3` never does this — assets live
on a separate HTTP server referenced by URL in the JSON configs.
Changes:
- Remove the two symlinks under `public/` and add a .gitignore entry
with a note explaining why they must not come back.
- Add a small Vite plugin (`nitroAssetsServer`) that mounts `sirv` on
`/nitro-assets/*` and `/swf/*`, reading from
`../Nitro-Files/{nitro-assets,swf}`. sirv is a connect-style
middleware that bypasses chokidar entirely, so 177k files no longer
cost anything at startup. The plugin also wires the same handler
into `configurePreviewServer` so `yarn preview` keeps working.
- Drop the matching `/nitro-assets` and `/swf` entries from
`server.proxy` — they had been pointed at the auth proxy on :2096
which does not expose those paths.
- Disable `login.turnstile.enabled` in `renderer-config.json`. The
configured sitekey is Cloudflare's "always-passes" test key but the
widget still requires user interaction and blocks the login flow
in local dev.
Login flow fixes that fell out of debugging:
- `prepare()` in App.tsx ran twice under React Strict Mode (mount →
cleanup → mount). The first pass set `setShowLogin(true)`, the
second raced ahead and fell through to `onSessionExpired()`,
clobbering the login UI. Guard the effect with
`lastPrepareTriggerRef` so duplicate runs at the same trigger value
are skipped while intentional re-runs (after a successful login,
which bumps `prepareTrigger`) still go through.
- Call `GetConfiguration().init()` from `bootstrap.ts` before
importing `./index`. The renderer's ConfigurationManager logs
"Missing configuration key" the first time any key is read against
an uninitialised store, and components mounted in the first paint
(login screen, hooks, the renderer warmup) were all hitting that
path before prepare()'s deferred init landed. Pre-loading the
config means the store is already populated when React mounts.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- FurniEditor component with Search/Edit tabs (NitroCard UI)
- useFurniEditor hook connecting to Next.js API routes via Vite proxy
- Edit Furni button in room infostand (godMode) with sprite ID lookup
- Toolbar: 3-column flex layout (icons | chat | friends)
- Heroicons SVG for ID/Sprite display in infostand and edit view
- Vite config: proxy /api to Next.js, aliases for renderer3 packages