@rozenite/vite-plugin 1.12.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -1
- package/src/bundle-dts.ts +125 -0
- package/src/client-plugin.ts +392 -0
- package/src/dev-config-module.ts +29 -0
- package/src/dev-host/App.tsx +567 -0
- package/src/dev-host/components/DispatchForm.tsx +169 -0
- package/src/dev-host/components/FlowList.tsx +142 -0
- package/src/dev-host/components/MessageDetailsPane.tsx +109 -0
- package/src/dev-host/components/MessageLogPane.tsx +84 -0
- package/src/dev-host/components/MessagePayloadDetail.tsx +32 -0
- package/src/dev-host/components/PanelTabs.tsx +22 -0
- package/src/dev-host/components/ResizeHandle.tsx +33 -0
- package/src/dev-host/components/icons.tsx +79 -0
- package/src/dev-host/components/ui/Button.tsx +91 -0
- package/src/dev-host/components/ui/DropdownMenu.tsx +84 -0
- package/src/dev-host/components/ui/IconButton.tsx +41 -0
- package/src/dev-host/components/ui/Input.tsx +73 -0
- package/src/dev-host/components/ui/ScrollArea.tsx +20 -0
- package/src/dev-host/components/ui/Tabs.tsx +166 -0
- package/src/dev-host/components/ui/Textarea.tsx +79 -0
- package/src/dev-host/components/ui/ToggleGroup.tsx +120 -0
- package/src/dev-host/config.ts +107 -0
- package/src/dev-host/constants.ts +31 -0
- package/src/dev-host/flow-runtime.ts +297 -0
- package/src/dev-host/index.html +12 -0
- package/src/dev-host/main.tsx +31 -0
- package/src/dev-host/server.ts +55 -0
- package/src/dev-host/styles.css +969 -0
- package/src/dev-host/types.ts +61 -0
- package/src/dev-host/utils.ts +96 -0
- package/src/dev-host/vite.config.mts +20 -0
- package/src/index.ts +114 -0
- package/src/load-config.ts +117 -0
- package/src/package-json.ts +16 -0
- package/src/react-native-plugin.ts +49 -0
- package/src/require-plugin.ts +221 -0
- package/src/sdk-plugin.ts +44 -0
- package/src/server-plugin.ts +36 -0
- package/src/utils.ts +31 -0
- package/src/virtual-modules.d.ts +7 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { DevFlowEntry, DevPresetEntry } from '../load-config.js';
|
|
2
|
+
import { DEV_HOST_CONFIG_GLOBAL_KEY } from './constants.js';
|
|
3
|
+
import type { DevHostFlowEntry, DevHostPresetEntry } from './types.js';
|
|
4
|
+
|
|
5
|
+
type DevHostPresetSource = Omit<DevPresetEntry, 'name'> & {
|
|
6
|
+
name?: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
type DevHostFlowSource = Omit<DevFlowEntry, 'name'> & {
|
|
10
|
+
name?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const getEntryDisplayName = (value: unknown, fallback: string) => {
|
|
14
|
+
if (typeof value === 'string' && value.trim()) {
|
|
15
|
+
return value.trim();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return fallback;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const getDevHostConfig = () => {
|
|
22
|
+
const value = (window as unknown as Record<string, unknown>)[DEV_HOST_CONFIG_GLOBAL_KEY];
|
|
23
|
+
|
|
24
|
+
if (typeof value !== 'object' || value === null) {
|
|
25
|
+
return {} as { presets?: unknown; flows?: unknown };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return value as { presets?: unknown; flows?: unknown };
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const isDevHostPresetSource = (value: unknown): value is DevHostPresetSource => {
|
|
32
|
+
return (
|
|
33
|
+
typeof value === 'object' &&
|
|
34
|
+
value !== null &&
|
|
35
|
+
(!('name' in value) || typeof value.name === 'string') &&
|
|
36
|
+
'type' in value &&
|
|
37
|
+
typeof value.type === 'string' &&
|
|
38
|
+
'payload' in value
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const isDevHostFlowSource = (value: unknown): value is DevHostFlowSource => {
|
|
43
|
+
return (
|
|
44
|
+
typeof value === 'object' &&
|
|
45
|
+
value !== null &&
|
|
46
|
+
(!('name' in value) || typeof value.name === 'string') &&
|
|
47
|
+
(!('autoRun' in value) || typeof value.autoRun === 'boolean') &&
|
|
48
|
+
'run' in value &&
|
|
49
|
+
typeof value.run === 'function'
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const toDevHostPresetEntry = (value: unknown): DevHostPresetEntry | null => {
|
|
54
|
+
if (!isDevHostPresetSource(value)) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const displayName = getEntryDisplayName(value.name, 'Untitled preset');
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
name: displayName,
|
|
62
|
+
displayName,
|
|
63
|
+
type: value.type,
|
|
64
|
+
payload: value.payload,
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const toDevHostFlowEntry = (value: unknown): DevHostFlowEntry | null => {
|
|
69
|
+
if (!isDevHostFlowSource(value)) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const displayName = getEntryDisplayName(value.name, 'Untitled flow');
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
name: displayName,
|
|
77
|
+
displayName,
|
|
78
|
+
autoRun: value.autoRun ?? false,
|
|
79
|
+
run: value.run,
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export const getDevHostPresets = (): DevHostPresetEntry[] => {
|
|
84
|
+
const presets = getDevHostConfig().presets;
|
|
85
|
+
|
|
86
|
+
if (!Array.isArray(presets)) {
|
|
87
|
+
return [];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return presets.flatMap((preset) => {
|
|
91
|
+
const entry = toDevHostPresetEntry(preset);
|
|
92
|
+
return entry ? [entry] : [];
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export const getDevHostFlows = (): DevHostFlowEntry[] => {
|
|
97
|
+
const flows = getDevHostConfig().flows;
|
|
98
|
+
|
|
99
|
+
if (!Array.isArray(flows)) {
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return flows.flatMap((flow) => {
|
|
104
|
+
const entry = toDevHostFlowEntry(flow);
|
|
105
|
+
return entry ? [entry] : [];
|
|
106
|
+
});
|
|
107
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export const DEV_HOST_STATE_ELEMENT_ID = '__rozenite-dev-host__';
|
|
2
|
+
export const DEV_HOST_CONFIG_GLOBAL_KEY = '__rozenite-dev-config__';
|
|
3
|
+
|
|
4
|
+
export const DEFAULT_DEVTOOLS_HEIGHT = 288;
|
|
5
|
+
export const MIN_DEVTOOLS_HEIGHT = 180;
|
|
6
|
+
export const MIN_IFRAME_HEIGHT = 220;
|
|
7
|
+
export const MIN_NARROW_IFRAME_HEIGHT = 140;
|
|
8
|
+
export const DETAILS_PANEL_WIDTH = 360;
|
|
9
|
+
export const MIN_DETAILS_WIDTH = 280;
|
|
10
|
+
export const DEFAULT_COMMAND_WIDTH = 320;
|
|
11
|
+
export const MIN_COMMAND_WIDTH = 260;
|
|
12
|
+
export const SPLITTER_SIZE = 6;
|
|
13
|
+
|
|
14
|
+
export const jsonTreeTheme = {
|
|
15
|
+
base00: 'transparent',
|
|
16
|
+
base01: '#374151',
|
|
17
|
+
base02: '#4b5563',
|
|
18
|
+
base03: '#6b7280',
|
|
19
|
+
base04: '#9ca3af',
|
|
20
|
+
base05: '#d1d5db',
|
|
21
|
+
base06: '#e5e7eb',
|
|
22
|
+
base07: '#f9fafb',
|
|
23
|
+
base08: '#ef4444',
|
|
24
|
+
base09: '#f59e0b',
|
|
25
|
+
base0A: '#10b981',
|
|
26
|
+
base0B: '#3b82f6',
|
|
27
|
+
base0C: '#06b6d4',
|
|
28
|
+
base0D: '#8b5cf6',
|
|
29
|
+
base0E: '#ec4899',
|
|
30
|
+
base0F: '#f97316',
|
|
31
|
+
};
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import type { DevFlowContext, DevFlowMessage, DevFlowMessageMatcher } from '../load-config.js';
|
|
3
|
+
import type { DevHostFlowEntry, DevHostFlowRunState, MessageEntry } from './types.js';
|
|
4
|
+
|
|
5
|
+
type FlowRunnerOptions = {
|
|
6
|
+
sendMessage: (type: string, payload: unknown) => void;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
type ActiveFlowRun = {
|
|
10
|
+
id: string;
|
|
11
|
+
flowName: string;
|
|
12
|
+
flowDisplayName: string;
|
|
13
|
+
autoRun: boolean;
|
|
14
|
+
controller: AbortController;
|
|
15
|
+
listeners: Map<number, (message: DevFlowMessage) => void>;
|
|
16
|
+
cleanups: Set<() => void>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const createAbortError = () => {
|
|
20
|
+
return new DOMException('Flow execution was stopped.', 'AbortError');
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const isAbortError = (error: unknown) => {
|
|
24
|
+
return error instanceof DOMException
|
|
25
|
+
? error.name === 'AbortError'
|
|
26
|
+
: error instanceof Error && error.name === 'AbortError';
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const toFlowMessage = (message: MessageEntry): DevFlowMessage => {
|
|
30
|
+
return {
|
|
31
|
+
id: message.id,
|
|
32
|
+
direction: message.direction,
|
|
33
|
+
date: message.date,
|
|
34
|
+
type: message.type,
|
|
35
|
+
payload: message.payload,
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const matchesMessage = (
|
|
40
|
+
message: DevFlowMessage,
|
|
41
|
+
matcher?: DevFlowMessageMatcher,
|
|
42
|
+
) => {
|
|
43
|
+
if (!matcher) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (typeof matcher === 'string') {
|
|
48
|
+
return message.type === matcher;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (typeof matcher === 'function') {
|
|
52
|
+
return matcher(message);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
(matcher.type == null || message.type === matcher.type) &&
|
|
57
|
+
(matcher.direction == null || message.direction === matcher.direction) &&
|
|
58
|
+
(matcher.predicate == null || matcher.predicate(message))
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const formatFlowError = (error: unknown) => {
|
|
63
|
+
if (isAbortError(error)) {
|
|
64
|
+
return 'Flow execution was stopped.';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (error instanceof Error) {
|
|
68
|
+
return error.message;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return String(error);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const useFlowRunner = ({ sendMessage }: FlowRunnerOptions) => {
|
|
75
|
+
const [flowRuns, setFlowRuns] = useState<DevHostFlowRunState[]>([]);
|
|
76
|
+
const messagesRef = useRef<MessageEntry[]>([]);
|
|
77
|
+
const activeRunsRef = useRef<Map<string, ActiveFlowRun>>(new Map());
|
|
78
|
+
const listenerIdRef = useRef(0);
|
|
79
|
+
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
return () => {
|
|
82
|
+
activeRunsRef.current.forEach((run) => {
|
|
83
|
+
run.controller.abort();
|
|
84
|
+
run.cleanups.forEach((cleanup) => cleanup());
|
|
85
|
+
});
|
|
86
|
+
activeRunsRef.current.clear();
|
|
87
|
+
};
|
|
88
|
+
}, []);
|
|
89
|
+
|
|
90
|
+
const stopFlow = (runId: string) => {
|
|
91
|
+
const activeRun = activeRunsRef.current.get(runId);
|
|
92
|
+
if (!activeRun) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
activeRun.controller.abort();
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const registerMessage = (message: MessageEntry) => {
|
|
100
|
+
messagesRef.current = [message, ...messagesRef.current];
|
|
101
|
+
|
|
102
|
+
const flowMessage = toFlowMessage(message);
|
|
103
|
+
activeRunsRef.current.forEach((activeRun) => {
|
|
104
|
+
activeRun.listeners.forEach((listener) => {
|
|
105
|
+
listener(flowMessage);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const resetMessages = () => {
|
|
111
|
+
messagesRef.current = [];
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const runFlow = (flow: DevHostFlowEntry, options?: { autoRun?: boolean }) => {
|
|
115
|
+
const duplicateRun = [...activeRunsRef.current.values()].find(
|
|
116
|
+
(run) => run.flowName === flow.name,
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
if (duplicateRun) {
|
|
120
|
+
return duplicateRun.id;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const runId = crypto.randomUUID();
|
|
124
|
+
const controller = new AbortController();
|
|
125
|
+
const activeRun: ActiveFlowRun = {
|
|
126
|
+
id: runId,
|
|
127
|
+
flowName: flow.name,
|
|
128
|
+
flowDisplayName: flow.displayName,
|
|
129
|
+
autoRun: options?.autoRun ?? flow.autoRun,
|
|
130
|
+
controller,
|
|
131
|
+
listeners: new Map(),
|
|
132
|
+
cleanups: new Set(),
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const throwIfAborted = () => {
|
|
136
|
+
if (controller.signal.aborted) {
|
|
137
|
+
throw createAbortError();
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const cleanupRun = () => {
|
|
142
|
+
activeRun.cleanups.forEach((cleanup) => cleanup());
|
|
143
|
+
activeRun.cleanups.clear();
|
|
144
|
+
activeRun.listeners.clear();
|
|
145
|
+
activeRunsRef.current.delete(runId);
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const onMessage: DevFlowContext['onMessage'] = (matcher, listener) => {
|
|
149
|
+
throwIfAborted();
|
|
150
|
+
|
|
151
|
+
const listenerId = listenerIdRef.current + 1;
|
|
152
|
+
listenerIdRef.current = listenerId;
|
|
153
|
+
|
|
154
|
+
const wrappedListener = (message: DevFlowMessage) => {
|
|
155
|
+
if (matchesMessage(message, matcher)) {
|
|
156
|
+
listener(message);
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
activeRun.listeners.set(listenerId, wrappedListener);
|
|
161
|
+
|
|
162
|
+
const remove = () => {
|
|
163
|
+
activeRun.listeners.delete(listenerId);
|
|
164
|
+
controller.signal.removeEventListener('abort', remove);
|
|
165
|
+
activeRun.cleanups.delete(remove);
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
controller.signal.addEventListener('abort', remove, { once: true });
|
|
169
|
+
activeRun.cleanups.add(remove);
|
|
170
|
+
|
|
171
|
+
return { remove };
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const flowContext: DevFlowContext = {
|
|
175
|
+
signal: controller.signal,
|
|
176
|
+
send: (type, payload) => {
|
|
177
|
+
throwIfAborted();
|
|
178
|
+
sendMessage(type, payload);
|
|
179
|
+
},
|
|
180
|
+
onMessage,
|
|
181
|
+
waitForMessage: (matcher, options) => {
|
|
182
|
+
throwIfAborted();
|
|
183
|
+
|
|
184
|
+
return new Promise((resolve, reject) => {
|
|
185
|
+
let timeoutId: number | null = null;
|
|
186
|
+
|
|
187
|
+
const cleanup = () => {
|
|
188
|
+
subscription.remove();
|
|
189
|
+
controller.signal.removeEventListener('abort', handleAbort);
|
|
190
|
+
|
|
191
|
+
if (timeoutId !== null) {
|
|
192
|
+
window.clearTimeout(timeoutId);
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const handleAbort = () => {
|
|
197
|
+
cleanup();
|
|
198
|
+
reject(createAbortError());
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const subscription = onMessage(matcher, (message) => {
|
|
202
|
+
cleanup();
|
|
203
|
+
resolve(message);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
controller.signal.addEventListener('abort', handleAbort, { once: true });
|
|
207
|
+
|
|
208
|
+
if (options?.timeoutMs != null) {
|
|
209
|
+
timeoutId = window.setTimeout(() => {
|
|
210
|
+
cleanup();
|
|
211
|
+
reject(
|
|
212
|
+
new Error(`Timed out waiting for a matching message after ${options.timeoutMs}ms.`),
|
|
213
|
+
);
|
|
214
|
+
}, options.timeoutMs);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
},
|
|
218
|
+
getMessages: (matcher) => {
|
|
219
|
+
throwIfAborted();
|
|
220
|
+
|
|
221
|
+
return messagesRef.current
|
|
222
|
+
.map(toFlowMessage)
|
|
223
|
+
.filter((message) => matchesMessage(message, matcher));
|
|
224
|
+
},
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
activeRunsRef.current.set(runId, activeRun);
|
|
228
|
+
setFlowRuns((current) => [
|
|
229
|
+
{
|
|
230
|
+
id: runId,
|
|
231
|
+
flowName: flow.name,
|
|
232
|
+
flowDisplayName: flow.displayName,
|
|
233
|
+
status: 'running',
|
|
234
|
+
result: null,
|
|
235
|
+
error: null,
|
|
236
|
+
autoRun: activeRun.autoRun,
|
|
237
|
+
},
|
|
238
|
+
...current,
|
|
239
|
+
]);
|
|
240
|
+
|
|
241
|
+
const updateRunState = (nextState: Partial<Omit<DevHostFlowRunState, 'id' | 'flowName' | 'flowDisplayName' | 'autoRun'>>) => {
|
|
242
|
+
setFlowRuns((current) =>
|
|
243
|
+
current.map((run) =>
|
|
244
|
+
run.id === runId
|
|
245
|
+
? {
|
|
246
|
+
...run,
|
|
247
|
+
...nextState,
|
|
248
|
+
}
|
|
249
|
+
: run,
|
|
250
|
+
),
|
|
251
|
+
);
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
Promise.resolve(flow.run(flowContext))
|
|
255
|
+
.then((result) => {
|
|
256
|
+
if (controller.signal.aborted) {
|
|
257
|
+
updateRunState({
|
|
258
|
+
status: 'aborted',
|
|
259
|
+
result: null,
|
|
260
|
+
error: 'Flow execution was stopped.',
|
|
261
|
+
});
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
updateRunState({
|
|
266
|
+
status: 'succeeded',
|
|
267
|
+
result,
|
|
268
|
+
error: null,
|
|
269
|
+
});
|
|
270
|
+
})
|
|
271
|
+
.catch((error) => {
|
|
272
|
+
updateRunState({
|
|
273
|
+
status: isAbortError(error) ? 'aborted' : 'failed',
|
|
274
|
+
result: null,
|
|
275
|
+
error: formatFlowError(error),
|
|
276
|
+
});
|
|
277
|
+
})
|
|
278
|
+
.finally(() => {
|
|
279
|
+
cleanupRun();
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
return runId;
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const hasRunningFlow = (flowName: string) => {
|
|
286
|
+
return flowRuns.some((run) => run.flowName === flowName && run.status === 'running');
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
flowRuns,
|
|
291
|
+
runFlow,
|
|
292
|
+
stopFlow,
|
|
293
|
+
hasRunningFlow,
|
|
294
|
+
registerMessage,
|
|
295
|
+
resetMessages,
|
|
296
|
+
};
|
|
297
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Rozenite Dev Host</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="./main.tsx"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { StrictMode } from 'react';
|
|
2
|
+
import { createRoot } from 'react-dom/client';
|
|
3
|
+
import { BaseProvider, DarkTheme } from 'baseui';
|
|
4
|
+
import { Client as Styletron } from 'styletron-engine-monolithic';
|
|
5
|
+
import { Provider as StyletronProvider } from 'styletron-react';
|
|
6
|
+
import { App } from './App.js';
|
|
7
|
+
import { getDevHostFlows, getDevHostPresets } from './config.js';
|
|
8
|
+
import './styles.css';
|
|
9
|
+
import { readDevHostState } from './utils.js';
|
|
10
|
+
|
|
11
|
+
const styletron = new Styletron();
|
|
12
|
+
|
|
13
|
+
const rootElement = document.getElementById('root');
|
|
14
|
+
|
|
15
|
+
if (!rootElement) {
|
|
16
|
+
throw new Error('Rozenite dev host failed to initialize.');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const state = readDevHostState();
|
|
20
|
+
const flows = getDevHostFlows();
|
|
21
|
+
const presets = getDevHostPresets();
|
|
22
|
+
|
|
23
|
+
createRoot(rootElement).render(
|
|
24
|
+
<StrictMode>
|
|
25
|
+
<StyletronProvider value={styletron}>
|
|
26
|
+
<BaseProvider theme={DarkTheme}>
|
|
27
|
+
<App {...state} flows={flows} presets={presets} />
|
|
28
|
+
</BaseProvider>
|
|
29
|
+
</StyletronProvider>
|
|
30
|
+
</StrictMode>,
|
|
31
|
+
);
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
type DevHostManifestEntry = {
|
|
5
|
+
file?: string;
|
|
6
|
+
css?: string[];
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
type DevHostBuildManifest = Record<string, DevHostManifestEntry>;
|
|
10
|
+
|
|
11
|
+
export type DevHostBuiltAssets = {
|
|
12
|
+
script: string;
|
|
13
|
+
styles: string[];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const DEV_HOST_BUILD_ENTRY_KEY = 'index.html';
|
|
17
|
+
|
|
18
|
+
export const getDevHostHtmlTemplate = () => {
|
|
19
|
+
return `<!DOCTYPE html>
|
|
20
|
+
<html lang="en">
|
|
21
|
+
<head>
|
|
22
|
+
<meta charset="UTF-8" />
|
|
23
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
24
|
+
<title>Rozenite Dev Host</title>
|
|
25
|
+
</head>
|
|
26
|
+
<body>
|
|
27
|
+
<div id="root"></div>
|
|
28
|
+
</body>
|
|
29
|
+
</html>`;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const getDevHostSourceEntryFile = (packageDir: string) => {
|
|
33
|
+
return path.join(packageDir, 'src', 'dev-host', 'main.tsx');
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const getBuiltDevHostAssets = (packageDir: string): DevHostBuiltAssets | null => {
|
|
37
|
+
const devHostDistDir = path.join(packageDir, 'dist', 'dev-host');
|
|
38
|
+
const manifestPath = path.join(devHostDistDir, 'manifest.json');
|
|
39
|
+
|
|
40
|
+
if (!fs.existsSync(manifestPath)) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as DevHostBuildManifest;
|
|
45
|
+
const entry = manifest[DEV_HOST_BUILD_ENTRY_KEY];
|
|
46
|
+
|
|
47
|
+
if (!entry?.file) {
|
|
48
|
+
throw new Error(`Missing ${DEV_HOST_BUILD_ENTRY_KEY} entry in dev host manifest.`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
script: path.join(devHostDistDir, entry.file),
|
|
53
|
+
styles: (entry.css ?? []).map((file) => path.join(devHostDistDir, file)),
|
|
54
|
+
};
|
|
55
|
+
};
|