Files
low-code-react-app-b/src/lib/route-preload-manager.ts

182 lines
5.4 KiB
TypeScript

import { getEnabledPages } from '@/config/page-loader'
import { preloadComponentByName, ComponentName } from '@/lib/component-registry'
import { FeatureToggles } from '@/types/project'
import { preloadLibrary } from '@/lib/library-loader'
interface PreloadStrategy {
preloadAdjacent: boolean
preloadPopular: boolean
maxConcurrentPreloads: number
}
const DEFAULT_STRATEGY: PreloadStrategy = {
preloadAdjacent: true,
preloadPopular: true,
maxConcurrentPreloads: 3,
}
const popularRoutes = new Set(['dashboard', 'editor', 'models', 'components'])
const preloadQueue: Array<() => void> = []
let activePreloads = 0
function processPreloadQueue(strategy: PreloadStrategy) {
while (activePreloads < strategy.maxConcurrentPreloads && preloadQueue.length > 0) {
const preload = preloadQueue.shift()
if (preload) {
activePreloads++
preload()
setTimeout(() => {
activePreloads--
processPreloadQueue(strategy)
}, 100)
}
}
}
export class RoutePreloadManager {
private strategy: PreloadStrategy
private preloadedRoutes = new Set<string>()
private currentRoute: string | null = null
private featureToggles: FeatureToggles | null = null
constructor(strategy: Partial<PreloadStrategy> = {}) {
this.strategy = { ...DEFAULT_STRATEGY, ...strategy }
console.log('[PRELOAD_MGR] 🎯 RoutePreloadManager initialized with strategy:', this.strategy)
}
setFeatureToggles(featureToggles: FeatureToggles) {
this.featureToggles = featureToggles
console.log('[PRELOAD_MGR] ⚙️ Feature toggles set')
}
setCurrentRoute(route: string) {
console.log(`[PRELOAD_MGR] 📍 Current route changed: ${this.currentRoute}${route}`)
this.currentRoute = route
if (this.strategy.preloadAdjacent) {
this.preloadAdjacentRoutes(route)
}
}
preloadRoute(pageId: string, priority: 'high' | 'low' = 'low') {
if (this.preloadedRoutes.has(pageId)) {
console.log(`[PRELOAD_MGR] ✅ Route ${pageId} already preloaded`)
return
}
console.log(`[PRELOAD_MGR] 🎯 Queuing preload for route: ${pageId} (priority: ${priority})`)
const preloadFn = () => {
if (this.preloadedRoutes.has(pageId)) return
const pages = getEnabledPages(this.featureToggles || undefined)
const page = pages.find(p => p.id === pageId)
if (!page) {
console.warn(`[PRELOAD_MGR] ⚠️ Page not found: ${pageId}`)
return
}
try {
const componentName = page.component as ComponentName
console.log(`[PRELOAD_MGR] 🚀 Preloading ${pageId}${componentName}`)
preloadComponentByName(componentName)
if (page.requiresResizable && page.resizableConfig) {
const leftComponentName = page.resizableConfig.leftComponent as ComponentName
console.log(`[PRELOAD_MGR] 🚀 Preloading left panel: ${leftComponentName}`)
preloadComponentByName(leftComponentName)
}
this.preloadedRoutes.add(pageId)
console.log(`[PRELOAD_MGR] ✅ Route ${pageId} preloaded`)
} catch (error) {
console.error(`[PRELOAD_MGR] ❌ Failed to preload ${pageId}:`, error)
}
}
if (priority === 'high') {
preloadQueue.unshift(preloadFn)
} else {
preloadQueue.push(preloadFn)
}
processPreloadQueue(this.strategy)
}
preloadAdjacentRoutes(currentRoute: string) {
if (!this.featureToggles) {
console.warn('[PRELOAD_MGR] ⚠️ Cannot preload adjacent routes: feature toggles not set')
return
}
const pages = getEnabledPages(this.featureToggles)
const currentIndex = pages.findIndex(p => p.id === currentRoute)
if (currentIndex === -1) {
console.warn(`[PRELOAD_MGR] ⚠️ Current route not found in enabled pages: ${currentRoute}`)
return
}
console.log(`[PRELOAD_MGR] 🔄 Preloading adjacent routes to ${currentRoute}`)
if (currentIndex > 0) {
const prevPage = pages[currentIndex - 1]
console.log(`[PRELOAD_MGR] ← Preloading previous route: ${prevPage.id}`)
this.preloadRoute(prevPage.id, 'low')
}
if (currentIndex < pages.length - 1) {
const nextPage = pages[currentIndex + 1]
console.log(`[PRELOAD_MGR] → Preloading next route: ${nextPage.id}`)
this.preloadRoute(nextPage.id, 'low')
}
}
preloadPopularRoutes() {
if (!this.strategy.preloadPopular) {
console.log('[PRELOAD_MGR] ⏭️ Popular route preloading disabled')
return
}
console.log('[PRELOAD_MGR] ⭐ Preloading popular routes')
popularRoutes.forEach(route => {
if (!this.preloadedRoutes.has(route)) {
this.preloadRoute(route, 'low')
}
})
}
preloadLibraries(libraries: Array<'recharts' | 'd3' | 'three' | 'reactflow'>) {
console.log('[PRELOAD_MGR] 📚 Preloading libraries:', libraries)
libraries.forEach(lib => {
preloadLibrary(lib)
})
}
isPreloaded(pageId: string): boolean {
return this.preloadedRoutes.has(pageId)
}
reset() {
console.log('[PRELOAD_MGR] 🔄 Resetting preload manager')
this.preloadedRoutes.clear()
this.currentRoute = null
preloadQueue.length = 0
activePreloads = 0
}
getStats() {
return {
preloadedCount: this.preloadedRoutes.size,
queuedCount: preloadQueue.length,
activePreloads,
currentRoute: this.currentRoute,
}
}
}
export const routePreloadManager = new RoutePreloadManager()