import { rmSync } from 'node:fs'; import path from 'node:path'; import tailwindcss from '@tailwindcss/vite'; import react from '@vitejs/plugin-react'; import postcss from 'postcss'; import { defineConfig, loadEnv, type Plugin } from 'vite'; const RETIRED_TEMPLATE_CSS_PATTERN = /(?:baby-object|bark-battle|big-fish|child-motion|creation-(?:agent|work)|creative-agent|custom-world|jump-hop|match3d|platform-recommend|platform-work-detail|public-work|puzzle|rpg|square-hole|unified-creation|visual-novel|wooden-fish)/iu; const ACTIVE_TAILWIND_SOURCES = `@import 'tailwindcss' source(none); @source "./active-main.tsx"; @source "./ActiveApp.tsx"; @source "./AuthenticatedApp.tsx"; @source "./components/auth"; @source "./components/common"; @source "./components/creation-home"; @source "./components/image-editor"; @source "./components/project"; @source "./components/platform-entry/PlatformEntryFlowShell.tsx"; @source "./components/platform-entry/PlatformEntryActiveFlowShell.tsx"; @source "./components/platform-entry/PlatformProfileModalShell.tsx"; @source "./components/platform-entry/PlatformProfileRechargeModal.tsx"; @source "./components/platform-entry/PlatformProfileWalletLedgerModal.tsx"; @source "./components/platform-entry/PlatformRechargePaymentStatusDialogs.tsx"; @source "./editor"; @source "../packages/shared/src/components";`; const RETIRED_PUBLIC_ASSET_PATHS = [ '/branding/jump-hop-taonier-character.png', '/branding/mobile-home-welcome-taonier-ip.png', '/anthro-cat-illustrations', '/bark-battle-assets', '/character', '/child-motion-demo', '/creation-type-references', '/edutainment-baby-object', '/generated-character-drafts', '/generated-characters', '/generated-qwen-sprites', '/Icons', '/creation-type-references/jump-hop.webp', '/creation-type-references/match3d.webp', '/match3d-background-references', '/match3d-style-references', '/Pixel Monsters Vol1', '/puzzle-creation-templates', '/scene_bg', '/UI', '/ui-previews', '/visual-novel-style-references', '/wooden-fish', ] as const; function isRetiredPublicAssetPath(pathname: string) { return RETIRED_PUBLIC_ASSET_PATHS.some( (prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`), ); } function retiredCreationTemplateAssetsPlugin(): Plugin { return { name: 'retired-creation-template-assets', configureServer(server) { server.middlewares.use((request, response, next) => { const pathname = new URL(request.url ?? '/', 'http://localhost') .pathname; if (!isRetiredPublicAssetPath(pathname)) { next(); return; } response.statusCode = 404; response.end(); }); }, writeBundle(options) { const outputDir = path.resolve(__dirname, options.dir ?? 'dist'); for (const assetPath of RETIRED_PUBLIC_ASSET_PATHS) { rmSync(path.join(outputDir, assetPath.slice(1)), { force: true, recursive: true, }); } }, }; } function retiredCreationTemplateCssPlugin(): Plugin { const stripRetiredCss = (code: string, from: string) => { const root = postcss.parse(code, { from }); root.walkRules((rule) => { if (RETIRED_TEMPLATE_CSS_PATTERN.test(rule.selector)) { rule.remove(); } }); root.walkAtRules((atRule) => { if ( (atRule.name === 'keyframes' || atRule.name === 'source') && RETIRED_TEMPLATE_CSS_PATTERN.test(atRule.params) ) { atRule.remove(); } }); root.walkDecls((declaration) => { if ( RETIRED_TEMPLATE_CSS_PATTERN.test(declaration.prop) || RETIRED_TEMPLATE_CSS_PATTERN.test(declaration.value) ) { declaration.remove(); } }); return root.toString(); }; return { name: 'retired-creation-template-css', enforce: 'pre', transform(code, id) { if ( !id.endsWith('/src/index.css') && !id.endsWith('/packages/shared/src/theme.css') ) { return null; } const activeSourceCode = id.endsWith('/src/index.css') ? code.replace("@import 'tailwindcss';", ACTIVE_TAILWIND_SOURCES) : code; return { code: stripRetiredCss(activeSourceCode, id), map: null }; }, generateBundle(_options, bundle) { Object.values(bundle).forEach((entry) => { if (entry.type !== 'asset' || !entry.fileName.endsWith('.css')) { return; } entry.source = stripRetiredCss( typeof entry.source === 'string' ? entry.source : new TextDecoder().decode(entry.source), entry.fileName, ); }); }, }; } export default defineConfig(({ mode }) => { const env = loadEnv(mode, __dirname, ''); const ignoredWatchGlobs = [ // Prevent a root-level nohup log from triggering a Vite reload loop. '**/nohup.out', '**/.git/**', '**/.worktrees/**', '**/dist/**', '**/dist_check/**', '**/dist_check_final/**', '**/dist_check_monster_position/**', '**/temp*build*/**', '**/public/generated-character-drafts/**', '**/public/generated-characters/**', '**/public/generated-custom-world-scenes/**', '**/public/generated-qwen-sprites/**', '**/public/child-motion-demo/**', '**/public/anthro-cat-illustrations/**', '**/public/bark-battle-assets/**', '**/public/character/**', '**/public/creation-type-references/**', '**/public/edutainment-baby-object/**', '**/public/match3d-background-references/**', '**/public/match3d-style-references/**', '**/public/puzzle-creation-templates/**', '**/public/visual-novel-style-references/**', '**/public/wooden-fish/**', '**/src/components/child-motion-demo/**', '**/src/components/asset-studio/**', '**/src/components/bark-battle-creation/**', '**/src/components/big-fish-*/**', '**/src/components/creation-agent/**', '**/src/components/creative-agent/**', '**/src/components/custom-world-*/**', '**/src/components/edutainment-*/**', '**/src/ChildMotionDemoApp.tsx', '**/src/Match3DPlaygroundApp.tsx', '**/src/components/jump-hop-result/**', '**/src/components/jump-hop-runtime/**', '**/src/components/match3d-result/**', '**/src/components/match3d-runtime/**', '**/src/components/puzzle-*/**', '**/src/components/rpg-creation-*/**', '**/src/components/rpg-runtime-*/**', '**/src/components/square-hole-*/**', '**/src/components/unified-creation/**', '**/src/components/visual-novel-*/**', '**/src/components/wooden-fish-*/**', '**/src/components/platform-entry/platformMatch3DRuntimeProfile*', '**/src/components/unified-creation/workspaces/JumpHopCreationWorkspace*', '**/src/components/unified-creation/workspaces/Match3DCreationWorkspace*', '**/src/services/child-motion-demo/**', '**/src/services/bark-battle-*/**', '**/src/services/big-fish-*/**', '**/src/services/creation-*/**', '**/src/services/creative-agent/**', '**/src/services/edutainment-*/**', '**/src/services/jump-hop/**', '**/src/services/match3d-creation/**', '**/src/services/match3d-runtime/**', '**/src/services/match3d-works/**', '**/src/services/match3dGeneratedModelCache*', '**/src/services/match3dSpritesheetParser*', '**/src/services/puzzle-*/**', '**/src/services/rpg-creation/**', '**/src/services/square-hole-*/**', '**/src/services/visual-novel-*/**', '**/src/services/wooden-fish/**', '**/backend-rewrite-tasklist/**', '**/docs/**', '**/jenkins/**', '**/media/**', '**/scripts/**', '**/server-rs/**', '**/server-rs/target/**', '**/*.test.ts', '**/*.test.tsx', '**/*.spec.ts', '**/*.spec.tsx', ]; const rustServerTarget = env.RUST_SERVER_TARGET || env.GENARRATIVE_API_TARGET || `http://127.0.0.1:${env.GENARRATIVE_API_PORT || '3100'}`; const runtimeServerTarget = env.GENARRATIVE_RUNTIME_SERVER_TARGET || rustServerTarget; const adminWebTarget = env.ADMIN_WEB_TARGET || `http://127.0.0.1:${env.ADMIN_WEB_PORT || '3102'}`; return { root: __dirname, envDir: __dirname, plugins: [ retiredCreationTemplateCssPlugin(), react(), tailwindcss(), retiredCreationTemplateAssetsPlugin(), ], define: { 'process.env.GEMINI_API_KEY': JSON.stringify(env.GEMINI_API_KEY), }, resolve: { alias: { '@': path.resolve(__dirname, '.'), }, }, optimizeDeps: { // Only crawl the real app entry so temporary build folders do not get // treated as extra HTML entrypoints during dependency scanning. entries: ['index.html'], }, build: { chunkSizeWarningLimit: 1000, rollupOptions: { output: { manualChunks(id) { if (id.includes('/node_modules/motion')) { return 'motion-vendor'; } if (id.includes('/src/services/')) { return 'app-services'; } }, }, }, }, server: { allowedHosts: ['outfield-outlook-reprocess.ngrok-free.dev'], // HMR is disabled in AI Studio via DISABLE_HMR env var. // Do not modify; file watching is disabled to prevent flickering during agent edits. hmr: process.env.DISABLE_HMR !== 'true', proxy: { '/admin/': { target: adminWebTarget, changeOrigin: true, secure: false, }, '/api/auth': { target: runtimeServerTarget, changeOrigin: true, secure: false, }, '/api/profile': { target: runtimeServerTarget, changeOrigin: true, secure: false, }, '/api/runtime': { target: runtimeServerTarget, changeOrigin: true, secure: false, }, '/api/editor': { target: runtimeServerTarget, changeOrigin: true, secure: false, }, '/api/assets': { target: runtimeServerTarget, changeOrigin: true, secure: false, }, '/api/llm': { target: runtimeServerTarget, changeOrigin: true, secure: false, }, '/api/ws': { target: runtimeServerTarget, changeOrigin: true, secure: false, ws: true, }, }, watch: { ignored: ignoredWatchGlobs, }, }, }; });