Files
world/vite.react.config.ts
zeekayandClaude Opus 4.8 ad713a6df0 feat(world): land the @hanzo/gui React rewrite as an opt-in canary on main
Overlays the complete 80-file src/react surface (all 58 panels, globe island,
variant tabs, analyst dock, finance terminal, OIDC PKCE callback) onto the live
origin/main backend (v2.4.51 AI-plane + events-stream fixes, kept intact). The
React surface is served ONLY to sessions that opt in via ?react (sticky cookie,
cmd/world canaryHandler); the vanilla build stays the default — nothing changes
for anyone until we flip it. @hanzogui/shell 7.6.1 (monochrome focus ring + world
surface). All gates green: typecheck:react, build:react (221kB gz), vanilla build,
canary server tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 16:26:47 -07:00

88 lines
3.2 KiB
TypeScript

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { resolve } from 'node:path';
import { readFileSync } from 'node:fs';
// Dedicated Vite config for the React + @hanzo/gui (Tamagui) surface. It is fully
// separate from the shipping vanilla vite.config.ts so the two entries never
// interfere: `npm run build` still builds the vanilla app at index.html untouched,
// while `npm run build:react` builds THIS entry (index.react.html) into dist-react/.
//
// @hanzo/gui is consumed at runtime (no compile-time extraction needed for the
// foundation): @vitejs/plugin-react gives JSX + fast-refresh, and the three knobs
// Tamagui-on-web needs are set below — the react-native → react-native-web alias,
// React de-duplication, and the TAMAGUI_TARGET / __DEV__ defines.
const pkg = JSON.parse(readFileSync(resolve(__dirname, 'package.json'), 'utf8'));
const isDev = process.env.NODE_ENV !== 'production';
export default defineConfig({
root: __dirname,
define: {
__APP_VERSION__: JSON.stringify(pkg.version),
'process.env.TAMAGUI_TARGET': JSON.stringify('web'),
__DEV__: JSON.stringify(isDev),
},
plugins: [react()],
resolve: {
alias: {
'@': resolve(__dirname, 'src'),
// Tamagui/@hanzo/gui primitives resolve react-native APIs at runtime through
// react-native-web on the web.
'react-native': 'react-native-web',
},
// Never let a transitive copy split the React runtime — one instance each.
dedupe: ['react', 'react-dom', 'react-native-web'],
},
optimizeDeps: {
include: ['react', 'react-dom', 'react-dom/client', 'react-native-web'],
esbuildOptions: {
// react-native-web / some @hanzogui packages ship .js containing JSX.
loader: { '.js': 'jsx' },
},
},
build: {
outDir: 'dist-react',
emptyOutDir: true,
rollupOptions: {
input: resolve(__dirname, 'index.react.html'),
output: {
// Split ONLY the always-eager runtime vendors out of the entry chunk. The
// entry had crossed ~402 kB gz because React + the Tamagui/react-native-web
// runtime (what @hanzo/gui is built on) were inlined into it; hoisting them
// into sibling eager chunks shrinks the entry file below target without
// changing load order (these are imported by main/GuiProvider regardless).
//
// CRITICAL: name ONLY these vendors. manualChunks force-hoists a module into
// the named chunk even when it is reached solely via dynamic import — so the
// heavy islands (deck.gl/mapbox behind GlobeIsland, TradingView behind
// FinanceTerminal) are deliberately NOT named here. They stay in Rollup's
// automatic async chunks, keeping the island lazy-load intact.
manualChunks(id) {
if (!id.includes('node_modules')) return undefined;
if (/[\\/]node_modules[\\/](react|react-dom|scheduler)[\\/]/.test(id)) {
return 'react-vendor';
}
if (
/[\\/]node_modules[\\/](react-native-web|@tamagui|tamagui|@hanzo[\\/]gui|@hanzogui)[\\/]/.test(
id,
)
) {
return 'gui-vendor';
}
return undefined;
},
},
},
},
server: {
port: 5273,
},
});