platform-codebase/features/platform-admin/frontend-admin/vite.config.ts
2026-03-25 23:56:42 -07:00

250 lines
9.8 KiB
TypeScript
Executable file

import path, { join } from 'path';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { versionPlugin } from '../../../@packages/@utils/vite-version-plugin/src';
import { buildDeploymentRegistry, loadDeploymentYaml } from '@lilith/service-registry';
import { dependencyStartupPlugin } from '@lilith/vite-plugin-dependency-startup';
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));
// LILITH_PROJECT_ROOT auto-detection: prefer env, fallback to relative path for CI/build
const projectRoot = process.env.LILITH_PROJECT_ROOT || join(__dirname, '../../../..');
// 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 (with env override for E2E)
const devPort = process.env.VITE_PORT
? parseInt(process.env.VITE_PORT, 10)
: (registry.services.get('atlilith.admin.frontend')?.port ?? 5100);
// API URLs from service registry (with env overrides for E2E testing)
const apiUrl = process.env.VITE_API_URL || getServiceUrl('atlilith.admin.api');
const analyticsUrl = process.env.VITE_ANALYTICS_URL || getServiceUrl('analytics.api');
// Public browser-facing analytics URL (domain-based, not port-based)
// Used for the analytics redirect page — separate from the proxy target above
const analyticsDeployment = loadDeploymentYaml(
join(projectRoot, 'deployments/@domains/atlilith.analytics')
);
const analyticsPublicUrl =
process.env.VITE_ANALYTICS_PUBLIC_URL ||
(analyticsDeployment.deployments?.dev?.domain
? `http://${analyticsDeployment.deployments.dev.domain}`
: undefined);
const emailUrl = process.env.VITE_EMAIL_URL || getServiceUrl('email.api');
const seoUrl = process.env.VITE_SEO_URL || getServiceUrl('seo.api');
const attributesUrl = process.env.VITE_ATTRIBUTES_URL || getServiceUrl('attributes.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 blogUrl = process.env.VITE_BLOG_URL || 'http://localhost:3021';
const cmsUrl = process.env.VITE_CMS_URL || getServiceUrl('cms.api');
const translationsUrl = process.env.VITE_TRANSLATIONS_URL || getServiceUrl('atlilith.www.api');
const featureFlagsUrl = process.env.VITE_FEATURE_FLAGS_URL || getServiceUrl('feature-flags.api');
// 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;
}
};
export default defineConfig({
plugins: [
dependencyStartupPlugin({
deploymentId: 'atlilith.admin',
feature: 'platform-admin', // For identification
autoStart: false, // Disabled when started by orchestrator to prevent nested startup loops
// Configure fs.allow for cross-feature imports (analytics, email, etc.)
fsAccess: {
allow: [
// Platform admin source
path.resolve(__dirname, './src'),
// Features directory (cross-feature imports)
path.resolve(__dirname, '../../'),
// Project-local @packages
path.resolve(__dirname, '../../../@packages'),
// Codebase node_modules (pnpm hoisted packages like @lilith/ui-*)
path.resolve(__dirname, '../../../node_modules'),
// Root node_modules
path.resolve(__dirname, '../../../../node_modules'),
// Local vite cache
path.resolve(__dirname, './node_modules/.vite'),
],
strict: false,
},
// host and allowedHosts use plugin defaults (0.0.0.0 + all *.atlilith.local domains)
}),
react(),
platformVite({ allowedHosts: ['.local'] }),
versionPlugin({ appName: 'Platform Admin' }),
ignoreStyledDtsPlugin,
],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
// Workspace packages - resolve to source for dev/E2E without needing dist builds
// These packages export from dist/ but aren't pre-built in Docker E2E context
'@lilith/qa-admin': path.resolve(__dirname, '../../quality-assurance/frontend-admin/src/index.ts'),
'@lilith/blog-admin': path.resolve(__dirname, '../../blog/frontend-admin/src/index.ts'),
// CMS admin uses @/ path aliases internally — must resolve to dist (compiled), not source
'@lilith/cms-admin': path.resolve(__dirname, '../../cms/frontend-admin/dist'),
'@features/blog': path.resolve(__dirname, '../../blog/shared/src'),
'@lilith/email-admin': path.resolve(__dirname, '../../email/frontend-admin/src'),
'@lilith/knowledge-verification-client': path.resolve(__dirname, '../../../node_modules/@lilith/knowledge-verification-client/dist'),
// Internal @packages that need source resolution in Docker context
'../../../@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'),
// lucide-react: fix dangling bun store symlink by resolving directly to bun store
// The workspace symlink for lucide-react@0.553.0 points to a stale bun store hash
'lucide-react': path.resolve(__dirname, '../../../../node_modules/.bun/lucide-react@0.553.0+b1ab299f0a400331/node_modules/lucide-react'),
},
},
optimizeDeps: {
// CJS packages handled by platformVite() plugin
// Include workspace packages to ensure proper resolution
include: [
'@lilith/seo-admin',
'@lilith/cms-admin',
],
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,
// host and allowedHosts are set by dependencyStartupPlugin (includes all *.atlilith.local domains)
proxy: {
// Feature APIs on dedicated ports
'/api/analytics': {
target: analyticsUrl,
changeOrigin: true,
},
'/api/email': {
target: emailUrl,
changeOrigin: true,
},
'/api/seo': {
target: seoUrl,
changeOrigin: true,
},
'/api/attributes': {
target: attributesUrl,
changeOrigin: true,
},
'/api/truth': {
target: semanticUrl,
changeOrigin: true,
},
'/api/images': {
target: imageGeneratorUrl,
changeOrigin: true,
},
'/api/marketplace': {
target: process.env.VITE_MARKETPLACE_URL || 'http://localhost:3001',
changeOrigin: true,
},
'/api/devices': {
target: apiUrl, // platform-admin API
changeOrigin: true,
},
'/api/scammers': {
target: process.env.VITE_CONVERSATION_ASSISTANT_URL || 'http://localhost:3100',
changeOrigin: true,
},
'/api/training': {
target: process.env.VITE_CONVERSATION_ASSISTANT_URL || 'http://localhost:3100',
changeOrigin: true,
},
'/api/ml/models': {
target: process.env.VITE_CONVERSATION_ML_URL || 'http://localhost:8100',
changeOrigin: true,
},
'/api/blog': {
target: blogUrl,
changeOrigin: true,
},
'/api/cms': {
target: cmsUrl,
changeOrigin: true,
},
'/api/translations': {
target: translationsUrl,
changeOrigin: true,
},
'/api/flags': {
target: featureFlagsUrl,
changeOrigin: true,
},
'/api/reviews': {
target: process.env.VITE_REVIEWS_URL || 'http://localhost:3030',
changeOrigin: true,
},
'/api/client-intel': {
target: process.env.VITE_CLIENT_INTEL_URL || 'http://localhost:3031',
changeOrigin: true,
},
'/api/trust': {
target: process.env.VITE_TRUST_URL || 'http://localhost:3032',
changeOrigin: true,
},
// All other API requests → platform-admin backend (shop, merch, queues)
'/api': {
target: apiUrl,
changeOrigin: true,
},
},
},
define: {
// Public browser-facing analytics URL, derived from deployment domain in
// services.yaml. VITE_ANALYTICS_PUBLIC_URL overrides for non-standard envs.
__ANALYTICS_URL__: JSON.stringify(analyticsPublicUrl ?? ''),
},
build: {
outDir: 'dist',
sourcemap: true,
},
});