feat: 无界渲染适配器

This commit is contained in:
wangxuefeng
2025-03-18 16:44:01 +08:00
parent 6c1c8b87a4
commit a2d308bc1a
9 changed files with 191 additions and 539 deletions

View File

@@ -28,7 +28,7 @@
"dependencies": {
"postmate": "catalog:",
"vue": "catalog:",
"wujie-vue3": "1.0.24"
"wujie-vue3": "1.0.13"
},
"devDependencies": {
"@farmfe/cli": "^1.0.4",

View File

@@ -1,168 +0,0 @@
<script setup lang="ts">
import { onBeforeUnmount, onMounted } from 'vue';
import WujieVue from 'wujie-vue3';
import { version } from '/package.json';
const props = defineProps<{
[key: string]: any;
accessToken?: string;
applicationId: number | string;
degrade?: boolean;
fileId: number | string;
name: string;
projectId: number | string;
sync: boolean;
url: string;
}>();
console.log('props', props);
const { bus } = WujieVue;
// 生命周期钩子
const beforeLoad = (appWindow: Window) => {
console.log(`${props.name} 开始加载`, appWindow);
};
const afterMount = (appWindow: Window) => {
console.log(`${props.name} 加载完成`, appWindow);
};
// 事件处理
const handleMessage = (data: any) => {
console.log('收到子应用消息:', data);
};
// 准备传递给子应用的数据
const subAppProps = {
...props,
adapterInfo: {
version,
},
};
// 监听子应用的事件
const handleReady = (data: any) => {
console.log('子应用就绪:', data);
// 可以在这里执行一些操作
};
const handleRenderSuccess = () => {
console.log('子应用渲染成功');
// 通知父应用
};
const handleRenderFail = (error: any) => {
console.error('子应用渲染失败:', error);
// 处理错误情况
};
onMounted(() => {
// 注册事件监听
bus.$on('message', handleMessage);
bus.$on('ready', handleReady);
bus.$on('render-success', handleRenderSuccess);
bus.$on('render-fail', handleRenderFail);
});
onBeforeUnmount(() => {
// 移除所有事件监听
bus.$off('message', handleMessage);
bus.$off('ready', handleReady);
bus.$off('render-success', handleRenderSuccess);
bus.$off('render-fail', handleRenderFail);
});
// 在子应用加载前执行的脚本,用于修补 adoptedStyleSheets
const execBeforeLoading = `
// 修补 CSSStyleSheet API
if (window.CSSStyleSheet && CSSStyleSheet.prototype.replaceSync) {
const originalReplaceSync = CSSStyleSheet.prototype.replaceSync;
CSSStyleSheet.prototype.replaceSync = function(text) {
try {
return originalReplaceSync.call(this, text);
} catch (e) {
console.warn('CSSStyleSheet.replaceSync 被拦截:', e);
// 降级处理:创建普通样式标签
const style = document.createElement('style');
style.textContent = text;
document.head.appendChild(style);
return null;
}
};
}
// 替换 adoptedStyleSheets 的 setter
try {
if (Document.prototype.hasOwnProperty('adoptedStyleSheets')) {
const descriptor = Object.getOwnPropertyDescriptor(Document.prototype, 'adoptedStyleSheets');
if (descriptor && descriptor.set) {
const originalSetter = descriptor.set;
descriptor.set = function(sheets) {
try {
originalSetter.call(this, sheets);
} catch (e) {
console.warn('adoptedStyleSheets setter 被拦截:', e);
// 不抛出错误,静默失败
}
};
Object.defineProperty(Document.prototype, 'adoptedStyleSheets', descriptor);
}
}
} catch (e) {
console.warn('无法修补 adoptedStyleSheets:', e);
}
`;
</script>
<template>
<div style="width: 100%; height: 100%">
<WujieVue
:name="name"
:url="url"
:sync="sync"
:degrade="degrade"
width="100%"
height="100%"
:props="subAppProps"
:before-load="beforeLoad"
:after-mount="afterMount"
:plugins="[
{
cssLoader: (code, url, jsdom, appWindow) => {
console.log('cssLoader', code, url, jsdom, appWindow);
try {
// 尝试在子应用窗口中创建样式
if (appWindow && appWindow.document) {
const style = appWindow.document.createElement('style');
style.textContent = code;
appWindow.document.head.appendChild(style);
return true;
}
// 如果没有 appWindow尝试使用 jsdom
if (jsdom && jsdom.window && jsdom.window.document) {
const style = jsdom.window.document.createElement('style');
style.textContent = code;
jsdom.window.document.head.appendChild(style);
return true;
}
// 都不可用时,返回 false 让 wujie 使用默认处理
return false;
} catch (error) {
console.warn('CSS 处理错误:', error);
return false; // 让 wujie 使用默认处理
}
},
},
]"
:degrade="true"
:exec-before-loading="execBeforeLoading"
/>
</div>
</template>

View File

@@ -1,93 +0,0 @@
<script setup lang="ts">
import { onBeforeUnmount, onMounted } from 'vue';
import WujieVue from 'wujie-vue3';
import { version } from '/package.json';
const props = defineProps<{
[key: string]: any;
accessToken?: string;
applicationId: number | string;
degrade?: boolean;
fileId: number | string;
name: string;
projectId: number | string;
sync: boolean;
url: string;
}>();
console.log('props', props);
const { bus } = WujieVue;
// 生命周期钩子
const beforeLoad = (appWindow: Window) => {
console.log(`${props.name} 开始加载`, appWindow);
};
const afterMount = (appWindow: Window) => {
console.log(`${props.name} 加载完成`, appWindow);
};
// 事件处理
const handleMessage = (data: any) => {
console.log('收到子应用消息:', data);
};
// 准备传递给子应用的数据
const subAppProps = {
...props,
adapterInfo: {
version,
},
};
// 监听子应用的事件
const handleReady = (data: any) => {
console.log('子应用就绪:', data);
// 可以在这里执行一些操作
};
const handleRenderSuccess = () => {
console.log('子应用渲染成功');
// 通知父应用
};
const handleRenderFail = (error: any) => {
console.error('子应用渲染失败:', error);
// 处理错误情况
};
onMounted(() => {
// 注册事件监听
bus.$on('message', handleMessage);
bus.$on('ready', handleReady);
bus.$on('render-success', handleRenderSuccess);
bus.$on('render-fail', handleRenderFail);
});
onBeforeUnmount(() => {
// 移除所有事件监听
bus.$off('message', handleMessage);
bus.$off('ready', handleReady);
bus.$off('render-success', handleRenderSuccess);
bus.$off('render-fail', handleRenderFail);
});
</script>
<template>
<div style="width: 100%; height: 100%">
<WujieVue
:name="name"
:url="url"
:sync="sync"
:degrade="true"
width="100%"
height="100%"
:props="subAppProps"
:before-load="beforeLoad"
:after-mount="afterMount"
/>
</div>
</template>

View File

@@ -17,10 +17,10 @@ const props = defineProps<{
url: string;
}>();
const { bus, preloadApp } = WujieVue;
console.log('props', props);
const { bus } = WujieVue;
// 生命周期钩子
const beforeLoad = (appWindow: Window) => {
console.log(`${props.name} 开始加载`, appWindow);
@@ -30,9 +30,9 @@ const afterMount = (appWindow: Window) => {
console.log(`${props.name} 加载完成`, appWindow);
};
// 定义自定义 fetch 函数
const customFetch = (url: string, options?: any) => {
return window.fetch(url, { ...options, credentials: 'include' });
// 事件处理
const handleMessage = (data: any) => {
console.log('收到子应用消息:', data);
};
// 准备传递给子应用的数据
@@ -43,35 +43,36 @@ const subAppProps = {
},
};
// 预加载应用
// 监听子应用的事件
const handleReady = (data: any) => {
console.log('子应用就绪:', data);
// 可以在这里执行一些操作
};
const handleRenderSuccess = () => {
console.log('子应用渲染成功');
// 通知父应用
};
const handleRenderFail = (error: any) => {
console.error('子应用渲染失败:', error);
// 处理错误情况
};
onMounted(() => {
// 注册事件监听
bus.$on('message', (data: any) => {
console.log('收到子应用消息:', data);
});
bus.$on('ready', (data: any) => {
console.log('子应用就绪:', data);
});
bus.$on('render-success', () => {
console.log('子应用渲染成功');
});
bus.$on('render-fail', (error: any) => {
console.error('子应用渲染失败:', error);
});
// 预加载应用
preloadApp({
degrade: true,
exec: true,
fetch: customFetch,
name: props.name,
url: props.url,
});
bus.$on('message', handleMessage);
bus.$on('ready', handleReady);
bus.$on('render-success', handleRenderSuccess);
bus.$on('render-fail', handleRenderFail);
});
onBeforeUnmount(() => {
// 移除所有事件监听
bus.$offAll();
bus.$off('message', handleMessage);
bus.$off('ready', handleReady);
bus.$off('render-success', handleRenderSuccess);
bus.$off('render-fail', handleRenderFail);
});
</script>
@@ -81,13 +82,12 @@ onBeforeUnmount(() => {
:name="name"
:url="url"
:sync="sync"
:degrade="true"
width="100%"
height="100%"
:degrade="degrade"
:props="subAppProps"
:before-load="beforeLoad"
:after-mount="afterMount"
:fetch="customFetch"
/>
</div>
</template>