@base44-preview/vite-plugin 1.0.40-pr.124.dc9695c → 1.0.41-pr.125.53b40d6
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/README.md +23 -0
- package/dist/html-injections-plugin.d.ts +21 -0
- package/dist/html-injections-plugin.d.ts.map +1 -1
- package/dist/html-injections-plugin.js +94 -6
- package/dist/html-injections-plugin.js.map +1 -1
- package/dist/injections/ssr-mount-signal.d.ts +2 -0
- package/dist/injections/ssr-mount-signal.d.ts.map +1 -0
- package/dist/injections/ssr-mount-signal.js +29 -0
- package/dist/injections/ssr-mount-signal.js.map +1 -0
- package/package.json +1 -1
- package/src/html-injections-plugin.ts +100 -6
- package/src/injections/ssr-mount-signal.ts +24 -0
package/README.md
CHANGED
|
@@ -140,6 +140,29 @@ The **visual edit agent** is the exception. It's a larger module (~560 lines) th
|
|
|
140
140
|
|
|
141
141
|
In **production**, an inline analytics tracker script is injected instead.
|
|
142
142
|
|
|
143
|
+
### Server-rendered documents (`base44:document`)
|
|
144
|
+
|
|
145
|
+
`transformIndexHtml` never runs for an app whose HTML document is rendered by the framework (TanStack Start and other SSR setups have no `index.html`). Those apps import the same scripts as a module and render them in `<body>`, **before the framework's own scripts**:
|
|
146
|
+
|
|
147
|
+
```jsx
|
|
148
|
+
import { Base44Scripts } from "base44:document";
|
|
149
|
+
|
|
150
|
+
function RootDocument({ children }) {
|
|
151
|
+
return (
|
|
152
|
+
<html>
|
|
153
|
+
<head><HeadContent /></head>
|
|
154
|
+
<body data-react-root="true">
|
|
155
|
+
{children}
|
|
156
|
+
<Base44Scripts />
|
|
157
|
+
<Scripts />
|
|
158
|
+
</body>
|
|
159
|
+
</html>
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The module is virtual: the plugin decides its contents from the same options, command and env as the `index.html` injections, so dev gets the sandbox scripts (plus `ssr-mount-signal.js`, which reports the mount once the document is parsed because a hydrated page never triggers the mutation observer) and production gets the analytics tracker. Module scripts run in document order, so rendering the component before `<Scripts />` keeps the error handlers registered before hydration starts, as they are in `index.html`. Never render it in `<head>`: the preview proxy prepends its own scripts there, and React 19 fails hydration of a head it did not render. `base44DocumentScripts()` returns the raw `{ src }` / `{ children }` list if the document renders the tags itself.
|
|
165
|
+
|
|
143
166
|
### Local Development (Visual Edit Agent)
|
|
144
167
|
|
|
145
168
|
To iterate on the visual edit agent locally without publishing:
|
|
@@ -8,6 +8,26 @@ import type { Connect, Plugin } from "vite";
|
|
|
8
8
|
export declare const BUNDLED_INJECTION_PREFIX = "virtual:base44-vite-plugin/";
|
|
9
9
|
/** This file lives in dist/ once built, so its directory is the served root. */
|
|
10
10
|
export declare const PLUGIN_DIST_DIR: string;
|
|
11
|
+
/**
|
|
12
|
+
* `base44:document` — the same scripts `transformIndexHtml` injects, for apps
|
|
13
|
+
* whose HTML document is rendered by a framework (TanStack Start, and any other
|
|
14
|
+
* SSR setup) and never passes through `index.html`. The root document renders
|
|
15
|
+
* `<Base44Scripts />` at the end of `<body>`; the plugin decides what that is
|
|
16
|
+
* from its own options, the command and the env, exactly as for `index.html`.
|
|
17
|
+
*/
|
|
18
|
+
export declare const DOCUMENT_SPECIFIER = "base44:document";
|
|
19
|
+
type DocumentScript = {
|
|
20
|
+
src: string;
|
|
21
|
+
} | {
|
|
22
|
+
children: string;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* The document renders inline content through `dangerouslySetInnerHTML`, which
|
|
26
|
+
* React does not escape; an env value carrying `</script>` would otherwise
|
|
27
|
+
* close the tag early. Only string literals can carry it, where `<\/` is `</`.
|
|
28
|
+
*/
|
|
29
|
+
export declare function escapeInlineScript(code: string): string;
|
|
30
|
+
export declare function documentModule(scripts: DocumentScript[]): string;
|
|
11
31
|
export declare function resolveBundledInjection(id: string, distDir?: string): string | undefined;
|
|
12
32
|
/**
|
|
13
33
|
* Bundled dev mounts no static/transform middleware, so the visual-edit agent's
|
|
@@ -21,4 +41,5 @@ export declare function htmlInjectionsPlugin({ hmrNotifier, navigationNotifier,
|
|
|
21
41
|
visualEditAgent: boolean;
|
|
22
42
|
analyticsTracker: boolean;
|
|
23
43
|
}): Plugin[];
|
|
44
|
+
export {};
|
|
24
45
|
//# sourceMappingURL=html-injections-plugin.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-injections-plugin.d.ts","sourceRoot":"","sources":["../src/html-injections-plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAoC,MAAM,MAAM,CAAC;AAiD9E;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,gCAAgC,CAAC;AAgDtE,gFAAgF;AAChF,eAAO,MAAM,eAAe,QAA+C,CAAC;
|
|
1
|
+
{"version":3,"file":"html-injections-plugin.d.ts","sourceRoot":"","sources":["../src/html-injections-plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAoC,MAAM,MAAM,CAAC;AAiD9E;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,gCAAgC,CAAC;AAgDtE,gFAAgF;AAChF,eAAO,MAAM,eAAe,QAA+C,CAAC;AAI5E;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,oBAAoB,CAAC;AAGpD,KAAK,cAAc,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7D;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,MAAM,CA2BhE;AAED,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,SAAkB,GAAG,MAAM,GAAG,SAAS,CAGjG;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,IACzC,KAAK,OAAO,CAAC,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,OAAO,CAAC,YAAY,UA0BtF;AAED,wBAAgB,oBAAoB,CAAC,EACnC,WAAW,EACX,kBAAkB,EAClB,eAAe,EACf,gBAAgB,GACjB,EAAE;IACD,WAAW,EAAE,OAAO,CAAC;IACrB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;CAC3B,GAAG,MAAM,EAAE,CA6KX"}
|
|
@@ -89,6 +89,52 @@ const CONTENT_TYPES = {
|
|
|
89
89
|
/** This file lives in dist/ once built, so its directory is the served root. */
|
|
90
90
|
export const PLUGIN_DIST_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
91
91
|
const VISUAL_EDIT_AGENT_FILE = "statics/index.mjs";
|
|
92
|
+
const SSR_MOUNT_SIGNAL_FILE = "injections/ssr-mount-signal.js";
|
|
93
|
+
/**
|
|
94
|
+
* `base44:document` — the same scripts `transformIndexHtml` injects, for apps
|
|
95
|
+
* whose HTML document is rendered by a framework (TanStack Start, and any other
|
|
96
|
+
* SSR setup) and never passes through `index.html`. The root document renders
|
|
97
|
+
* `<Base44Scripts />` at the end of `<body>`; the plugin decides what that is
|
|
98
|
+
* from its own options, the command and the env, exactly as for `index.html`.
|
|
99
|
+
*/
|
|
100
|
+
export const DOCUMENT_SPECIFIER = "base44:document";
|
|
101
|
+
const DOCUMENT_RESOLVED = "\0base44:document";
|
|
102
|
+
/**
|
|
103
|
+
* The document renders inline content through `dangerouslySetInnerHTML`, which
|
|
104
|
+
* React does not escape; an env value carrying `</script>` would otherwise
|
|
105
|
+
* close the tag early. Only string literals can carry it, where `<\/` is `</`.
|
|
106
|
+
*/
|
|
107
|
+
export function escapeInlineScript(code) {
|
|
108
|
+
return code.replace(/<\/(script)/gi, "<\\/$1");
|
|
109
|
+
}
|
|
110
|
+
export function documentModule(scripts) {
|
|
111
|
+
return `
|
|
112
|
+
import { createElement, Fragment } from "react";
|
|
113
|
+
|
|
114
|
+
const SCRIPTS = ${JSON.stringify(scripts)};
|
|
115
|
+
|
|
116
|
+
export function base44DocumentScripts() {
|
|
117
|
+
return SCRIPTS;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function Base44Scripts() {
|
|
121
|
+
return createElement(
|
|
122
|
+
Fragment,
|
|
123
|
+
null,
|
|
124
|
+
...SCRIPTS.map((script, index) =>
|
|
125
|
+
"src" in script
|
|
126
|
+
? createElement("script", { key: index, type: "module", src: script.src })
|
|
127
|
+
: createElement("script", {
|
|
128
|
+
key: index,
|
|
129
|
+
type: "module",
|
|
130
|
+
suppressHydrationWarning: true,
|
|
131
|
+
dangerouslySetInnerHTML: { __html: script.children },
|
|
132
|
+
}),
|
|
133
|
+
),
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
`;
|
|
137
|
+
}
|
|
92
138
|
export function resolveBundledInjection(id, distDir = PLUGIN_DIST_DIR) {
|
|
93
139
|
if (!id.startsWith(BUNDLED_INJECTION_PREFIX))
|
|
94
140
|
return undefined;
|
|
@@ -146,10 +192,10 @@ export function htmlInjectionsPlugin({ hmrNotifier, navigationNotifier, visualEd
|
|
|
146
192
|
let resolvedEnv = {};
|
|
147
193
|
let isServe = false;
|
|
148
194
|
let bundled = false;
|
|
149
|
-
const tagsFor = (mode) => Object.entries(INJECTIONS)
|
|
195
|
+
const tagsFor = (mode, useBundled = bundled) => Object.entries(INJECTIONS)
|
|
150
196
|
.filter(([key, injection]) => enabledInjections[key] &&
|
|
151
197
|
injection.mode === mode &&
|
|
152
|
-
(!injection.bundledOnly ||
|
|
198
|
+
(!injection.bundledOnly || useBundled))
|
|
153
199
|
.map(([, injection]) => {
|
|
154
200
|
if (injection.inlineContent) {
|
|
155
201
|
// Vite doesn't replace import.meta.env inside injected inline scripts.
|
|
@@ -161,7 +207,7 @@ export function htmlInjectionsPlugin({ hmrNotifier, navigationNotifier, visualEd
|
|
|
161
207
|
injectTo: injection.injectTo,
|
|
162
208
|
};
|
|
163
209
|
}
|
|
164
|
-
const src =
|
|
210
|
+
const src = useBundled
|
|
165
211
|
? `${BUNDLED_INJECTION_PREFIX}${injection.file}`
|
|
166
212
|
: `${DIST_URL_PREFIX}/${injection.file}`;
|
|
167
213
|
return {
|
|
@@ -188,8 +234,8 @@ export function htmlInjectionsPlugin({ hmrNotifier, navigationNotifier, visualEd
|
|
|
188
234
|
].join("\n"),
|
|
189
235
|
injectTo: "body",
|
|
190
236
|
});
|
|
191
|
-
const devTags = () => {
|
|
192
|
-
const tags = tagsFor("dev");
|
|
237
|
+
const devTags = (useBundled = bundled) => {
|
|
238
|
+
const tags = tagsFor("dev", useBundled);
|
|
193
239
|
if (visualEditAgent)
|
|
194
240
|
tags.push(visualEditAgentTag());
|
|
195
241
|
return tags;
|
|
@@ -242,6 +288,48 @@ export function htmlInjectionsPlugin({ hmrNotifier, navigationNotifier, visualEd
|
|
|
242
288
|
},
|
|
243
289
|
},
|
|
244
290
|
};
|
|
245
|
-
|
|
291
|
+
// The framework's dev server is middleware-based, so the document never takes
|
|
292
|
+
// the bundled form: node_modules URLs, and none of the `import.meta.hot`-gated
|
|
293
|
+
// bundled-only scripts, which would be silent no-ops served raw. The SSR mount
|
|
294
|
+
// signal stands in for the mutation-driven observer, which never fires on a
|
|
295
|
+
// hydrated page.
|
|
296
|
+
const documentScripts = () => {
|
|
297
|
+
const tags = isServe ? devTags(false) : tagsFor("production", false);
|
|
298
|
+
if (isServe) {
|
|
299
|
+
tags.push({
|
|
300
|
+
tag: "script",
|
|
301
|
+
attrs: { src: `${DIST_URL_PREFIX}/${SSR_MOUNT_SIGNAL_FILE}`, type: "module" },
|
|
302
|
+
injectTo: "body",
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
// index.html runs `head` injections before the app entry and `body` ones
|
|
306
|
+
// after it; module scripts run in document order, so head entries go first.
|
|
307
|
+
const ordered = [
|
|
308
|
+
...tags.filter((tag) => tag.injectTo === "head"),
|
|
309
|
+
...tags.filter((tag) => tag.injectTo !== "head"),
|
|
310
|
+
];
|
|
311
|
+
return ordered.map((tag) => {
|
|
312
|
+
if (typeof tag.children === "string")
|
|
313
|
+
return { children: escapeInlineScript(tag.children) };
|
|
314
|
+
const src = tag.attrs?.src;
|
|
315
|
+
if (typeof src !== "string") {
|
|
316
|
+
throw new Error(`[base44-document] injection has neither src nor inline content: ${JSON.stringify(tag)}`);
|
|
317
|
+
}
|
|
318
|
+
return { src };
|
|
319
|
+
});
|
|
320
|
+
};
|
|
321
|
+
const document = {
|
|
322
|
+
name: "base44-document",
|
|
323
|
+
// Ahead of Vite's own resolution so the bare `base44:` specifier is never
|
|
324
|
+
// mistaken for a URL protocol.
|
|
325
|
+
enforce: "pre",
|
|
326
|
+
resolveId(id) {
|
|
327
|
+
return id === DOCUMENT_SPECIFIER ? DOCUMENT_RESOLVED : null;
|
|
328
|
+
},
|
|
329
|
+
load(id) {
|
|
330
|
+
return id === DOCUMENT_RESOLVED ? documentModule(documentScripts()) : null;
|
|
331
|
+
},
|
|
332
|
+
};
|
|
333
|
+
return [dev, devBundled, production, document];
|
|
246
334
|
}
|
|
247
335
|
//# sourceMappingURL=html-injections-plugin.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-injections-plugin.js","sourceRoot":"","sources":["../src/html-injections-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAahD,MAAM,wBAAwB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BhC,CAAC;AAEF,MAAM,eAAe,GAAG,wCAAwC,CAAC;AACjE;;;;GAIG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,6BAA6B,CAAC;AAEtE,MAAM,UAAU,GAA8B;IAC5C,eAAe,EAAE;QACf,IAAI,EAAE,yCAAyC;QAC/C,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,KAAK;KACZ;IACD,YAAY,EAAE;QACZ,IAAI,EAAE,sCAAsC;QAC5C,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,KAAK;KACZ;IACD,WAAW,EAAE;QACX,IAAI,EAAE,oCAAoC;QAC1C,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,KAAK;KACZ;IACD,kBAAkB,EAAE;QAClB,IAAI,EAAE,mCAAmC;QACzC,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,KAAK;KACZ;IACD,kBAAkB,EAAE;QAClB,IAAI,EAAE,4CAA4C;QAClD,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,KAAK;QACX,WAAW,EAAE,IAAI;KAClB;IACD,cAAc,EAAE;QACd,IAAI,EAAE,wCAAwC;QAC9C,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,KAAK;QACX,WAAW,EAAE,IAAI;KAClB;IACD,gBAAgB,EAAE;QAChB,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,YAAY;QAClB,aAAa,EAAE,wBAAwB;KACxC;CACF,CAAC;AAEF,MAAM,aAAa,GAA2B;IAC5C,KAAK,EAAE,iBAAiB;IACxB,MAAM,EAAE,iBAAiB;IACzB,MAAM,EAAE,kBAAkB;CAC3B,CAAC;AAEF,gFAAgF;AAChF,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC5E,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"html-injections-plugin.js","sourceRoot":"","sources":["../src/html-injections-plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssr-mount-signal.d.ts","sourceRoot":"","sources":["../../src/injections/ssr-mount-signal.ts"],"names":[],"mappings":"AAMA,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAe,EAAE,GAAG,GAAE,QAAmB,GAAG,IAAI,CAenF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// A server-rendered page hydrates in place and never mutates the DOM, so the
|
|
2
|
+
// mount observer's MutationObserver never fires for it. The instrumented markup
|
|
3
|
+
// in the server's HTML is the mount, so it is reported as soon as the document
|
|
4
|
+
// is parsed — before hydration; a hydration error reaches the editor through the
|
|
5
|
+
// unhandled-error handlers. Streamed markup that lands later is caught by the
|
|
6
|
+
// `load` retry, or by the observer, which parser insertions do trigger.
|
|
7
|
+
export function reportSsrMount(win = window, doc = document) {
|
|
8
|
+
if (win.self === win.top)
|
|
9
|
+
return;
|
|
10
|
+
const report = () => {
|
|
11
|
+
if (!doc.body.querySelector("[data-source-location], [data-dynamic-content]"))
|
|
12
|
+
return false;
|
|
13
|
+
win.parent?.postMessage({ type: "sandbox:onMounted" }, "*");
|
|
14
|
+
return true;
|
|
15
|
+
};
|
|
16
|
+
const reportOrRetryOnLoad = () => {
|
|
17
|
+
if (!report())
|
|
18
|
+
win.addEventListener("load", () => void report(), { once: true });
|
|
19
|
+
};
|
|
20
|
+
if (doc.readyState === "loading") {
|
|
21
|
+
doc.addEventListener("DOMContentLoaded", reportOrRetryOnLoad, { once: true });
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
reportOrRetryOnLoad();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (typeof window !== "undefined")
|
|
28
|
+
reportSsrMount();
|
|
29
|
+
//# sourceMappingURL=ssr-mount-signal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssr-mount-signal.js","sourceRoot":"","sources":["../../src/injections/ssr-mount-signal.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,gFAAgF;AAChF,+EAA+E;AAC/E,iFAAiF;AACjF,8EAA8E;AAC9E,wEAAwE;AACxE,MAAM,UAAU,cAAc,CAAC,MAAc,MAAM,EAAE,MAAgB,QAAQ;IAC3E,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,GAAG;QAAE,OAAO;IACjC,MAAM,MAAM,GAAG,GAAY,EAAE;QAC3B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,gDAAgD,CAAC;YAAE,OAAO,KAAK,CAAC;QAC5F,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,EAAE,GAAG,CAAC,CAAC;QAC5D,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;IACF,MAAM,mBAAmB,GAAG,GAAG,EAAE;QAC/B,IAAI,CAAC,MAAM,EAAE;YAAE,GAAG,CAAC,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACnF,CAAC,CAAC;IACF,IAAI,GAAG,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACjC,GAAG,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,mBAAmB,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAChF,CAAC;SAAM,CAAC;QACN,mBAAmB,EAAE,CAAC;IACxB,CAAC;AACH,CAAC;AAED,IAAI,OAAO,MAAM,KAAK,WAAW;IAAE,cAAc,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -107,6 +107,57 @@ const CONTENT_TYPES: Record<string, string> = {
|
|
|
107
107
|
/** This file lives in dist/ once built, so its directory is the served root. */
|
|
108
108
|
export const PLUGIN_DIST_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
109
109
|
const VISUAL_EDIT_AGENT_FILE = "statics/index.mjs";
|
|
110
|
+
const SSR_MOUNT_SIGNAL_FILE = "injections/ssr-mount-signal.js";
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* `base44:document` — the same scripts `transformIndexHtml` injects, for apps
|
|
114
|
+
* whose HTML document is rendered by a framework (TanStack Start, and any other
|
|
115
|
+
* SSR setup) and never passes through `index.html`. The root document renders
|
|
116
|
+
* `<Base44Scripts />` at the end of `<body>`; the plugin decides what that is
|
|
117
|
+
* from its own options, the command and the env, exactly as for `index.html`.
|
|
118
|
+
*/
|
|
119
|
+
export const DOCUMENT_SPECIFIER = "base44:document";
|
|
120
|
+
const DOCUMENT_RESOLVED = "\0base44:document";
|
|
121
|
+
|
|
122
|
+
type DocumentScript = { src: string } | { children: string };
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* The document renders inline content through `dangerouslySetInnerHTML`, which
|
|
126
|
+
* React does not escape; an env value carrying `</script>` would otherwise
|
|
127
|
+
* close the tag early. Only string literals can carry it, where `<\/` is `</`.
|
|
128
|
+
*/
|
|
129
|
+
export function escapeInlineScript(code: string): string {
|
|
130
|
+
return code.replace(/<\/(script)/gi, "<\\/$1");
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function documentModule(scripts: DocumentScript[]): string {
|
|
134
|
+
return `
|
|
135
|
+
import { createElement, Fragment } from "react";
|
|
136
|
+
|
|
137
|
+
const SCRIPTS = ${JSON.stringify(scripts)};
|
|
138
|
+
|
|
139
|
+
export function base44DocumentScripts() {
|
|
140
|
+
return SCRIPTS;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function Base44Scripts() {
|
|
144
|
+
return createElement(
|
|
145
|
+
Fragment,
|
|
146
|
+
null,
|
|
147
|
+
...SCRIPTS.map((script, index) =>
|
|
148
|
+
"src" in script
|
|
149
|
+
? createElement("script", { key: index, type: "module", src: script.src })
|
|
150
|
+
: createElement("script", {
|
|
151
|
+
key: index,
|
|
152
|
+
type: "module",
|
|
153
|
+
suppressHydrationWarning: true,
|
|
154
|
+
dangerouslySetInnerHTML: { __html: script.children },
|
|
155
|
+
}),
|
|
156
|
+
),
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
`;
|
|
160
|
+
}
|
|
110
161
|
|
|
111
162
|
export function resolveBundledInjection(id: string, distDir = PLUGIN_DIST_DIR): string | undefined {
|
|
112
163
|
if (!id.startsWith(BUNDLED_INJECTION_PREFIX)) return undefined;
|
|
@@ -177,13 +228,13 @@ export function htmlInjectionsPlugin({
|
|
|
177
228
|
let isServe = false;
|
|
178
229
|
let bundled = false;
|
|
179
230
|
|
|
180
|
-
const tagsFor = (mode: "dev" | "production"): HtmlTagDescriptor[] =>
|
|
231
|
+
const tagsFor = (mode: "dev" | "production", useBundled = bundled): HtmlTagDescriptor[] =>
|
|
181
232
|
Object.entries(INJECTIONS)
|
|
182
233
|
.filter(
|
|
183
234
|
([key, injection]) =>
|
|
184
235
|
enabledInjections[key] &&
|
|
185
236
|
injection.mode === mode &&
|
|
186
|
-
(!injection.bundledOnly ||
|
|
237
|
+
(!injection.bundledOnly || useBundled)
|
|
187
238
|
)
|
|
188
239
|
.map(([, injection]): HtmlTagDescriptor => {
|
|
189
240
|
if (injection.inlineContent) {
|
|
@@ -199,7 +250,7 @@ export function htmlInjectionsPlugin({
|
|
|
199
250
|
injectTo: injection.injectTo,
|
|
200
251
|
};
|
|
201
252
|
}
|
|
202
|
-
const src =
|
|
253
|
+
const src = useBundled
|
|
203
254
|
? `${BUNDLED_INJECTION_PREFIX}${injection.file}`
|
|
204
255
|
: `${DIST_URL_PREFIX}/${injection.file}`;
|
|
205
256
|
return {
|
|
@@ -228,8 +279,8 @@ export function htmlInjectionsPlugin({
|
|
|
228
279
|
injectTo: "body",
|
|
229
280
|
});
|
|
230
281
|
|
|
231
|
-
const devTags = () => {
|
|
232
|
-
const tags = tagsFor("dev");
|
|
282
|
+
const devTags = (useBundled = bundled) => {
|
|
283
|
+
const tags = tagsFor("dev", useBundled);
|
|
233
284
|
if (visualEditAgent) tags.push(visualEditAgentTag());
|
|
234
285
|
return tags;
|
|
235
286
|
};
|
|
@@ -286,5 +337,48 @@ export function htmlInjectionsPlugin({
|
|
|
286
337
|
},
|
|
287
338
|
};
|
|
288
339
|
|
|
289
|
-
|
|
340
|
+
// The framework's dev server is middleware-based, so the document never takes
|
|
341
|
+
// the bundled form: node_modules URLs, and none of the `import.meta.hot`-gated
|
|
342
|
+
// bundled-only scripts, which would be silent no-ops served raw. The SSR mount
|
|
343
|
+
// signal stands in for the mutation-driven observer, which never fires on a
|
|
344
|
+
// hydrated page.
|
|
345
|
+
const documentScripts = (): DocumentScript[] => {
|
|
346
|
+
const tags = isServe ? devTags(false) : tagsFor("production", false);
|
|
347
|
+
if (isServe) {
|
|
348
|
+
tags.push({
|
|
349
|
+
tag: "script",
|
|
350
|
+
attrs: { src: `${DIST_URL_PREFIX}/${SSR_MOUNT_SIGNAL_FILE}`, type: "module" },
|
|
351
|
+
injectTo: "body",
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
// index.html runs `head` injections before the app entry and `body` ones
|
|
355
|
+
// after it; module scripts run in document order, so head entries go first.
|
|
356
|
+
const ordered = [
|
|
357
|
+
...tags.filter((tag) => tag.injectTo === "head"),
|
|
358
|
+
...tags.filter((tag) => tag.injectTo !== "head"),
|
|
359
|
+
];
|
|
360
|
+
return ordered.map((tag) => {
|
|
361
|
+
if (typeof tag.children === "string") return { children: escapeInlineScript(tag.children) };
|
|
362
|
+
const src = tag.attrs?.src;
|
|
363
|
+
if (typeof src !== "string") {
|
|
364
|
+
throw new Error(`[base44-document] injection has neither src nor inline content: ${JSON.stringify(tag)}`);
|
|
365
|
+
}
|
|
366
|
+
return { src };
|
|
367
|
+
});
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
const document: Plugin = {
|
|
371
|
+
name: "base44-document",
|
|
372
|
+
// Ahead of Vite's own resolution so the bare `base44:` specifier is never
|
|
373
|
+
// mistaken for a URL protocol.
|
|
374
|
+
enforce: "pre",
|
|
375
|
+
resolveId(id) {
|
|
376
|
+
return id === DOCUMENT_SPECIFIER ? DOCUMENT_RESOLVED : null;
|
|
377
|
+
},
|
|
378
|
+
load(id) {
|
|
379
|
+
return id === DOCUMENT_RESOLVED ? documentModule(documentScripts()) : null;
|
|
380
|
+
},
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
return [dev, devBundled, production, document];
|
|
290
384
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// A server-rendered page hydrates in place and never mutates the DOM, so the
|
|
2
|
+
// mount observer's MutationObserver never fires for it. The instrumented markup
|
|
3
|
+
// in the server's HTML is the mount, so it is reported as soon as the document
|
|
4
|
+
// is parsed — before hydration; a hydration error reaches the editor through the
|
|
5
|
+
// unhandled-error handlers. Streamed markup that lands later is caught by the
|
|
6
|
+
// `load` retry, or by the observer, which parser insertions do trigger.
|
|
7
|
+
export function reportSsrMount(win: Window = window, doc: Document = document): void {
|
|
8
|
+
if (win.self === win.top) return;
|
|
9
|
+
const report = (): boolean => {
|
|
10
|
+
if (!doc.body.querySelector("[data-source-location], [data-dynamic-content]")) return false;
|
|
11
|
+
win.parent?.postMessage({ type: "sandbox:onMounted" }, "*");
|
|
12
|
+
return true;
|
|
13
|
+
};
|
|
14
|
+
const reportOrRetryOnLoad = () => {
|
|
15
|
+
if (!report()) win.addEventListener("load", () => void report(), { once: true });
|
|
16
|
+
};
|
|
17
|
+
if (doc.readyState === "loading") {
|
|
18
|
+
doc.addEventListener("DOMContentLoaded", reportOrRetryOnLoad, { once: true });
|
|
19
|
+
} else {
|
|
20
|
+
reportOrRetryOnLoad();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (typeof window !== "undefined") reportSsrMount();
|