9.1 服务端渲染缓存策略
9.1.1 多级缓存架构
// cache/CacheManager.js
const LRU = require('lru-cache')
const Redis = require('ioredis')
const crypto = require('crypto')
class CacheManager {
constructor(options = {}) {
this.options = {
redis: {
host: process.env.REDIS_HOST || 'localhost',
port: process.env.REDIS_PORT || 6379,
password: process.env.REDIS_PASSWORD,
db: 0
},
memory: {
max: 1000,
maxAge: 5 * 60 * 1000 // 5分钟
},
page: {
max: 5000,
maxAge: 15 * 60 * 1000 // 15分钟
},
component: {
max: 10000,
maxAge: 30 * 60 * 1000 // 30分钟
},
...options
}
this.initializeCaches()
}
initializeCaches() {
// Redis缓存
this.redis = new Redis(this.options.redis)
// 内存缓存
this.memoryCache = new LRU(this.options.memory)
// 页面缓存
this.pageCache = new LRU(this.options.page)
// 组件缓存
this.componentCache = new LRU(this.options.component)
// 数据缓存
this.dataCache = new LRU({
max: 2000,
maxAge: 10 * 60 * 1000 // 10分钟
})
}
// 生成缓存键
generateKey(prefix, data) {
const hash = crypto
.createHash('md5')
.update(JSON.stringify(data))
.digest('hex')
return `${prefix}:${hash}`
}
// 页面缓存
async getPage(key) {
// 先检查内存缓存
let cached = this.pageCache.get(key)
if (cached) {
return { data: cached, source: 'memory' }
}
// 检查Redis缓存
try {
cached = await this.redis.get(`page:${key}`)
if (cached) {
const data = JSON.parse(cached)
// 回写到内存缓存
this.pageCache.set(key, data)
return { data, source: 'redis' }
}
} catch (error) {
console.error('Redis get error:', error)
}
return null
}
async setPage(key, data, ttl = 900) {
// 设置内存缓存
this.pageCache.set(key, data)
// 设置Redis缓存
try {
await this.redis.setex(`page:${key}`, ttl, JSON.stringify(data))
} catch (error) {
console.error('Redis set error:', error)
}
}
// 组件缓存
getComponent(key) {
return this.componentCache.get(key)
}
setComponent(key, data) {
this.componentCache.set(key, data)
}
// 数据缓存
async getData(key) {
// 先检查内存
let cached = this.dataCache.get(key)
if (cached) {
return { data: cached, source: 'memory' }
}
// 检查Redis
try {
cached = await this.redis.get(`data:${key}`)
if (cached) {
const data = JSON.parse(cached)
this.dataCache.set(key, data)
return { data, source: 'redis' }
}
} catch (error) {
console.error('Redis get error:', error)
}
return null
}
async setData(key, data, ttl = 600) {
this.dataCache.set(key, data)
try {
await this.redis.setex(`data:${key}`, ttl, JSON.stringify(data))
} catch (error) {
console.error('Redis set error:', error)
}
}
// 智能缓存失效
async invalidate(pattern) {
// 清除内存缓存
if (pattern.includes('page')) {
this.pageCache.reset()
}
if (pattern.includes('component')) {
this.componentCache.reset()
}
if (pattern.includes('data')) {
this.dataCache.reset()
}
// 清除Redis缓存
try {
const keys = await this.redis.keys(pattern)
if (keys.length > 0) {
await this.redis.del(...keys)
}
} catch (error) {
console.error('Redis invalidate error:', error)
}
}
// 缓存统计
getStats() {
return {
memory: {
size: this.memoryCache.length,
max: this.memoryCache.max
},
page: {
size: this.pageCache.length,
max: this.pageCache.max
},
component: {
size: this.componentCache.length,
max: this.componentCache.max
},
data: {
size: this.dataCache.length,
max: this.dataCache.max
}
}
}
// 预热缓存
async warmup(routes) {
console.log('开始缓存预热...')
for (const route of routes) {
try {
// 这里可以调用渲染函数来预热页面缓存
console.log(`预热路由: ${route}`)
// await this.renderAndCache(route)
} catch (error) {
console.error(`预热失败 ${route}:`, error)
}
}
console.log('缓存预热完成')
}
}
module.exports = CacheManager
9.1.2 智能缓存策略
// cache/SmartCache.js
class SmartCache {
constructor(cacheManager) {
this.cache = cacheManager
this.hitRates = new Map()
this.accessPatterns = new Map()
}
// 记录访问模式
recordAccess(key, hit = false) {
const now = Date.now()
// 记录命中率
if (!this.hitRates.has(key)) {
this.hitRates.set(key, { hits: 0, total: 0 })
}
const stats = this.hitRates.get(key)
stats.total++
if (hit) stats.hits++
// 记录访问模式
if (!this.accessPatterns.has(key)) {
this.accessPatterns.set(key, [])
}
const pattern = this.accessPatterns.get(key)
pattern.push(now)
// 只保留最近1小时的访问记录
const oneHourAgo = now - 60 * 60 * 1000
this.accessPatterns.set(key, pattern.filter(time => time > oneHourAgo))
}
// 计算缓存优先级
calculatePriority(key) {
const hitRate = this.getHitRate(key)
const frequency = this.getAccessFrequency(key)
const recency = this.getRecency(key)
// 综合评分:命中率 * 0.4 + 访问频率 * 0.4 + 最近访问 * 0.2
return hitRate * 0.4 + frequency * 0.4 + recency * 0.2
}
getHitRate(key) {
const stats = this.hitRates.get(key)
if (!stats || stats.total === 0) return 0
return stats.hits / stats.total
}
getAccessFrequency(key) {
const pattern = this.accessPatterns.get(key)
if (!pattern) return 0
const now = Date.now()
const oneHourAgo = now - 60 * 60 * 1000
const recentAccesses = pattern.filter(time => time > oneHourAgo)
return recentAccesses.length / 60 // 每分钟访问次数
}
getRecency(key) {
const pattern = this.accessPatterns.get(key)
if (!pattern || pattern.length === 0) return 0
const lastAccess = Math.max(...pattern)
const now = Date.now()
const timeDiff = now - lastAccess
// 最近访问的权重更高
return Math.max(0, 1 - timeDiff / (60 * 60 * 1000))
}
// 智能TTL计算
calculateTTL(key, baseTime = 300) {
const priority = this.calculatePriority(key)
const frequency = this.getAccessFrequency(key)
// 高优先级和高频访问的内容缓存时间更长
let ttl = baseTime
if (priority > 0.8) {
ttl *= 3 // 高优先级缓存3倍时间
} else if (priority > 0.5) {
ttl *= 2 // 中等优先级缓存2倍时间
}
if (frequency > 10) {
ttl *= 2 // 高频访问缓存2倍时间
}
return Math.min(ttl, 3600) // 最大1小时
}
// 预测性缓存
async predictiveCache(userContext) {
const predictions = this.predictNextPages(userContext)
for (const prediction of predictions) {
if (prediction.probability > 0.7) {
// 预加载高概率页面
await this.preloadPage(prediction.route)
}
}
}
predictNextPages(userContext) {
// 基于用户行为预测下一个可能访问的页面
const { currentRoute, userAgent, referrer, sessionData } = userContext
const predictions = []
// 基于路由模式预测
if (currentRoute === '/products') {
predictions.push({
route: '/products/category/electronics',
probability: 0.6,
reason: 'common_navigation'
})
}
if (currentRoute.startsWith('/product/')) {
predictions.push({
route: '/cart',
probability: 0.4,
reason: 'purchase_flow'
})
}
// 基于用户历史行为预测
if (sessionData && sessionData.viewedCategories) {
sessionData.viewedCategories.forEach(category => {
predictions.push({
route: `/products/category/${category}`,
probability: 0.3,
reason: 'user_interest'
})
})
}
return predictions.sort((a, b) => b.probability - a.probability)
}
async preloadPage(route) {
try {
// 检查是否已缓存
const cacheKey = this.cache.generateKey('page', { route })
const cached = await this.cache.getPage(cacheKey)
if (!cached) {
// 异步预加载
setTimeout(async () => {
try {
// 这里调用实际的渲染函数
console.log(`预加载页面: ${route}`)
// await renderPage(route)
} catch (error) {
console.error(`预加载失败 ${route}:`, error)
}
}, 100)
}
} catch (error) {
console.error(`预加载错误 ${route}:`, error)
}
}
// 缓存分析报告
generateReport() {
const report = {
timestamp: new Date().toISOString(),
totalKeys: this.hitRates.size,
topPerformers: [],
lowPerformers: [],
recommendations: []
}
// 分析性能
for (const [key, stats] of this.hitRates.entries()) {
const hitRate = stats.hits / stats.total
const frequency = this.getAccessFrequency(key)
const priority = this.calculatePriority(key)
const item = { key, hitRate, frequency, priority }
if (hitRate > 0.8 && frequency > 5) {
report.topPerformers.push(item)
} else if (hitRate < 0.3 && frequency > 1) {
report.lowPerformers.push(item)
}
}
// 生成建议
if (report.lowPerformers.length > 0) {
report.recommendations.push({
type: 'cache_strategy',
message: `发现${report.lowPerformers.length}个低效缓存项,建议调整缓存策略`
})
}
if (report.topPerformers.length > 10) {
report.recommendations.push({
type: 'cache_expansion',
message: '高效缓存项较多,建议增加缓存容量'
})
}
return report
}
}
module.exports = SmartCache
9.2 流式渲染
9.2.1 流式SSR实现
// streaming/StreamRenderer.js
const { Readable } = require('stream')
const { createBundleRenderer } = require('vue-server-renderer')
class StreamRenderer {
constructor(serverBundle, options = {}) {
this.renderer = createBundleRenderer(serverBundle, {
...options,
runInNewContext: false
})
}
// 流式渲染
renderToStream(context) {
return new Promise((resolve, reject) => {
const stream = this.renderer.renderToStream(context)
const chunks = []
stream.on('data', chunk => {
chunks.push(chunk)
})
stream.on('end', () => {
resolve(Buffer.concat(chunks).toString())
})
stream.on('error', reject)
})
}
// 渐进式流式渲染
async progressiveRender(context, res) {
try {
// 发送HTML头部
const htmlStart = this.getHTMLStart(context)
res.write(htmlStart)
// 创建渲染流
const renderStream = this.renderer.renderToStream(context)
// 处理流数据
renderStream.on('data', chunk => {
res.write(chunk)
})
renderStream.on('end', () => {
// 发送HTML尾部
const htmlEnd = this.getHTMLEnd(context)
res.write(htmlEnd)
res.end()
})
renderStream.on('error', error => {
console.error('Stream render error:', error)
res.status(500).end('Render Error')
})
} catch (error) {
console.error('Progressive render error:', error)
res.status(500).end('Server Error')
}
}
// 分块渲染
async chunkRender(context, res) {
const chunks = await this.getChunks(context)
// 发送初始HTML
res.write(this.getHTMLStart(context))
// 逐个渲染组件块
for (const chunk of chunks) {
try {
const html = await this.renderChunk(chunk, context)
res.write(html)
// 添加延迟以模拟渐进加载
if (chunk.priority === 'low') {
await this.delay(50)
}
} catch (error) {
console.error(`Chunk render error for ${chunk.name}:`, error)
res.write(`<!-- Error rendering ${chunk.name} -->`)
}
}
res.write(this.getHTMLEnd(context))
res.end()
}
async getChunks(context) {
// 分析路由组件,确定渲染优先级
const route = context.url
const chunks = [
{
name: 'header',
component: 'AppHeader',
priority: 'high',
critical: true
},
{
name: 'navigation',
component: 'AppNavigation',
priority: 'high',
critical: true
},
{
name: 'main-content',
component: 'MainContent',
priority: 'high',
critical: true
},
{
name: 'sidebar',
component: 'AppSidebar',
priority: 'medium',
critical: false
},
{
name: 'footer',
component: 'AppFooter',
priority: 'low',
critical: false
}
]
// 根据路由调整优先级
if (route.startsWith('/product/')) {
chunks.find(c => c.name === 'main-content').priority = 'critical'
}
return chunks.sort((a, b) => {
const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 }
return priorityOrder[a.priority] - priorityOrder[b.priority]
})
}
async renderChunk(chunk, context) {
// 这里实现具体的组件渲染逻辑
// 可以使用缓存、并行渲染等优化技术
const cacheKey = `chunk:${chunk.name}:${context.url}`
// 检查缓存
if (this.cache) {
const cached = await this.cache.getComponent(cacheKey)
if (cached) {
return cached
}
}
// 渲染组件
const html = await this.renderComponent(chunk.component, context)
// 缓存结果
if (this.cache && !chunk.critical) {
await this.cache.setComponent(cacheKey, html)
}
return html
}
async renderComponent(componentName, context) {
// 模拟组件渲染
return `<div class="${componentName.toLowerCase()}">
<!-- ${componentName} content -->
</div>`
}
getHTMLStart(context) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>${context.title || 'Vue SSR App'}</title>
${context.renderResourceHints()}
${context.renderStyles()}
</head>
<body>
<div id="app">`
}
getHTMLEnd(context) {
return ` </div>
${context.renderState()}
${context.renderScripts()}
</body>
</html>`
}
delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
}
module.exports = StreamRenderer
9.2.2 客户端流式激活
// client/streaming-hydration.js
class StreamingHydration {
constructor() {
this.pendingComponents = new Set()
this.hydratedComponents = new Set()
this.observers = new Map()
}
// 初始化流式激活
init() {
this.setupIntersectionObserver()
this.setupMutationObserver()
this.startHydration()
}
// 设置交叉观察器
setupIntersectionObserver() {
if (!window.IntersectionObserver) return
this.intersectionObserver = new IntersectionObserver(
(entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
this.hydrateComponent(entry.target)
}
})
},
{
rootMargin: '50px 0px',
threshold: 0.1
}
)
}
// 设置变化观察器
setupMutationObserver() {
this.mutationObserver = new MutationObserver((mutations) => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.nodeType === Node.ELEMENT_NODE) {
this.scanForComponents(node)
}
})
})
})
this.mutationObserver.observe(document.body, {
childList: true,
subtree: true
})
}
// 开始激活过程
startHydration() {
// 优先激活关键组件
this.hydrateCriticalComponents()
// 延迟激活非关键组件
requestIdleCallback(() => {
this.hydrateNonCriticalComponents()
})
}
// 激活关键组件
hydrateCriticalComponents() {
const criticalComponents = document.querySelectorAll('[data-critical="true"]')
criticalComponents.forEach(element => {
this.hydrateComponent(element)
})
}
// 激活非关键组件
hydrateNonCriticalComponents() {
const nonCriticalComponents = document.querySelectorAll('[data-component]:not([data-critical="true"])')
nonCriticalComponents.forEach(element => {
if (this.isInViewport(element)) {
this.hydrateComponent(element)
} else {
this.intersectionObserver.observe(element)
}
})
}
// 激活单个组件
async hydrateComponent(element) {
const componentName = element.getAttribute('data-component')
if (this.hydratedComponents.has(element) || this.pendingComponents.has(element)) {
return
}
this.pendingComponents.add(element)
try {
// 动态导入组件
const component = await this.loadComponent(componentName)
// 创建Vue实例并挂载
const instance = this.createComponentInstance(component, element)
await this.mountComponent(instance, element)
this.hydratedComponents.add(element)
element.setAttribute('data-hydrated', 'true')
// 触发激活事件
this.emitHydrationEvent(element, componentName)
} catch (error) {
console.error(`Failed to hydrate component ${componentName}:`, error)
} finally {
this.pendingComponents.delete(element)
}
}
// 动态加载组件
async loadComponent(componentName) {
const componentMap = {
'AppHeader': () => import('../components/AppHeader.vue'),
'AppNavigation': () => import('../components/AppNavigation.vue'),
'MainContent': () => import('../components/MainContent.vue'),
'AppSidebar': () => import('../components/AppSidebar.vue'),
'AppFooter': () => import('../components/AppFooter.vue')
}
const loader = componentMap[componentName]
if (!loader) {
throw new Error(`Unknown component: ${componentName}`)
}
const module = await loader()
return module.default || module
}
// 创建组件实例
createComponentInstance(component, element) {
const props = this.extractProps(element)
const data = this.extractData(element)
return new Vue({
...component,
propsData: props,
data() {
return {
...data,
...(typeof component.data === 'function' ? component.data() : component.data || {})
}
}
})
}
// 提取属性
extractProps(element) {
const propsData = element.getAttribute('data-props')
return propsData ? JSON.parse(propsData) : {}
}
// 提取数据
extractData(element) {
const data = element.getAttribute('data-state')
return data ? JSON.parse(data) : {}
}
// 挂载组件
async mountComponent(instance, element) {
return new Promise((resolve, reject) => {
try {
instance.$mount(element)
// 等待下一个tick确保挂载完成
instance.$nextTick(() => {
resolve(instance)
})
} catch (error) {
reject(error)
}
})
}
// 检查元素是否在视口中
isInViewport(element) {
const rect = element.getBoundingClientRect()
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
)
}
// 扫描新添加的组件
scanForComponents(element) {
const components = element.querySelectorAll('[data-component]:not([data-hydrated])')
components.forEach(component => {
if (this.isInViewport(component)) {
this.hydrateComponent(component)
} else {
this.intersectionObserver.observe(component)
}
})
}
// 触发激活事件
emitHydrationEvent(element, componentName) {
const event = new CustomEvent('component:hydrated', {
detail: {
element,
componentName,
timestamp: Date.now()
}
})
element.dispatchEvent(event)
document.dispatchEvent(event)
}
// 获取激活统计
getStats() {
return {
hydrated: this.hydratedComponents.size,
pending: this.pendingComponents.size,
total: document.querySelectorAll('[data-component]').length
}
}
// 清理资源
destroy() {
if (this.intersectionObserver) {
this.intersectionObserver.disconnect()
}
if (this.mutationObserver) {
this.mutationObserver.disconnect()
}
this.pendingComponents.clear()
this.hydratedComponents.clear()
}
}
// 初始化流式激活
if (typeof window !== 'undefined') {
const hydration = new StreamingHydration()
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
hydration.init()
})
} else {
hydration.init()
}
// 暴露到全局以便调试
window.__STREAMING_HYDRATION__ = hydration
}
export default StreamingHydration
9.3 微前端集成
9.3.1 微前端架构设计
// microfrontend/MicroFrontendManager.js
class MicroFrontendManager {
constructor() {
this.apps = new Map()
this.routes = new Map()
this.sharedDependencies = new Map()
this.eventBus = new EventTarget()
}
// 注册微前端应用
registerApp(config) {
const {
name,
entry,
routes,
container,
activeWhen,
props = {},
sandbox = true
} = config
const app = {
name,
entry,
routes,
container,
activeWhen,
props,
sandbox,
status: 'NOT_LOADED',
instance: null,
sandboxInstance: null
}
this.apps.set(name, app)
// 注册路由
routes.forEach(route => {
this.routes.set(route, name)
})
console.log(`Registered micro frontend: ${name}`)
}
// 加载微前端应用
async loadApp(name) {
const app = this.apps.get(name)
if (!app) {
throw new Error(`App ${name} not found`)
}
if (app.status === 'LOADED' || app.status === 'LOADING') {
return app
}
app.status = 'LOADING'
try {
// 创建沙箱环境
if (app.sandbox) {
app.sandboxInstance = this.createSandbox(app)
}
// 加载应用资源
const resources = await this.loadResources(app.entry)
// 执行应用代码
const appExports = await this.executeApp(resources, app)
app.instance = appExports
app.status = 'LOADED'
// 触发加载完成事件
this.emitEvent('app:loaded', { name, app })
return app
} catch (error) {
app.status = 'LOAD_ERROR'
console.error(`Failed to load app ${name}:`, error)
throw error
}
}
// 挂载微前端应用
async mountApp(name, props = {}) {
const app = await this.loadApp(name)
if (app.status !== 'LOADED') {
throw new Error(`App ${name} is not loaded`)
}
try {
// 准备挂载容器
const container = this.prepareContainer(app.container)
// 合并属性
const mountProps = {
...app.props,
...props,
container,
eventBus: this.eventBus
}
// 调用应用的mount方法
if (app.instance && typeof app.instance.mount === 'function') {
await app.instance.mount(mountProps)
app.status = 'MOUNTED'
this.emitEvent('app:mounted', { name, app })
}
} catch (error) {
console.error(`Failed to mount app ${name}:`, error)
throw error
}
}
// 卸载微前端应用
async unmountApp(name) {
const app = this.apps.get(name)
if (!app || app.status !== 'MOUNTED') {
return
}
try {
// 调用应用的unmount方法
if (app.instance && typeof app.instance.unmount === 'function') {
await app.instance.unmount()
}
// 清理容器
this.cleanupContainer(app.container)
// 清理沙箱
if (app.sandboxInstance) {
app.sandboxInstance.destroy()
}
app.status = 'UNMOUNTED'
this.emitEvent('app:unmounted', { name, app })
} catch (error) {
console.error(`Failed to unmount app ${name}:`, error)
}
}
// 创建沙箱环境
createSandbox(app) {
return new Sandbox({
name: app.name,
globals: this.getSharedGlobals()
})
}
// 获取共享的全局变量
getSharedGlobals() {
return {
Vue: window.Vue,
VueRouter: window.VueRouter,
Vuex: window.Vuex,
axios: window.axios,
// 其他共享依赖
...Object.fromEntries(this.sharedDependencies)
}
}
// 加载应用资源
async loadResources(entry) {
if (typeof entry === 'string') {
// 单个入口文件
return await this.loadScript(entry)
} else if (Array.isArray(entry)) {
// 多个资源文件
const resources = await Promise.all(
entry.map(url => this.loadScript(url))
)
return resources.join('\n')
} else if (typeof entry === 'object') {
// 详细配置
const { js = [], css = [] } = entry
// 加载CSS
await Promise.all(css.map(url => this.loadCSS(url)))
// 加载JS
const scripts = await Promise.all(js.map(url => this.loadScript(url)))
return scripts.join('\n')
}
}
// 加载脚本
async loadScript(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then(response => response.text())
.then(resolve)
.catch(reject)
})
}
// 加载样式
async loadCSS(url) {
return new Promise((resolve, reject) => {
const link = document.createElement('link')
link.rel = 'stylesheet'
link.href = url
link.onload = resolve
link.onerror = reject
document.head.appendChild(link)
})
}
// 执行应用代码
async executeApp(code, app) {
const sandbox = app.sandboxInstance
if (sandbox) {
return sandbox.execute(code)
} else {
// 直接执行(不推荐用于生产环境)
return new Function('return ' + code)()
}
}
// 准备挂载容器
prepareContainer(selector) {
let container
if (typeof selector === 'string') {
container = document.querySelector(selector)
} else {
container = selector
}
if (!container) {
throw new Error(`Container not found: ${selector}`)
}
// 清空容器
container.innerHTML = ''
return container
}
// 清理容器
cleanupContainer(selector) {
const container = typeof selector === 'string'
? document.querySelector(selector)
: selector
if (container) {
container.innerHTML = ''
}
}
// 路由匹配
matchRoute(path) {
for (const [route, appName] of this.routes.entries()) {
if (this.isRouteMatch(path, route)) {
return appName
}
}
return null
}
isRouteMatch(path, route) {
// 简单的路由匹配逻辑
if (route === path) return true
if (route.endsWith('*')) {
const prefix = route.slice(0, -1)
return path.startsWith(prefix)
}
return false
}
// 事件发射
emitEvent(type, detail) {
const event = new CustomEvent(type, { detail })
this.eventBus.dispatchEvent(event)
}
// 事件监听
addEventListener(type, listener) {
this.eventBus.addEventListener(type, listener)
}
// 移除事件监听
removeEventListener(type, listener) {
this.eventBus.removeEventListener(type, listener)
}
// 获取应用状态
getAppStatus(name) {
const app = this.apps.get(name)
return app ? app.status : 'NOT_FOUND'
}
// 获取所有应用
getAllApps() {
return Array.from(this.apps.values())
}
}
// 沙箱实现
class Sandbox {
constructor(options = {}) {
this.name = options.name || 'sandbox'
this.globals = options.globals || {}
this.iframe = null
this.context = null
}
// 创建沙箱环境
create() {
// 使用iframe创建隔离环境
this.iframe = document.createElement('iframe')
this.iframe.style.display = 'none'
document.body.appendChild(this.iframe)
this.context = this.iframe.contentWindow
// 注入共享依赖
Object.assign(this.context, this.globals)
}
// 执行代码
execute(code) {
if (!this.context) {
this.create()
}
try {
return this.context.eval(code)
} catch (error) {
console.error(`Sandbox execution error in ${this.name}:`, error)
throw error
}
}
// 销毁沙箱
destroy() {
if (this.iframe) {
document.body.removeChild(this.iframe)
this.iframe = null
this.context = null
}
}
}
module.exports = MicroFrontendManager
9.3.2 微前端路由集成
// microfrontend/MicroFrontendRouter.js
class MicroFrontendRouter {
constructor(manager, baseRouter) {
this.manager = manager
this.baseRouter = baseRouter
this.currentApp = null
this.setupRouteGuards()
}
// 设置路由守卫
setupRouteGuards() {
this.baseRouter.beforeEach(async (to, from, next) => {
try {
await this.handleRouteChange(to, from)
next()
} catch (error) {
console.error('Route change error:', error)
next(false)
}
})
}
// 处理路由变化
async handleRouteChange(to, from) {
const targetApp = this.manager.matchRoute(to.path)
// 如果目标应用与当前应用相同,不需要切换
if (targetApp === this.currentApp) {
return
}
// 卸载当前应用
if (this.currentApp) {
await this.manager.unmountApp(this.currentApp)
}
// 挂载目标应用
if (targetApp) {
await this.manager.mountApp(targetApp, {
route: to,
router: this.baseRouter
})
this.currentApp = targetApp
} else {
this.currentApp = null
}
}
// 注册微前端路由
registerMicroRoutes() {
const apps = this.manager.getAllApps()
apps.forEach(app => {
app.routes.forEach(route => {
this.baseRouter.addRoute({
path: route,
name: `micro-${app.name}-${route}`,
component: {
template: `<div id="micro-${app.name}"></div>`,
async mounted() {
// 组件挂载时加载微前端
await this.$microManager.mountApp(app.name, {
container: `#micro-${app.name}`
})
},
async beforeDestroy() {
// 组件销毁时卸载微前端
await this.$microManager.unmountApp(app.name)
}
}
})
})
})
}
// 预加载微前端
async preloadApps(routes) {
const preloadPromises = routes.map(async route => {
const appName = this.manager.matchRoute(route)
if (appName) {
try {
await this.manager.loadApp(appName)
console.log(`Preloaded micro frontend: ${appName}`)
} catch (error) {
console.error(`Failed to preload ${appName}:`, error)
}
}
})
await Promise.allSettled(preloadPromises)
}
}
module.exports = MicroFrontendRouter
9.4 本章小结
本章介绍了Vue SSR的高级特性与优化技巧,包括:
核心要点
服务端渲染缓存策略
- 多级缓存架构设计
- 智能缓存策略实现
- 缓存性能分析与优化
流式渲染
- 流式SSR实现原理
- 渐进式渲染技术
- 客户端流式激活
微前端集成
- 微前端架构设计
- 沙箱隔离机制
- 路由集成方案
最佳实践
缓存优化
- 根据访问模式调整缓存策略
- 实施预测性缓存
- 定期分析缓存性能
流式渲染
- 优先渲染关键内容
- 实施渐进式激活
- 合理分配渲染优先级
微前端
- 保持应用间的独立性
- 合理共享依赖
- 实施有效的通信机制
练习作业
- 实现智能缓存系统
- 开发流式渲染方案
- 集成微前端架构
- 性能测试与优化
下一章我们将学习Vue SSR的实战项目开发。