207 lines
5.9 KiB
TypeScript
Executable File
207 lines
5.9 KiB
TypeScript
Executable File
import { cpSync, existsSync, mkdirSync, readdirSync } from 'fs';
|
|
import { join } from 'path';
|
|
import { defineConfig, type ResolvedConfig, type ViteDevServer } from 'vite';
|
|
import react from '@vitejs/plugin-react';
|
|
import { VitePWA } from 'vite-plugin-pwa';
|
|
|
|
const DEV_APP_UPDATE_PATH = '/__app-update';
|
|
const processEnv =
|
|
(
|
|
globalThis as typeof globalThis & {
|
|
process?: {
|
|
env?: Record<string, string | undefined>;
|
|
};
|
|
}
|
|
).process?.env ?? {};
|
|
const VITE_PUBLIC_HMR_HOST = processEnv.VITE_PUBLIC_HMR_HOST ?? 'test.sm-home.cloud';
|
|
const VITE_PUBLIC_HMR_PROTOCOL = processEnv.VITE_PUBLIC_HMR_PROTOCOL ?? 'wss';
|
|
const VITE_PUBLIC_HMR_CLIENT_PORT = Number(processEnv.VITE_PUBLIC_HMR_CLIENT_PORT ?? 443);
|
|
const VITE_EMPTY_OUT_DIR = processEnv.VITE_EMPTY_OUT_DIR !== 'false';
|
|
const VITE_FILTER_PUBLIC_DIR = processEnv.VITE_FILTER_PUBLIC_DIR === 'true';
|
|
const VITE_DISABLE_MODULE_PRELOAD = processEnv.VITE_DISABLE_MODULE_PRELOAD === 'true';
|
|
|
|
function shouldIgnoreDevUpdatePath(watchedPath: string) {
|
|
return (
|
|
watchedPath.includes('/.auto_codex/') ||
|
|
watchedPath.includes('/dist/') ||
|
|
watchedPath.includes('/app-dist/') ||
|
|
watchedPath.includes('/test-app-dist/') ||
|
|
watchedPath.includes('/node_modules/') ||
|
|
watchedPath.includes('/public/.codex_chat/') ||
|
|
watchedPath.endsWith('/.server-command-runner-heartbeat.json')
|
|
);
|
|
}
|
|
|
|
function createDevAppUpdatePlugin() {
|
|
let updateToken = `${Date.now()}`;
|
|
|
|
const bumpUpdateToken = () => {
|
|
updateToken = `${Date.now()}`;
|
|
};
|
|
|
|
const shouldTrackPath = (watchedPath: string) => !shouldIgnoreDevUpdatePath(watchedPath);
|
|
|
|
return {
|
|
name: 'dev-app-update-probe',
|
|
apply: 'serve' as const,
|
|
configureServer(server: ViteDevServer) {
|
|
const handleFileChange = (file: string) => {
|
|
if (shouldTrackPath(file)) {
|
|
bumpUpdateToken();
|
|
}
|
|
};
|
|
|
|
server.watcher.on('add', handleFileChange);
|
|
server.watcher.on('change', handleFileChange);
|
|
server.watcher.on('unlink', handleFileChange);
|
|
|
|
server.middlewares.use(DEV_APP_UPDATE_PATH, (_request, response) => {
|
|
response.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
response.setHeader('Cache-Control', 'no-store');
|
|
response.end(
|
|
JSON.stringify({
|
|
token: updateToken,
|
|
updatedAt: new Date(Number(updateToken)).toISOString(),
|
|
}),
|
|
);
|
|
});
|
|
},
|
|
};
|
|
}
|
|
|
|
function copyPublicAssetsExceptCodexChat() {
|
|
let resolvedConfig: ResolvedConfig | null = null;
|
|
|
|
const copyDirectory = (sourceDir: string, targetDir: string) => {
|
|
if (!existsSync(sourceDir)) {
|
|
return;
|
|
}
|
|
|
|
mkdirSync(targetDir, { recursive: true });
|
|
|
|
for (const entry of readdirSync(sourceDir, { withFileTypes: true })) {
|
|
if (entry.name === '.codex_chat') {
|
|
continue;
|
|
}
|
|
|
|
const sourcePath = join(sourceDir, entry.name);
|
|
const targetPath = join(targetDir, entry.name);
|
|
|
|
if (entry.isDirectory()) {
|
|
copyDirectory(sourcePath, targetPath);
|
|
continue;
|
|
}
|
|
|
|
if (entry.isFile()) {
|
|
mkdirSync(join(targetPath, '..'), { recursive: true });
|
|
cpSync(sourcePath, targetPath, { force: true });
|
|
}
|
|
}
|
|
};
|
|
|
|
return {
|
|
name: 'copy-public-assets-except-codex-chat',
|
|
apply: 'build' as const,
|
|
configResolved(config: ResolvedConfig) {
|
|
resolvedConfig = config;
|
|
},
|
|
closeBundle() {
|
|
if (!VITE_FILTER_PUBLIC_DIR || !resolvedConfig) {
|
|
return;
|
|
}
|
|
|
|
const publicDir = join(resolvedConfig.root, 'public');
|
|
const outDir = resolvedConfig.build.outDir.startsWith('/')
|
|
? resolvedConfig.build.outDir
|
|
: join(resolvedConfig.root, resolvedConfig.build.outDir);
|
|
|
|
copyDirectory(publicDir, outDir);
|
|
},
|
|
};
|
|
}
|
|
|
|
export default defineConfig({
|
|
build: {
|
|
copyPublicDir: !VITE_FILTER_PUBLIC_DIR,
|
|
emptyOutDir: VITE_EMPTY_OUT_DIR,
|
|
modulePreload: VITE_DISABLE_MODULE_PRELOAD ? false : undefined,
|
|
},
|
|
server: {
|
|
host: '0.0.0.0',
|
|
port: 5173,
|
|
hmr: {
|
|
host: VITE_PUBLIC_HMR_HOST,
|
|
protocol: VITE_PUBLIC_HMR_PROTOCOL as 'ws' | 'wss',
|
|
clientPort: VITE_PUBLIC_HMR_CLIENT_PORT,
|
|
},
|
|
allowedHosts: ['sm-home.cloud', 'test.sm-home.cloud', 'rel.sm-home.cloud'],
|
|
watch: {
|
|
ignored: (watchedPath) => shouldIgnoreDevUpdatePath(watchedPath),
|
|
},
|
|
proxy: {
|
|
'/api': {
|
|
target: 'http://work-server:3100',
|
|
changeOrigin: true,
|
|
},
|
|
'/ws/chat': {
|
|
target: 'ws://work-server:3100',
|
|
ws: true,
|
|
changeOrigin: true,
|
|
},
|
|
'/.codex_chat': {
|
|
target: 'http://work-server:3100',
|
|
changeOrigin: true,
|
|
},
|
|
},
|
|
},
|
|
preview: {
|
|
host: '0.0.0.0',
|
|
port: 5173,
|
|
allowedHosts: ['sm-home.cloud', 'test.sm-home.cloud', 'rel.sm-home.cloud'],
|
|
},
|
|
plugins: [
|
|
react(),
|
|
createDevAppUpdatePlugin(),
|
|
copyPublicAssetsExceptCodexChat(),
|
|
VitePWA({
|
|
strategies: 'injectManifest',
|
|
srcDir: 'src',
|
|
filename: 'sw.js',
|
|
registerType: 'prompt',
|
|
includeAssets: ['favicon.svg', 'apple-touch-icon.svg'],
|
|
injectManifest: {
|
|
globPatterns: ['**/*.{js,css,html,ico,png,svg,webp,woff2}'],
|
|
globIgnores: ['**/.codex_chat/**'],
|
|
maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
|
|
},
|
|
manifest: {
|
|
name: 'AI Code App',
|
|
short_name: 'AI Code App',
|
|
description: 'Ant Design 기반 UI 샘플과 문서를 확인하는 AI Code App',
|
|
theme_color: '#165dff',
|
|
background_color: '#eff5ff',
|
|
display: 'standalone',
|
|
lang: 'ko',
|
|
scope: '/',
|
|
start_url: '/',
|
|
icons: [
|
|
{
|
|
src: '/pwa-192x192.svg',
|
|
sizes: '192x192',
|
|
type: 'image/svg+xml',
|
|
},
|
|
{
|
|
src: '/pwa-512x512.svg',
|
|
sizes: '512x512',
|
|
type: 'image/svg+xml',
|
|
purpose: 'any maskable',
|
|
},
|
|
],
|
|
},
|
|
devOptions: {
|
|
enabled: true,
|
|
},
|
|
}),
|
|
],
|
|
});
|