diff --git a/vite.config.ts b/vite.config.ts index a84cb6c..8bf55d1 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,5 +1,6 @@ import tailwindcss from '@tailwindcss/vite'; import react from '@vitejs/plugin-react'; +import fs from 'fs'; import path from 'path'; import {defineConfig, loadEnv} from 'vite'; import { supabaseSync } from './plugins/vite-plugin-supabase-sync'; @@ -54,6 +55,26 @@ export default defineConfig(({mode}) => { return { plugins: [ react(), + { + // 루트 /favicon.ico. 미리보기 카드와 일부 브라우저는 을 보지 않고 루트를 그대로 요청한다. + // vercel.json 의 SPA 리라이트가 모든 경로를 index.html 로 보내므로, 파일이 없으면 HTML 이 아이콘 자리에 온다. + // public/ 은 infinith-demo 배포와 공용이라 파일명을 나눠 두었고, 빌드 때 이 배포의 것만 루트 이름으로 복사한다. + name: 'infinith-root-favicon', + apply: 'build' as const, + writeBundle(options: {dir?: string}) { + if (!isDiscovery) return; + const out = options.dir ?? 'dist'; + for (const [from, to] of [ + ['discovery-favicon.ico', 'favicon.ico'], + ['discovery-favicon-32.png', 'favicon-32.png'], + ['discovery-favicon-192.png', 'favicon-192.png'], + ['discovery-apple-touch-icon.png', 'apple-touch-icon.png'], + ]) { + const src = path.resolve(out, from); + if (fs.existsSync(src)) fs.copyFileSync(src, path.resolve(out, to)); + } + }, + }, { name: 'infinith-head', transformIndexHtml(html: string) {