Skip to content

Commit 17a9903

Browse files
committed
feat: support config previewURL by registry
1 parent 7b0e48c commit 17a9903

4 files changed

Lines changed: 89 additions & 65 deletions

File tree

packages/common/js/preview.js

Lines changed: 66 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ const { deepClone } = utils
3030
// 保存预览窗口引用
3131
let previewWindow = null
3232

33+
// 创建 BroadcastChannel 实例用于通信
34+
const previewChannel = new BroadcastChannel('tiny-engine-preview-channel')
35+
3336
const getScriptAndStyleDeps = () => {
3437
const { scripts, styles } = useMaterial().getCanvasDeps()
3538
const utilsDeps = useResource().getUtilsDeps()
@@ -99,46 +102,29 @@ const sendSchemaUpdate = (data) => {
99102
)
100103
}
101104

102-
// 监听来自预览页面的消息
103-
const setupMessageListener = () => {
104-
window.addEventListener('message', async (event) => {
105-
// 确保消息来源安全
106-
if (event.origin === window.location.origin || event.origin.includes(window.location.hostname)) {
107-
const { event: eventType, source } = event.data || {}
108-
// 通过 heartbeat 消息来重新建立连接,避免刷新页面后 previewWindow 为 null
109-
if (source === 'preview' && eventType === 'heartbeat' && !previewWindow) {
110-
previewWindow = event.source
111-
}
105+
let hasSchemaChangeListener = false
112106

113-
if (source === 'preview' && eventType === 'onMounted' && previewWindow) {
114-
const params = await getSchemaParams()
115-
sendSchemaUpdate(params)
116-
}
117-
}
107+
const cleanupSchemaChangeListener = () => {
108+
const { unsubscribe } = useMessage()
109+
unsubscribe({
110+
topic: 'schemaChange',
111+
subscriber: 'preview-communication'
112+
})
113+
unsubscribe({
114+
topic: 'schemaImport',
115+
subscriber: 'preview-communication'
116+
})
117+
unsubscribe({
118+
topic: 'pageOrBlockInit',
119+
subscriber: 'preview-communication'
118120
})
121+
hasSchemaChangeListener = false
119122
}
120123

121-
// 初始化消息监听
122-
setupMessageListener()
123-
124-
let schemaChangeListener = null
125124
const handleSchemaChange = async () => {
126-
const { unsubscribe } = useMessage()
127125
// 如果预览窗口不存在或已关闭,则取消订阅
128126
if (!previewWindow || previewWindow.closed) {
129-
unsubscribe({
130-
topic: 'schemaChange',
131-
subscriber: 'preview-communication'
132-
})
133-
unsubscribe({
134-
topic: 'schemaImport',
135-
subscriber: 'preview-communication'
136-
})
137-
unsubscribe({
138-
topic: 'pageOrBlockInit',
139-
subscriber: 'preview-communication'
140-
})
141-
schemaChangeListener = null
127+
cleanupSchemaChangeListener()
142128
return
143129
}
144130

@@ -149,13 +135,13 @@ const handleSchemaChange = async () => {
149135
// 设置监听 schemaChange 事件,自动发送更新到预览页面
150136
export const setupSchemaChangeListener = () => {
151137
// 如果已经存在监听,则取消之前的监听
152-
if (schemaChangeListener) {
138+
if (hasSchemaChangeListener) {
153139
return
154140
}
155141

156142
const { subscribe } = useMessage()
157143

158-
schemaChangeListener = subscribe({
144+
subscribe({
159145
topic: 'schemaChange',
160146
subscriber: 'preview-communication',
161147
// 防抖更新,防止因为属性变化频繁触发
@@ -173,8 +159,39 @@ export const setupSchemaChangeListener = () => {
173159
subscriber: 'preview-communication',
174160
callback: handleSchemaChange
175161
})
162+
163+
hasSchemaChangeListener = true
176164
}
177165

166+
// 监听来自预览页面的消息
167+
const setupMessageListener = () => {
168+
window.addEventListener('message', async (event) => {
169+
// 确保消息来源安全
170+
if (event.origin === window.location.origin || event.origin.includes(window.location.hostname)) {
171+
const { event: eventType, source } = event.data || {}
172+
// 通过 heartbeat 消息来重新建立连接,避免刷新页面后 previewWindow 为 null
173+
if (source === 'preview' && eventType === 'connect' && !previewWindow) {
174+
previewWindow = event.source
175+
setupSchemaChangeListener()
176+
}
177+
178+
if (source === 'preview' && eventType === 'onMounted' && previewWindow) {
179+
const params = await getSchemaParams()
180+
sendSchemaUpdate(params)
181+
}
182+
}
183+
})
184+
185+
// 可能是刷新,需要重新建立连接
186+
previewChannel.postMessage({
187+
event: 'connect',
188+
source: 'designer'
189+
})
190+
}
191+
192+
// 初始化消息监听
193+
setupMessageListener()
194+
178195
const handleHistoryPreview = (params, url) => {
179196
let historyPreviewWindow = null
180197
const handlePreviewReady = (event) => {
@@ -241,7 +258,20 @@ const open = (params = {}, isHistory = false) => {
241258

242259
let openUrl = ''
243260

244-
openUrl = isDevelopEnv ? `./preview.html?${query}` : `${href.endsWith('/') ? href : `${href}/`}preview?${query}`
261+
// 从预览组件配置获取自定义URL
262+
const customPreviewUrl = getMergeMeta('engine.toolbars.preview')?.options?.previewUrl
263+
const defaultPreviewUrl = isDevelopEnv ? `./preview.html` : `${href.endsWith('/') ? href : `${href}/`}preview`
264+
265+
if (customPreviewUrl) {
266+
// 如果配置了自定义预览URL,则使用自定义URL
267+
openUrl =
268+
typeof customPreviewUrl === 'function'
269+
? customPreviewUrl(defaultPreviewUrl, query)
270+
: `${customPreviewUrl}?${query}`
271+
} else {
272+
// 否则使用默认生成的URL
273+
openUrl = `${defaultPreviewUrl}?${query}`
274+
}
245275

246276
if (isHistory) {
247277
handleHistoryPreview({ ...params, scripts, styles }, openUrl)

packages/design-core/src/preview/src/preview/usePreviewCommunication.ts

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,29 @@ interface PreviewCommunicationOptions {
44
}
55

66
let onSchemaReceivedAction: PreviewCommunicationOptions['onSchemaReceived'] | null = null
7+
// 创建 BroadcastChannel 实例,与主页面通信
8+
let previewChannel: BroadcastChannel | null = null
79

810
const handleMessage = async (event: MessageEvent) => {
911
if (event.origin === window.location.origin || event.origin.includes(window.location.hostname)) {
1012
const { type, data, source } = event.data || {}
1113

12-
if (source === 'designer' && type === 'schema' && data) {
13-
if (onSchemaReceivedAction) {
14-
await onSchemaReceivedAction(data)
15-
}
14+
if (source === 'designer' && type === 'schema' && data && onSchemaReceivedAction) {
15+
await onSchemaReceivedAction(data)
1616
}
1717
}
1818
}
1919

20-
let heartbeatTimer: ReturnType<typeof setTimeout> | undefined = undefined
21-
let retryTimes = 0
22-
let loadInitialData: PreviewCommunicationOptions['loadInitialData'] | null = null
23-
24-
// 心跳重连,防止主页面刷新之后,丢失子页面实例
25-
const heartbeat = () => {
26-
const opener = window.opener
27-
if (retryTimes > 10) {
28-
clearTimeout(heartbeatTimer)
29-
return
20+
const handleBroadcastMessage = async (event: MessageEvent) => {
21+
const { event: eventType, source } = event.data || {}
22+
// 初始化了,重新建立连接
23+
if (source === 'designer' && eventType === 'connect' && window.opener) {
24+
window.opener.postMessage({ event: 'connect', source: 'preview' }, '*')
3025
}
31-
32-
if (!opener) {
33-
retryTimes++
34-
}
35-
36-
if (opener) {
37-
retryTimes = 0
38-
opener.postMessage({ event: 'heartbeat', source: 'preview' }, '*')
39-
}
40-
41-
heartbeatTimer = setTimeout(heartbeat, 1000)
4226
}
4327

28+
let loadInitialData: PreviewCommunicationOptions['loadInitialData'] | null = null
29+
4430
const sendReadyMessage = () => {
4531
// 尝试获取父窗口引用
4632
const opener = window.opener
@@ -57,7 +43,12 @@ const sendReadyMessage = () => {
5743
const cleanupCommunication = () => {
5844
// 移除消息监听器
5945
window.removeEventListener('message', handleMessage)
60-
clearTimeout(heartbeatTimer)
46+
47+
// 关闭 BroadcastChannel
48+
if (previewChannel) {
49+
previewChannel.close()
50+
previewChannel = null
51+
}
6152
}
6253

6354
const initCommunication = () => {
@@ -70,7 +61,9 @@ const initCommunication = () => {
7061
const isHistory = new URLSearchParams(location.search).get('history')
7162

7263
if (!isHistory && window.opener) {
73-
heartbeatTimer = setTimeout(heartbeat, 1000)
64+
// 初始化 BroadcastChannel
65+
previewChannel = new BroadcastChannel('tiny-engine-preview-channel')
66+
previewChannel.onmessage = handleBroadcastMessage
7467
}
7568
}
7669

packages/toolbars/preview/meta.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export default {
66
icon: {
77
default: 'preview'
88
},
9-
renderType: 'icon'
9+
renderType: 'icon',
10+
previewUrl: ''
1011
}
1112
}

packages/toolbars/preview/src/Main.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<div class="toolbar-save">
33
<toolbar-base
44
content="预览页面"
5-
:icon="options.icon.default || options.icon"
5+
:icon="options.icon?.default || options?.icon"
66
:options="options"
77
@click-api="preview"
88
>

0 commit comments

Comments
 (0)