三、性能优化策略
3.1 预加载机制
Wujie 提供了强大的预加载能力,可以显著提升应用切换速度。
基础预加载
// 主应用 main.js
import { preloadApp } from 'wujie'
// 在应用启动时预加载高频子应用
preloadApp({
name: 'app1',
url: 'http://localhost:8081/',
// 预加载时执行 JS
exec: true,
// 预取资源
fetch: (url) => fetch(url),
// 预加载的 props
props: {
preload: true
}
})
// 批量预加载
const appsToPreload = [
{ name: 'app1', url: 'http://localhost:8081/' },
{ name: 'app2', url: 'http://localhost:8082/' }
]
Promise.all(
appsToPreload.map(app => preloadApp(app))
).then(() => {
console.log('所有应用预加载完成')
})
智能预加载策略
// 根据用户行为预加载
class SmartPreloader {
constructor() {
this.preloadQueue = []
this.preloadHistory = new Map()
this.userBehavior = {
clicks: new Map(),
visits: new Map()
}
}
// 记录用户行为
trackBehavior(appName, action = 'visit') {
const map = action === 'visit' ? this.userBehavior.visits : this.userBehavior.clicks
const count = map.get(appName) || 0
map.set(appName, count + 1)
// 分析并触发预加载
this.analyze()
}
// 分析用户行为,决定预加载策略
analyze() {
const apps = Array.from(this.userBehavior.visits.entries())
.sort((a, b) => b[1] - a[1]) // 按访问频率排序
.slice(0, 3) // 取前3个高频应用
.map(([name]) => name)
apps.forEach(appName => {
if (!this.preloadHistory.has(appName)) {
this.preload(appName)
}
})
}
// 执行预加载
async preload(appName) {
const config = this.getAppConfig(appName)
if (!config) return
console.log(`预加载应用: ${appName}`)
this.preloadHistory.set(appName, Date.now())
try {
await preloadApp(config)
console.log(`${appName} 预加载成功`)
} catch (error) {
console.error(`${appName} 预加载失败`, error)
this.preloadHistory.delete(appName)
}
}
// 获取应用配置
getAppConfig(appName) {
const configs = {
app1: { name: 'app1', url: 'http://localhost:8081/' },
app2: { name: 'app2', url: 'http://localhost:8082/' },
app3: { name: 'app3', url: 'http://localhost:8083/' }
}
return configs[appName]
}
// 空闲时预加载
preloadOnIdle(appName) {
if ('requestIdleCallback' in window) {
requestIdleCallback(() => {
this.preload(appName)
}, { timeout: 2000 })
} else {
setTimeout(() => {
this.preload(appName)
}, 1000)
}
}
}
const preloader = new SmartPreloader()
// 使用示例
preloader.trackBehavior('app1', 'visit')
preloader.preloadOnIdle('app2')
3.2 保活机制深度优化
保活是 Wujie 的杀手锏功能,但需要合理使用。
保活配置
<template>
<div class="app-container">
<!-- 开启保活 -->
<WujieVue
v-if="showApp1"
name="app1"
url="http://localhost:8081/"
:alive="true"
@activated="onAppActivated"
@deactivated="onAppDeactivated"
/>
<!-- 不保活,每次都重新加载 -->
<WujieVue
v-if="showApp2"
name="app2"
url="http://localhost:8082/"
:alive="false"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
const showApp1 = ref(true)
const showApp2 = ref(false)
const onAppActivated = () => {
console.log('应用激活,状态保留')
// 可以在这里做一些恢复操作
// 比如刷新数据、恢复滚动位置等
}
const onAppDeactivated = () => {
console.log('应用失活,状态保留')
// 可以在这里做一些清理操作
// 比如暂停视频、保存状态等
}
</script>
保活策略管理
class AliveStrategyManager {
constructor() {
this.aliveApps = new Set()
this.maxAliveApps = 3 // 最多保活3个应用
this.aliveQueue = [] // 保活队列(LRU)
}
// 判断是否应该保活
shouldKeepAlive(appName) {
// 策略1:高频应用总是保活
const highFrequencyApps = ['app1', 'app3']
if (highFrequencyApps.includes(appName)) {
return true
}
// 策略2:根据访问频率
const visitCount = this.getVisitCount(appName)
if (visitCount > 5) {
return true
}
// 策略3:最近使用的应用保活
const recentApps = this.aliveQueue.slice(0, this.maxAliveApps)
if (recentApps.includes(appName)) {
return true
}
return false
}
// 激活应用
activate(appName) {
// 移到队列前面(LRU)
const index = this.aliveQueue.indexOf(appName)
if (index > -1) {
this.aliveQueue.splice(index, 1)
}
this.aliveQueue.unshift(appName)
// 如果超过限制,移除最久未使用的
if (this.aliveQueue.length > this.maxAliveApps) {
const removed = this.aliveQueue.pop()
this.destroy(removed)
}
this.aliveApps.add(appName)
}
// 销毁应用
destroy(appName) {
import('wujie').then(({ destroyApp }) => {
destroyApp(appName)
this.aliveApps.delete(appName)
console.log(`应用 ${appName} 已销毁`)
})
}
// 获取访问次数
getVisitCount(appName) {
const count = localStorage.getItem(`app-visit-${appName}`)
return parseInt(count) || 0
}
// 记录访问
recordVisit(appName) {
const count = this.getVisitCount(appName)
localStorage.setItem(`app-visit-${appName}`, count + 1)
}
// 获取保活状态
getAliveStatus() {
return {
alive: Array.from(this.aliveApps),
queue: [...this.aliveQueue],
count: this.aliveApps.size
}
}
}
const aliveManager = new AliveStrategyManager()
// 使用示例
const alive = computed(() => {
return aliveManager.shouldKeepAlive(currentApp.value)
})
watch(currentApp, (newApp) => {
aliveManager.recordVisit(newApp)
aliveManager.activate(newApp)
})
3.3 资源加载优化
// 资源预取和并行加载
class ResourceOptimizer {
constructor() {
this.cache = new Map()
this.loading = new Map()
}
// 预取资源
async prefetch(url, type = 'script') {
if (this.cache.has(url)) {
return this.cache.get(url)
}
const link = document.createElement('link')
link.rel = 'prefetch'
link.as = type
link.href = url
return new Promise((resolve) => {
link.onload = () => {
this.cache.set(url, true)
resolve()
}
link.onerror = () => resolve()
document.head.appendChild(link)
})
}
// 并行加载多个资源
async loadParallel(resources) {
const promises = resources.map(({ url, type }) =>
this.prefetch(url, type)
)
return Promise.all(promises)
}
// 加载应用资源
async loadAppResources(appUrl) {
try {
// 获取应用的 HTML
const html = await fetch(appUrl).then(res => res.text())
// 解析出所有资源
const resources = this.parseResources(html)
// 并行预取
await this.loadParallel(resources)
console.log(`应用资源预取完成: ${appUrl}`)
} catch (error) {
console.error(`资源预取失败: ${appUrl}`, error)
}
}
// 解析 HTML 中的资源
parseResources(html) {
const resources = []
// 解析 script
const scriptRegex = /<script[^>]+src="([^"]+)"/g
let match
while ((match = scriptRegex.exec(html)) !== null) {
resources.push({ url: match[1], type: 'script' })
}
// 解析 link
const linkRegex = /<link[^>]+href="([^"]+)"[^>]*>/g
while ((match = linkRegex.exec(html)) !== null) {
resources.push({ url: match[1], type: 'style' })
}
return resources
}
}
const optimizer = new ResourceOptimizer()
// 预取应用资源
optimizer.loadAppResources('http://localhost:8081/')
3.4 内存管理
// 内存监控和自动清理
class MemoryManager {
constructor() {
this.threshold = 100 * 1024 * 1024 // 100MB 阈值
this.checkInterval = 30000 // 30秒检查一次
this.apps = new Map()
this.startMonitoring()
}
// 记录应用内存使用
recordApp(appName, memoryUsage) {
this.apps.set(appName, {
memory: memoryUsage,
timestamp: Date.now()
})
}
// 开始监控
startMonitoring() {
setInterval(() => {
this.checkMemory()
}, this.checkInterval)
}
// 检查内存使用
checkMemory() {
if (!performance.memory) {
console.warn('浏览器不支持内存监控')
return
}
const { usedJSHeapSize, jsHeapSizeLimit } = performance.memory
const usagePercent = (usedJSHeapSize / jsHeapSizeLimit) * 100
console.log(`内存使用: ${(usedJSHeapSize / 1024 / 1024).toFixed(2)}MB (${usagePercent.toFixed(2)}%)`)
// 如果超过阈值,触发清理
if (usedJSHeapSize > this.threshold) {
console.warn('内存使用过高,开始清理')
this.cleanup()
}
}
// 清理策略
cleanup() {
// 找到最久未使用的应用
const sortedApps = Array.from(this.apps.entries())
.sort((a, b) => a[1].timestamp - b[1].timestamp)
// 销毁最久未使用的应用
if (sortedApps.length > 0) {
const [appName] = sortedApps[0]
import('wujie').then(({ destroyApp }) => {
destroyApp(appName)
this.apps.delete(appName)
console.log(`已清理应用: ${appName}`)
})
}
// 触发垃圾回收(如果可用)
if (window.gc) {
window.gc()
}
}
// 获取内存使用报告
getReport() {
if (!performance.memory) {
return { error: '浏览器不支持内存监控' }
}
const { usedJSHeapSize, totalJSHeapSize, jsHeapSizeLimit } = performance.memory
return {
used: `${(usedJSHeapSize / 1024 / 1024).toFixed(2)}MB`,
total: `${(totalJSHeapSize / 1024 / 1024).toFixed(2)}MB`,
limit: `${(jsHeapSizeLimit / 1024 / 1024).toFixed(2)}MB`,
usagePercent: `${((usedJSHeapSize / jsHeapSizeLimit) * 100).toFixed(2)}%`,
apps: this.apps.size
}
}
}
const memoryManager = new MemoryManager()
// 应用加载时记录
const onAppMounted = (appName) => {
if (performance.memory) {
memoryManager.recordApp(appName, performance.memory.usedJSHeapSize)
}
}
四、通信机制详解
4.1 Props 传递(单向数据流)
<!-- 主应用 -->
<template>
<WujieVue
name="app1"
url="http://localhost:8081/"
:props="appProps"
/>
</template>
<script setup>
import { reactive, watch } from 'vue'
const userData = reactive({
id: 1,
name: 'Admin',
role: 'admin',
permissions: ['read', 'write']
})
const appProps = reactive({
user: userData,
theme: 'light',
apiBaseUrl: '/api',
// 传递方法
logout: () => {
console.log('用户退出')
userData.name = ''
},
navigate: (path) => {
console.log('导航到', path)
}
})
// 监听用户数据变化,自动同步到子应用
watch(() => userData, (newVal) => {
Object.assign(appProps.user, newVal)
}, { deep: true })
</script>
<!-- 子应用使用 -->
<script setup>
import { ref, onMounted, watch } from 'vue'
const mainAppData = ref(null)
onMounted(() => {
// 获取主应用传递的 props
if (window.$wujie) {
mainAppData.value = window.$wujie.props
console.log('用户信息:', mainAppData.value.user)
console.log('主题:', mainAppData.value.theme)
// 调用主应用方法
// mainAppData.value.logout()
// mainAppData.value.navigate('/home')
}
})
// 监听 props 变化
watch(() => window.$wujie?.props, (newProps) => {
if (newProps) {
mainAppData.value = newProps
console.log('Props 更新:', newProps)
}
}, { deep: true })
</script>
4.2 EventBus 通信(双向)
// 主应用
import { bus } from 'wujie'
// 发送消息给子应用
bus.$emit('main-to-child', {
type: 'notification',
message: '主应用消息',
data: { id: 123 }
})
// 监听子应用消息
bus.$on('child-to-main', (data) => {
console.log('收到子应用消息', data)
// 处理不同类型的消息
switch (data.type) {
case 'request-data':
// 返回数据
bus.$emit('main-response', { data: [] })
break
case 'user-action':
// 处理用户操作
handleUserAction(data.action)
break
}
})
// 子应用
// 监听主应用消息
window.$wujie?.bus.$on('main-to-child', (data) => {
console.log('收到主应用消息', data)
})
// 发送消息给主应用
window.$wujie?.bus.$emit('child-to-main', {
type: 'request-data',
params: { page: 1 }
})
4.3 封装通信工具类
// communication.js
class WujieCommunication {
constructor(appName) {
this.appName = appName
this.isMainApp = !window.$wujie
this.handlers = new Map()
this.init()
}
init() {
if (this.isMainApp) {
// 主应用
import('wujie').then(({ bus }) => {
this.bus = bus
this.setupMainAppListeners()
})
} else {
// 子应用
this.bus = window.$wujie.bus
this.props = window.$wujie.props
this.setupChildAppListeners()
}
}
setupMainAppListeners() {
// 监听所有子应用消息
this.bus.$on('*', (event, data) => {
console.log(`[主应用] 收到事件: ${event}`, data)
this.handleEvent(event, data)
})
}
setupChildAppListeners() {
// 监听主应用消息
this.bus.$on(`to-${this.appName}`, (data) => {
console.log(`[${this.appName}] 收到主应用消息`, data)
this.handleEvent('main-message', data)
})
}
// 发送消息
send(event, data) {
if (this.isMainApp) {
// 主应用发送给指定子应用
this.bus.$emit(`to-${data.target}`, {
from: 'main',
event,
data: data.payload
})
} else {
// 子应用发送给主应用
this.bus.$emit('from-child', {
from: this.appName,
event,
data
})
}
}
// 监听事件
on(event, handler) {
if (!this.handlers.has(event)) {
this.handlers.set(event, [])
}
this.handlers.get(event).push(handler)
}
// 移除监听
off(event, handler) {
if (!this.handlers.has(event)) return
const handlers = this.handlers.get(event)
const index = handlers.indexOf(handler)
if (index > -1) {
handlers.splice(index, 1)
}
}
// 处理事件
handleEvent(event, data) {
const handlers = this.handlers.get(event)
if (handlers) {
handlers.forEach(handler => handler(data))
}
}
// 请求-响应模式
async request(event, data, timeout = 5000) {
return new Promise((resolve, reject) => {
const requestId = `${event}-${Date.now()}`
// 设置超时
const timer = setTimeout(() => {
this.off(`response-${requestId}`)
reject(new Error('Request timeout'))
}, timeout)
// 监听响应
this.on(`response-${requestId}`, (response) => {
clearTimeout(timer)
this.off(`response-${requestId}`)
resolve(response)
})
// 发送请求
this.send(event, {
...data,
requestId
})
})
}
// 响应请求
response(requestId, data) {
this.send(`response-${requestId}`, data)
}
}
// 使用示例
// 主应用
const mainComm = new WujieCommunication('main')
mainComm.on('request-data', async (data) => {
console.log('收到数据请求', data)
const result = await fetchData(data.params)
mainComm.response(data.requestId, result)
})
// 子应用
const childComm = new WujieCommunication('app1')
// 请求数据
const data = await childComm.request('request-data', {
params: { page: 1 }
})
console.log('收到数据', data)
4.4 状态共享(进阶)
// 实现类似 Vuex 的全局状态管理
class WujieStore {
constructor(initialState = {}) {
this.state = reactive(initialState)
this.mutations = {}
this.actions = {}
this.getters = {}
this.setupCommunication()
}
setupCommunication() {
if (window.$wujie) {
// 子应用:监听状态更新
window.$wujie.bus.$on('store-update', (newState) => {
Object.assign(this.state, newState)
})
} else {
// 主应用:广播状态更新
watch(() => this.state, (newState) => {
import('wujie').then(({ bus }) => {
bus.$emit('store-update', newState)
})
}, { deep: true })
}
}
// 注册 mutation
registerMutation(name, handler) {
this.mutations[name] = handler
}
// 提交 mutation
commit(name, payload) {
const mutation = this.mutations[name]
if (!mutation) {
console.error(`Mutation ${name} not found`)
return
}
mutation(this.state, payload)
}
// 注册 action
registerAction(name, handler) {
this.actions[name] = handler
}
// 分发 action
async dispatch(name, payload) {
const action = this.actions[name]
if (!action) {
console.error(`Action ${name} not found`)
return
}
return await action({
state: this.state,
commit: this.commit.bind(this),
dispatch: this.dispatch.bind(this)
}, payload)
}
// 注册 getter
registerGetter(name, handler) {
this.getters[name] = computed(() => handler(this.state))
}
// 获取 getter
getGetter(name) {
return this.getters[name]
}
}
// 创建全局 store
const store = new WujieStore({
user: null,
token: null,
theme: 'light'
})
// 注册 mutations
store.registerMutation('setUser', (state, user) => {
state.user = user
})
store.registerMutation('setToken', (state, token) => {
state.token = token
})
// 注册 actions
store.registerAction('login', async ({ commit }, { username, password }) => {
const res = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify({ username, password })
})
const data = await res.json()
commit('setUser', data.user)
commit('setToken', data.token)
})
// 注册 getters
store.registerGetter('isLoggedIn', (state) => {
return !!state.token
})
// 使用
store.commit('setUser', { name: 'Admin' })
await store.dispatch('login', { username: 'admin', password: '123456' })
const isLoggedIn = store.getGetter('isLoggedIn')
// 导出供全局使用
window.__WUJIE_STORE__ = store