Appearance
qiankun 高级特性
沙箱机制详解
1. JS 沙箱
qiankun 提供了多种 JS 沙箱实现方式:
快照沙箱(SnapshotSandbox)
适用于不支持 Proxy 的低版本浏览器:
javascript
// 在不支持 Proxy 的环境中自动降级
start({
sandbox: {
experimentalStyleIsolation: true,
}
});
代理沙箱(LegacySandbox)
基于 Proxy 实现的沙箱机制:
javascript
// 代理沙箱配置
start({
sandbox: {
// 默认使用代理沙箱
type: 'legacy',
// 指定要保护的全局变量
patchers: [
function(window) {
// 自定义补丁
return function() {
// 恢复操作
};
}
]
}
});
2. 样式隔离
严格的样式隔离
javascript
start({
sandbox: {
strictStyleIsolation: true,
}
});
在这种模式下,qiankun 会为每个微应用的样式添加特定的属性选择器,从而实现样式隔离。
实验性样式隔离
javascript
start({
sandbox: {
experimentalStyleIsolation: true,
}
});
这种模式下,qiankun 会将微应用的 DOM 结构包裹在一个特殊的容器中,实现更严格的样式隔离。
生命周期管理
1. 完整生命周期钩子
javascript
// 自定义生命周期钩子
registerMicroApps([
{
name: 'app1',
entry: '//localhost:3001',
container: '#container',
activeRule: '/app1',
// 自定义加载行为
loader: (loading) => {
if (loading) {
// 显示加载状态
showLoading();
} else {
// 隐藏加载状态
hideLoading();
}
}
}
], {
// 全局生命周期钩子
beforeLoad: async (app) => {
console.log('应用加载前', app.name);
return app;
},
beforeMount: async (app) => {
console.log('应用挂载前', app.name);
return app;
},
afterMount: async (app) => {
console.log('应用挂载后', app.name);
return app;
},
beforeUnmount: async (app) => {
console.log('应用卸载前', app.name);
return app;
},
afterUnmount: async (app) => {
console.log('应用卸载后', app.name);
return app;
}
});
2. 微应用生命周期
微应用需要导出以下生命周期函数:
javascript
// 微应用入口文件
let app = null;
/**
* bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子
*/
export async function bootstrap(props) {
console.log('微应用启动', props);
}
/**
* 应用每次进入都会调用 mount 方法
*/
export async function mount(props) {
console.log('微应用挂载', props);
// 获取主应用传递的属性
const { container, onGlobalStateChange, setGlobalState } = props;
// 初始化应用
app = new Vue({
router,
store,
render: h => h(App),
}).$mount(container ? container.querySelector('#app') : '#app');
}
/**
* 应用每次切出/卸载都会调用 unmount 方法
*/
export async function unmount(props) {
console.log('微应用卸载', props);
// 销毁应用实例
if (app) {
app.$destroy();
app.$el.innerHTML = '';
app = null;
}
}
/**
* 可选的 update 钩子,仅使用 loadMicroApp 方式加载微应用时会调用
*/
export async function update(props) {
console.log('微应用更新', props);
}
通信机制
1. 主应用向微应用传递数据
javascript
// 主应用注册微应用时传递数据
registerMicroApps([
{
name: 'app1',
entry: '//localhost:3001',
container: '#container',
activeRule: '/app1',
props: {
// 传递给微应用的数据
userName: 'admin',
theme: 'dark',
onMainEvent: (data) => {
// 主应用提供的回调函数
console.log('来自主应用的事件', data);
}
}
}
]);
2. 微应用访问主应用数据
javascript
// 微应用中接收主应用传递的数据
export async function mount(props) {
const { container, userName, theme, onMainEvent } = props;
// 使用传递的数据
console.log('用户名:', userName);
console.log('主题:', theme);
// 调用主应用提供的方法
onMainEvent({ message: '来自微应用的消息' });
// 设置主应用提供的状态变更监听器
if (props.onGlobalStateChange) {
props.onGlobalStateChange((state, prev) => {
console.log('全局状态变化', state, prev);
}, true); // true 表示立即触发一次
}
}
3. 全局状态管理
javascript
// 主应用初始化全局状态
import { initGlobalState } from 'qiankun';
const { onGlobalStateChange, setGlobalState, getGlobalState } = initGlobalState({
user: { name: 'admin', id: 1 },
theme: 'light',
language: 'zh-CN'
});
// 监听全局状态变化
onGlobalStateChange((state, prev) => {
console.log('全局状态变化', state, prev);
}, true);
// 微应用中使用全局状态
export async function mount(props) {
// 从 props 中获取状态管理方法
const { onGlobalStateChange, setGlobalState, getGlobalState } = props;
// 监听状态变化
onGlobalStateChange((state, prev) => {
console.log('微应用监听到状态变化', state, prev);
});
// 修改全局状态
setGlobalState({
user: { ...getGlobalState().user, lastLogin: Date.now() }
});
}
预加载策略
1. 默认预加载
javascript
start({
prefetch: true, // 开启预加载
});
2. 自定义预加载
javascript
start({
prefetch: ['app1', 'app2'], // 预加载指定应用
});
// 或者更复杂的预加载策略
start({
prefetch: {
criticalAppList: [
{ name: 'criticalApp', entry: '//localhost:3001' }
],
idleAppList: [
{ name: 'idleApp', entry: '//localhost:3002' }
],
}
});
// 自定义预加载函数
start({
prefetch: (apps) => {
// 自定义预加载逻辑
return apps.filter(app => app.status !== 'failed');
}
});
动态加载微应用
1. 使用 loadMicroApp
javascript
import { loadMicroApp } from 'qiankun';
// 动态加载微应用
const microApp = await loadMicroApp(
{
name: 'dynamicApp',
entry: '//localhost:3003',
container: '#dynamic-container',
},
{
sandbox: {
strictStyleIsolation: true,
},
props: {
data: 'from parent'
}
}
);
// 监听微应用状态
microApp.onGlobalStateChange((state) => {
console.log('微应用状态变化', state);
});
// 卸载微应用
await microApp.unmount();
2. 条件加载
javascript
// 根据条件动态注册微应用
async function registerConditionalApp(userRole) {
if (userRole === 'admin') {
registerMicroApps([
{
name: 'adminPanel',
entry: '//localhost:3004',
container: '#admin-container',
activeRule: '/admin',
}
]);
}
}
错误处理
1. 全局错误处理
javascript
// 捕获微应用错误
window.addEventListener('error', (e) => {
console.error('微应用运行时错误:', e);
// 可以添加错误上报逻辑
});
window.addEventListener('unhandledrejection', (e) => {
console.error('微应用未处理的 Promise 错误:', e);
});
// qiankun 提供的错误处理
start({
error: (error, app) => {
console.error('qiankun 错误:', error, app);
}
});
2. 微应用错误处理
javascript
// 微应用中处理错误
export async function mount(props) {
try {
// 应用初始化逻辑
app = new Vue({
router,
store,
render: h => h(App),
}).$mount(props.container ? props.container.querySelector('#app') : '#app');
} catch (error) {
console.error('微应用挂载失败:', error);
// 可以通知主应用错误状态
if (props.onError) {
props.onError(error);
}
}
}
性能优化
1. 资源预加载
javascript
// 预加载微应用资源
start({
prefetch: true,
sandbox: {
// 使用沙箱提高安全性
strictStyleIsolation: true,
}
});
2. 懒加载配置
javascript
// 配置懒加载
const lazyLoadApp = (appName, appConfig) => {
return new Promise((resolve) => {
// 检查是否已加载
if (!window.loadedApps) {
window.loadedApps = new Set();
}
if (window.loadedApps.has(appName)) {
resolve(appConfig);
return;
}
// 首次加载时添加到已加载集合
window.loadedApps.add(appName);
resolve(appConfig);
});
};
3. 缓存策略
javascript
// 自定义缓存策略
start({
sandbox: {
// 沙箱缓存
experimentalStyleIsolation: true,
}
});
// 微应用级别的缓存
const appCache = new Map();
export async function mount(props) {
const cacheKey = props.container;
if (appCache.has(cacheKey)) {
// 使用缓存的实例
app = appCache.get(cacheKey);
app.$mount(cacheKey);
} else {
// 创建新实例并缓存
app = new Vue({
router,
store,
render: h => h(App),
});
app.$mount(cacheKey);
appCache.set(cacheKey, app);
}
}
安全性考虑
1. XSS 防护
javascript
// 确保内容安全策略
start({
sandbox: {
// 启用样式隔离防止 CSS XSS
strictStyleIsolation: true,
}
});
2. 数据验证
javascript
// 验证来自主应用的数据
export async function mount(props) {
const { userData } = props;
// 验证数据格式
if (userData && typeof userData === 'object') {
// 安全处理数据
processUserData(userData);
}
}
通过这些高级特性,您可以更好地控制和优化基于 qiankun 的微前端架构,实现更复杂和安全的应用集成。