platform-codebase/features/platform-content-tools/frontend-dev/vite.config.ts
Lilith 560e46c8d5 chore(frontend): 🔧 Standardize Vite, Vitest, and TypeScript configurations
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-02-27 15:06:52 -08:00

210 lines
7 KiB
TypeScript

import { join } from 'path';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import fs from 'fs';
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
import { versionPlugin } from '../../../@packages/@utils/vite-version-plugin/src';
import { buildDeploymentRegistry } from '@lilith/service-registry';
import { platformVite } from '@lilith/build-core';
// =============================================================================
// Service Configuration - loaded from deployment-centric services.yaml
// =============================================================================
// __dirname for path.resolve aliases (still needed for Vite resolve.alias)
const __dirname = dirname(fileURLToPath(import.meta.url));
// Fail-fast: LILITH_PROJECT_ROOT required - start services via ./run dev
if (!process.env.LILITH_PROJECT_ROOT) {
throw new Error(
'LILITH_PROJECT_ROOT not set. Start services via ./run dev to ensure env var is set.'
);
}
const projectRoot = process.env.LILITH_PROJECT_ROOT;
// Build deployment registry - paths resolved via LILITH_PROJECT_ROOT env var
const registry = buildDeploymentRegistry({
deploymentsPath: join(projectRoot, 'deployments/@domains'),
sharedServicesPath: join(projectRoot, 'deployments/shared-services'),
});
// Helper to get service URL from registry
function getServiceUrl(serviceId: string): string {
const service = registry.services.get(serviceId);
if (!service) return `http://localhost:3000`; // fallback
return `http://localhost:${service.port}`;
}
// Port for this frontend (dev tool - uses env override or hardcoded default)
const devPort = process.env.VITE_PORT
? parseInt(process.env.VITE_PORT, 10)
: 5150; // platform-content-tools dev port
// API URLs from service registry - reuses platform-admin API backend
const platformAdminApiUrl = process.env.VITE_API_URL || getServiceUrl('atlilith.admin.api');
const seoUrl = process.env.VITE_SEO_URL || getServiceUrl('seo.api');
const imageGeneratorUrl = process.env.VITE_IMAGE_GENERATOR_URL || getServiceUrl('image-generator.api');
const semanticUrl = process.env.VITE_SEMANTIC_URL || getServiceUrl('knowledge-verification.api');
const conversationAssistantUrl = process.env.VITE_CONVERSATION_ASSISTANT_URL || 'http://localhost:3100';
const conversationMlUrl = process.env.VITE_CONVERSATION_ML_URL || 'http://localhost:8100';
// Plugin to handle .d.ts imports (fixes broken styled.d.ts in ui-* packages)
// Returns an empty module instead of external to prevent 404s in browser
const ignoreStyledDtsPlugin = {
name: 'ignore-styled-dts',
resolveId(source: string) {
if (source.endsWith('.d.ts') || source === './styled.d.ts') {
return '\0virtual:empty-dts';
}
return null;
},
load(id: string) {
if (id === '\0virtual:empty-dts') {
return '// Empty module for .d.ts import';
}
return null;
}
};
// Plugin to resolve @/ imports based on importer's feature location
const featureAliasPlugin = {
name: 'feature-alias-resolver',
resolveId(source: string, importer: string | undefined) {
if (!source.startsWith('@/') || !importer) return null;
// Map of feature paths to their src directories
const featureMap: Record<string, string> = {
'seo/frontend-admin': path.resolve(__dirname, '../../seo/frontend-admin/src'),
'knowledge-verification/frontend-admin': path.resolve(__dirname, '../../knowledge-verification/frontend-admin/src'),
};
// Find which feature the importer belongs to
let srcPath = path.resolve(__dirname, './src'); // default
for (const [featurePath, featureSrcPath] of Object.entries(featureMap)) {
if (importer.includes(featurePath)) {
srcPath = featureSrcPath;
break;
}
}
const relativePath = source.slice(2); // Remove @/
let resolvedPath = path.resolve(srcPath, relativePath);
// Check if it's a directory and look for index file
try {
const stat = fs.statSync(resolvedPath);
if (stat.isDirectory()) {
// Try index.tsx first, then index.ts
for (const ext of ['.tsx', '.ts', '.js']) {
const indexPath = path.join(resolvedPath, `index${ext}`);
if (fs.existsSync(indexPath)) {
return indexPath;
}
}
}
} catch {
// Path doesn't exist yet, try adding extensions
for (const ext of ['.tsx', '.ts', '.js']) {
const withExt = resolvedPath + ext;
if (fs.existsSync(withExt)) {
return withExt;
}
}
}
return resolvedPath;
}
};
export default defineConfig({
plugins: [
featureAliasPlugin,
react(),
platformVite({ allowedHosts: ['.local'] }),
versionPlugin({ appName: 'Platform Content Tools' }),
ignoreStyledDtsPlugin,
],
resolve: {
alias: {
// @/ is handled by featureAliasPlugin
// Internal @packages that need source resolution
'../../../@packages/@utils/vite-version-plugin/src/console': path.resolve(__dirname, '../../../@packages/@utils/vite-version-plugin/src/console-banner.ts'),
'../../../@packages/@utils/vite-version-plugin/src': path.resolve(__dirname, '../../../@packages/@utils/vite-version-plugin/src'),
},
},
optimizeDeps: {
esbuildOptions: {
// Replace .d.ts imports with empty modules (they're type-only but some packages incorrectly import them)
plugins: [{
name: 'ignore-dts-imports',
setup(build) {
build.onResolve({ filter: /\.d\.ts$/ }, (args) => ({
path: args.path,
namespace: 'empty-dts',
}));
build.onLoad({ filter: /.*/, namespace: 'empty-dts' }, () => ({
contents: '// Empty module for .d.ts import',
loader: 'js',
}));
}
}]
}
},
server: {
port: devPort,
allowedHosts: ['platform-content-tools'],
proxy: {
// SEO admin API
'/api/seo': {
target: seoUrl,
changeOrigin: true,
},
// Truth validation API
'/api/truth': {
target: semanticUrl,
changeOrigin: true,
},
// Image generator API
'/api/images': {
target: imageGeneratorUrl,
changeOrigin: true,
},
// Conversation assistant API (scammers, training)
'/api/scammers': {
target: conversationAssistantUrl,
changeOrigin: true,
},
'/api/training': {
target: conversationAssistantUrl,
changeOrigin: true,
},
// ML models API
'/api/ml/models': {
target: conversationMlUrl,
changeOrigin: true,
},
// Asset storage API (via platform-admin backend)
'/api/asset-storage': {
target: platformAdminApiUrl,
changeOrigin: true,
},
// LLM proxy API (via platform-admin backend)
'/api/llm': {
target: platformAdminApiUrl,
changeOrigin: true,
},
// All other API requests → platform-admin backend
'/api': {
target: platformAdminApiUrl,
changeOrigin: true,
},
},
},
build: {
outDir: 'dist',
sourcemap: true,
},
});