210 lines
7 KiB
TypeScript
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,
|
|
},
|
|
});
|