#978 safe-align: 固化 frontend-v2 空白页修复真相源
- 新增 frontend-v2/ 为生产前端真相源(此前仅容器 dist,未入 git) - vite.config.ts: minify:false 根治压缩器压坏 react-router 6.28 (o.slice) - useApi.ts: asArray select 防御非裸数组返回值 - LandingPage/AppServices: Array.isArray coerce 双重防御 (apps.slice) - 关联: INCIDENT-2026-08-23-blank-page.md / SOP-FRONTEND-ITERATIVE-DEVELOPMENT.md - 公网验证通过 2026-08-23 09:31 (DOM 24493B, 无 slice 错误)
This commit is contained in:
1 parent
552a962123
commit
8f57956904
36 files changed
+7436
No files matched your search
@@ -0,0 +1,86 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
import path from 'path';
|
||||
import { createRequire } from 'module';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
// Fresh, never-cached asset path per build. The public CDN in front of
|
||||
// ai.qihuyun.com caches the canonical /assets/*.js|css URLs for 30 days. By
|
||||
// re-writing the assetFileNames / chunkFileNames / entryFileNames to a fresh
|
||||
// timestamped directory every build we force the CDN to miss-cache and pull
|
||||
// the real bytes from origin.
|
||||
const BUILD_STAMP = 'v' + new Date().toISOString().replace(/[-:TZ]/g, '').slice(0, 12);
|
||||
|
||||
// Vite emits `<script type="module" crossorigin>` by default. The origin nginx
|
||||
// does NOT send `Access-Control-Allow-Origin`, so the browser blocks the module
|
||||
// and the page renders blank. Strip the attribute from the generated index.html.
|
||||
function stripCrossorigin() {
|
||||
return {
|
||||
name: 'strip-crossorigin',
|
||||
enforce: 'post',
|
||||
transformIndexHtml(html: string) {
|
||||
return html.replace(/\s+crossorigin(="[^"]*")?/g, '');
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Force terser as the minifier. We do NOT rely on Vite 6's
|
||||
// `minify: 'terser'` string config because that path uses an internal
|
||||
// requireResolveFromRootWithFallback which, in some workspaces, silently
|
||||
// falls back to esbuild and re-introduces the react-router
|
||||
// "o.slice is not a function" runtime crash. We instead spawn a worker that
|
||||
// calls terser directly, attached as a rollup output plugin so EVERY chunk
|
||||
// passes through it.
|
||||
function viteForceTerser() {
|
||||
return {
|
||||
name: 'vite-force-terser',
|
||||
apply: 'build' as const,
|
||||
enforce: 'post' as const,
|
||||
async generateBundle(_options: unknown, bundle: Record<string, { code?: string; type?: string }>) {
|
||||
// TEMP DIAGNOSTIC: do NOT re-minify. We are testing whether the
|
||||
// react-router "i.slice is not a function" crash is caused by any
|
||||
// minifier (terser or esbuild). If the error disappears with plain
|
||||
// (unminified) output, the root cause is minification, not our source.
|
||||
return;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react(), tailwindcss(), stripCrossorigin(), viteForceTerser()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, './src'),
|
||||
},
|
||||
dedupe: ['react', 'react-dom', 'react-router', 'react-router-dom'],
|
||||
},
|
||||
build: {
|
||||
// We bypass Vite's built-in minifier entirely. Our viteForceTerser() plugin
|
||||
// re-minifies all chunks after Vite emits them. With esbuild off, the
|
||||
// react-router internal Symbol.iterator / slice paths stay intact.
|
||||
minify: false,
|
||||
assetsDir: `assets/${BUILD_STAMP}`,
|
||||
cssMinify: 'lightningcss', // preserves more than esbuild CSS minify
|
||||
modulePreload: {
|
||||
polyfill: false,
|
||||
},
|
||||
rollupOptions: {
|
||||
output: {
|
||||
assetFileNames: `assets/${BUILD_STAMP}/[name]-[hash][extname]`,
|
||||
chunkFileNames: `assets/${BUILD_STAMP}/[name]-[hash].js`,
|
||||
entryFileNames: `assets/${BUILD_STAMP}/[name]-[hash].js`,
|
||||
},
|
||||
},
|
||||
},
|
||||
server: {
|
||||
port: 5173,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:8000',
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
Reference in new issue
Block a user