@base44/vite-plugin 1.0.30 → 1.0.32
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/dist/capabilities/inline-edit/controller.d.ts.map +1 -1
- package/dist/capabilities/inline-edit/controller.js +2 -5
- package/dist/capabilities/inline-edit/controller.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +33 -2
- package/dist/index.js.map +1 -1
- package/dist/injections/unhandled-errors-handlers.d.ts +2 -1
- package/dist/injections/unhandled-errors-handlers.d.ts.map +1 -1
- package/dist/injections/unhandled-errors-handlers.js +34 -19
- package/dist/injections/unhandled-errors-handlers.js.map +1 -1
- package/dist/injections/utils.d.ts +6 -0
- package/dist/injections/utils.d.ts.map +1 -1
- package/dist/injections/utils.js +8 -0
- package/dist/injections/utils.js.map +1 -1
- package/dist/injections/visual-edit-agent.d.ts.map +1 -1
- package/dist/injections/visual-edit-agent.js +2 -5
- package/dist/injections/visual-edit-agent.js.map +1 -1
- package/dist/processors/collection-item-field-processor.d.ts.map +1 -1
- package/dist/processors/collection-item-field-processor.js +11 -0
- package/dist/processors/collection-item-field-processor.js.map +1 -1
- package/dist/statics/index.mjs +7 -7
- package/dist/statics/index.mjs.map +1 -1
- package/dist/visual-edit-plugin.d.ts.map +1 -1
- package/dist/visual-edit-plugin.js +7 -1
- package/dist/visual-edit-plugin.js.map +1 -1
- package/package.json +1 -1
- package/src/capabilities/inline-edit/controller.ts +2 -6
- package/src/index.ts +36 -2
- package/src/injections/unhandled-errors-handlers.ts +36 -19
- package/src/injections/utils.ts +9 -0
- package/src/injections/visual-edit-agent.ts +2 -6
- package/src/processors/collection-item-field-processor.ts +12 -0
- package/src/visual-edit-plugin.md +3 -2
- package/src/visual-edit-plugin.ts +9 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"visual-edit-plugin.d.ts","sourceRoot":"","sources":["../src/visual-edit-plugin.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"visual-edit-plugin.d.ts","sourceRoot":"","sources":["../src/visual-edit-plugin.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAa,MAAM,EAAc,MAAM,MAAM,CAAC;AAI1D,wBAAgB,gBAAgB,IA+EzB,MAAM,CACZ"}
|
|
@@ -7,7 +7,13 @@ import { JSXUtils } from "./jsx-utils.js";
|
|
|
7
7
|
export function visualEditPlugin() {
|
|
8
8
|
return {
|
|
9
9
|
name: "visual-edit-transform",
|
|
10
|
-
|
|
10
|
+
// Dev SERVER only: the injected data-* markers are consumed by the
|
|
11
|
+
// visual-edit agent in the live preview, which vite serves — never by
|
|
12
|
+
// build output. Gating on mode alone also caught `vite build --mode
|
|
13
|
+
// development` (the platform's validation build), where instrumenting
|
|
14
|
+
// user code is pure risk: an injection bug there fails the build on
|
|
15
|
+
// code that doesn't exist on disk.
|
|
16
|
+
apply: (config, env) => env.command === "serve" && config.mode === "development",
|
|
11
17
|
enforce: "pre",
|
|
12
18
|
order: "pre",
|
|
13
19
|
transformIndexHtml(html) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"visual-edit-plugin.js","sourceRoot":"","sources":["../src/visual-edit-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAElC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,MAAM,UAAU,gBAAgB;IAC9B,OAAO;QACL,IAAI,EAAE,uBAAuB;QAC7B,KAAK,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"visual-edit-plugin.js","sourceRoot":"","sources":["../src/visual-edit-plugin.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
shouldEnterInlineEditingMode,
|
|
7
7
|
isStaticArrayTextElement,
|
|
8
8
|
} from "./dom-utils.js";
|
|
9
|
-
import { PLUGIN_ELEMENT_ATTR } from "../../injections/utils.js";
|
|
9
|
+
import { PLUGIN_ELEMENT_ATTR, readElementClasses } from "../../injections/utils.js";
|
|
10
10
|
|
|
11
11
|
const DEBOUNCE_MS = 500;
|
|
12
12
|
|
|
@@ -36,17 +36,13 @@ export function createInlineEditController(
|
|
|
36
36
|
const originalContent = element.dataset.originalTextContent;
|
|
37
37
|
const newContent = element.textContent;
|
|
38
38
|
|
|
39
|
-
const svgElement = element as unknown as SVGElement;
|
|
40
39
|
const rect = element.getBoundingClientRect();
|
|
41
40
|
|
|
42
41
|
const message: Record<string, unknown> = {
|
|
43
42
|
type: "inline-edit",
|
|
44
43
|
elementInfo: {
|
|
45
44
|
tagName: element.tagName,
|
|
46
|
-
classes:
|
|
47
|
-
(svgElement.className as unknown as SVGAnimatedString)?.baseVal ||
|
|
48
|
-
element.className ||
|
|
49
|
-
"",
|
|
45
|
+
classes: readElementClasses(element),
|
|
50
46
|
visualSelectorId: host.getSelectedElementId(),
|
|
51
47
|
content: newContent,
|
|
52
48
|
dataSourceLocation: element.dataset.sourceLocation,
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import path from "node:path";
|
|
1
2
|
import type { Plugin, UserConfig } from "vite";
|
|
2
3
|
import { loadEnv } from "vite";
|
|
3
4
|
import { errorOverlayPlugin } from "./error-overlay-plugin.js";
|
|
@@ -8,6 +9,19 @@ import { buildStatusPlugin } from "./build-status-plugin.js";
|
|
|
8
9
|
|
|
9
10
|
const isRunningInSandbox = !!process.env.MODAL_SANDBOX_ID;
|
|
10
11
|
|
|
12
|
+
const ENV_UNSET_GUIDANCE = [
|
|
13
|
+
"[base44] No Base44 backend configured — VITE_BASE44_APP_BASE_URL is not set, so /api requests have nowhere to go.",
|
|
14
|
+
"[base44] Run the app through the Base44 CLI instead:",
|
|
15
|
+
"[base44] base44 dev app + local backend (throwaway local data)",
|
|
16
|
+
"[base44] base44 dev --remote app + your app's real backend (production data)",
|
|
17
|
+
].join("\n");
|
|
18
|
+
|
|
19
|
+
const BUILD_WITHOUT_APP_ID_WARNING = [
|
|
20
|
+
"[base44] Warning: VITE_BASE44_APP_ID is not set — this build",
|
|
21
|
+
"[base44] will not know its app id and its API calls will fail.",
|
|
22
|
+
"[base44] Build with: base44 build (or base44 deploy --build)",
|
|
23
|
+
].join("\n");
|
|
24
|
+
|
|
11
25
|
export default function vitePlugin(
|
|
12
26
|
opts: {
|
|
13
27
|
legacySDKImports?: boolean;
|
|
@@ -28,9 +42,14 @@ export default function vitePlugin(
|
|
|
28
42
|
return [
|
|
29
43
|
{
|
|
30
44
|
name: "base44",
|
|
31
|
-
config: (
|
|
45
|
+
config: (config, { command }) => {
|
|
46
|
+
const { mode, root = process.cwd() } = config;
|
|
32
47
|
const env = loadEnv(mode ?? "development", root, "");
|
|
33
48
|
|
|
49
|
+
if (!isRunningInSandbox && command === "build" && !env.VITE_BASE44_APP_ID) {
|
|
50
|
+
console.log(BUILD_WITHOUT_APP_ID_WARNING);
|
|
51
|
+
}
|
|
52
|
+
|
|
34
53
|
return {
|
|
35
54
|
resolve: {
|
|
36
55
|
alias: {
|
|
@@ -59,6 +78,19 @@ export default function vitePlugin(
|
|
|
59
78
|
strictPort: true,
|
|
60
79
|
// Allow all hosts - essential for Modal tunnel URLs
|
|
61
80
|
allowedHosts: true,
|
|
81
|
+
fs: {
|
|
82
|
+
strict: true,
|
|
83
|
+
// Vite replaces its default deny list when one is provided, so preserve those defaults here.
|
|
84
|
+
deny: [
|
|
85
|
+
".env",
|
|
86
|
+
".env.*",
|
|
87
|
+
"*.{crt,pem}",
|
|
88
|
+
"**/.git/**",
|
|
89
|
+
// base44/ contains backend code and the Base44 manifest — never serve it from the dev server.
|
|
90
|
+
// Root-anchored on purpose: some apps have a stray src/base44/ that IS frontend code.
|
|
91
|
+
path.resolve(root, "base44").replace(/\\/g, "/") + "/**",
|
|
92
|
+
],
|
|
93
|
+
},
|
|
62
94
|
// Route the HMR WebSocket through the preview proxy instead of
|
|
63
95
|
// the sandbox origin. When BASE44_HMR_HOST is unset (e.g. before
|
|
64
96
|
// the proxy is deployed), fall back to Vite's default behavior
|
|
@@ -110,7 +142,9 @@ export default function vitePlugin(
|
|
|
110
142
|
};
|
|
111
143
|
}
|
|
112
144
|
console.log(
|
|
113
|
-
|
|
145
|
+
command === "serve"
|
|
146
|
+
? ENV_UNSET_GUIDANCE
|
|
147
|
+
: "[base44] Proxy not enabled (VITE_BASE44_APP_BASE_URL not set)"
|
|
114
148
|
);
|
|
115
149
|
return {};
|
|
116
150
|
})()),
|
|
@@ -56,7 +56,7 @@ function onAppError({
|
|
|
56
56
|
}: {
|
|
57
57
|
title: string;
|
|
58
58
|
details: string;
|
|
59
|
-
componentName: string;
|
|
59
|
+
componentName: string | undefined;
|
|
60
60
|
originalError: any;
|
|
61
61
|
}) {
|
|
62
62
|
if (originalError?.response?.status === 402) {
|
|
@@ -80,35 +80,52 @@ function onAppError({
|
|
|
80
80
|
);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
function
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
83
|
+
// extract function name from "at X (eval" where X is the function name
|
|
84
|
+
function extractFunctionName(stack: unknown): string | undefined {
|
|
85
|
+
if (typeof stack !== "string") return undefined;
|
|
86
|
+
return stack.match(/at\s+(\w+)\s+\(eval/)?.[1];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// A rejection reason or error can be any value — undefined, a string, a
|
|
90
|
+
// null-prototype object. Throwing here masks the real error entirely.
|
|
91
|
+
function describeErrorValue(value: unknown): string {
|
|
92
|
+
try {
|
|
93
|
+
return String(value);
|
|
94
|
+
} catch {
|
|
95
|
+
return Object.prototype.toString.call(value);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function handleUnhandledRejection(event: any) {
|
|
100
|
+
const reason = event?.reason;
|
|
101
|
+
const functionName = extractFunctionName(reason?.stack);
|
|
102
|
+
const text = describeErrorValue(reason);
|
|
103
|
+
const msg = functionName ? `Error in ${functionName}: ${text}` : text;
|
|
90
104
|
onAppError({
|
|
91
105
|
title: msg,
|
|
92
|
-
details:
|
|
106
|
+
details: text,
|
|
93
107
|
componentName: functionName,
|
|
94
|
-
originalError:
|
|
108
|
+
originalError: reason,
|
|
95
109
|
});
|
|
96
110
|
}
|
|
97
111
|
|
|
98
|
-
function handleWindowError(event: any) {
|
|
99
|
-
const
|
|
100
|
-
let functionName = stack
|
|
112
|
+
export function handleWindowError(event: any) {
|
|
113
|
+
const error = event?.error;
|
|
114
|
+
let functionName = extractFunctionName(error?.stack);
|
|
101
115
|
if (functionName === "eval") {
|
|
102
|
-
functionName =
|
|
116
|
+
functionName = undefined;
|
|
103
117
|
}
|
|
104
118
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
119
|
+
// window.onerror fires with a null error for cross-origin script failures
|
|
120
|
+
const text =
|
|
121
|
+
error == null && typeof event?.message === "string"
|
|
122
|
+
? event.message
|
|
123
|
+
: describeErrorValue(error);
|
|
124
|
+
const msg = functionName ? `in ${functionName}: ${text}` : text;
|
|
108
125
|
onAppError({
|
|
109
126
|
title: msg,
|
|
110
|
-
details:
|
|
127
|
+
details: text,
|
|
111
128
|
componentName: functionName,
|
|
112
|
-
originalError:
|
|
129
|
+
originalError: error,
|
|
113
130
|
});
|
|
114
131
|
}
|
package/src/injections/utils.ts
CHANGED
|
@@ -98,6 +98,15 @@ export function updateElementAttribute(elements: Element[], attribute: string, v
|
|
|
98
98
|
});
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Read an element's classes as a plain string, safe to postMessage.
|
|
103
|
+
* `element.className` is an SVGAnimatedString on SVG elements, which is not
|
|
104
|
+
* structured-cloneable — posting it throws DataCloneError and the preview hangs.
|
|
105
|
+
*/
|
|
106
|
+
export function readElementClasses(element: Element): string {
|
|
107
|
+
return element.getAttribute("class") ?? "";
|
|
108
|
+
}
|
|
109
|
+
|
|
101
110
|
/** Collect attribute values from an element for a given allowlist. */
|
|
102
111
|
export function collectAllowedAttributes(element: Element, allowedAttributes: string[]): Record<string, string> {
|
|
103
112
|
const attributes: Record<string, string> = {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { findElementsById, updateElementClasses, updateElementAttribute, collectAllowedAttributes, ALLOWED_ATTRIBUTES, getElementSelectorId, stopAnimations, resumeAnimations, findInstrumentedElement, resolveHoverTarget, positionLabel, injectFontFaceCss } from "./utils.js";
|
|
1
|
+
import { findElementsById, updateElementClasses, updateElementAttribute, collectAllowedAttributes, readElementClasses, ALLOWED_ATTRIBUTES, getElementSelectorId, stopAnimations, resumeAnimations, findInstrumentedElement, resolveHoverTarget, positionLabel, injectFontFaceCss } from "./utils.js";
|
|
2
2
|
import { createLayerController } from "./layer-dropdown/controller.js";
|
|
3
3
|
import { LAYER_DROPDOWN_ATTR } from "./layer-dropdown/consts.js";
|
|
4
4
|
import { createInlineEditController } from "../capabilities/inline-edit/index.js";
|
|
@@ -137,7 +137,6 @@ export function setupVisualEditAgent() {
|
|
|
137
137
|
const notifyElementSelected = (element: Element) => {
|
|
138
138
|
const htmlElement = element as HTMLElement;
|
|
139
139
|
const rect = element.getBoundingClientRect();
|
|
140
|
-
const svgElement = element as SVGElement;
|
|
141
140
|
const isTextElement = TEXT_TAGS.includes(element.tagName?.toLowerCase());
|
|
142
141
|
|
|
143
142
|
const arrEl = htmlElement.closest("[data-arr-variable-name]") as HTMLElement | null;
|
|
@@ -153,10 +152,7 @@ export function setupVisualEditAgent() {
|
|
|
153
152
|
window.parent.postMessage({
|
|
154
153
|
type: "element-selected",
|
|
155
154
|
tagName: element.tagName,
|
|
156
|
-
classes:
|
|
157
|
-
(svgElement.className as unknown as SVGAnimatedString)?.baseVal ||
|
|
158
|
-
element.className ||
|
|
159
|
-
"",
|
|
155
|
+
classes: readElementClasses(element),
|
|
160
156
|
visualSelectorId: getElementSelectorId(element),
|
|
161
157
|
content: isTextElement ? htmlElement.innerText : undefined,
|
|
162
158
|
dataSourceLocation: htmlElement.dataset.sourceLocation,
|
|
@@ -382,6 +382,18 @@ export class DataItemFieldProcessor {
|
|
|
382
382
|
}
|
|
383
383
|
|
|
384
384
|
const fieldToInject = idField ?? "id";
|
|
385
|
+
|
|
386
|
+
// Never inject a param whose name is already bound where the JSX
|
|
387
|
+
// element sits. A function-scope binding (e.g. `const { id } =
|
|
388
|
+
// useParams()`) makes the output fail to compile — "The symbol 'id'
|
|
389
|
+
// has already been declared" — an outer-scope binding would be
|
|
390
|
+
// silently shadowed by an undefined prop, and a block-scope binding
|
|
391
|
+
// between the element and the function would make the emitted
|
|
392
|
+
// attribute read the wrong value. Anchoring on the element's scope
|
|
393
|
+
// chain covers all three; skipping just degrades visual-edit tracing
|
|
394
|
+
// for this element.
|
|
395
|
+
if (path.scope.hasBinding(fieldToInject)) return;
|
|
396
|
+
|
|
385
397
|
const newProp = this.types.objectProperty(
|
|
386
398
|
this.types.identifier(fieldToInject),
|
|
387
399
|
this.types.identifier(fieldToInject),
|
|
@@ -29,7 +29,7 @@ It adds two HTML `data-*` attributes to every JSX element:
|
|
|
29
29
|
| Condition | Where | Why |
|
|
30
30
|
|-----------|-------|-----|
|
|
31
31
|
| `MODAL_SANDBOX_ID` env var is set | `index.ts:8` | Only runs inside Modal sandbox containers |
|
|
32
|
-
|
|
|
32
|
+
| Dev **server** in `"development"` mode | `apply: (config, env) => env.command === "serve" && config.mode === "development"` | The injected `data-*` markers are only consumed by the visual-edit agent in the live preview, which the dev server serves. Builds never use them — including `vite build --mode development` (the platform's validation build), where instrumenting user code once produced compile errors on code that wasn't on disk |
|
|
33
33
|
| File is `.js`, `.jsx`, `.ts`, or `.tsx` | `id.match(/\.(jsx?\|tsx?)$/)` | Only JSX-capable files |
|
|
34
34
|
| File is NOT in `node_modules` | `id.includes("node_modules")` | Skip third-party code |
|
|
35
35
|
| File is NOT `visual-edit-agent` | `id.includes("visual-edit-agent")` | Don't instrument the agent itself |
|
|
@@ -37,7 +37,8 @@ It adds two HTML `data-*` attributes to every JSX element:
|
|
|
37
37
|
### Execution Timeline
|
|
38
38
|
|
|
39
39
|
```
|
|
40
|
-
1. npm run dev
|
|
40
|
+
1. npm run dev (dev SERVER only — `vite build` never registers this plugin,
|
|
41
|
+
regardless of mode)
|
|
41
42
|
2. Vite starts, loads plugin config
|
|
42
43
|
3. index.ts checks: isRunningInSandbox = !!process.env.MODAL_SANDBOX_ID
|
|
43
44
|
4. If true → registers visualEditPlugin() in the plugin pipeline
|
|
@@ -2,14 +2,21 @@ import { parse } from "@babel/parser";
|
|
|
2
2
|
import { default as traverse } from "@babel/traverse";
|
|
3
3
|
import { default as generate } from "@babel/generator";
|
|
4
4
|
import * as t from "@babel/types";
|
|
5
|
-
import type { Plugin } from "vite";
|
|
5
|
+
import type { ConfigEnv, Plugin, UserConfig } from "vite";
|
|
6
6
|
import { JSXProcessor } from "./jsx-processor.js";
|
|
7
7
|
import { JSXUtils } from "./jsx-utils.js";
|
|
8
8
|
|
|
9
9
|
export function visualEditPlugin() {
|
|
10
10
|
return {
|
|
11
11
|
name: "visual-edit-transform",
|
|
12
|
-
|
|
12
|
+
// Dev SERVER only: the injected data-* markers are consumed by the
|
|
13
|
+
// visual-edit agent in the live preview, which vite serves — never by
|
|
14
|
+
// build output. Gating on mode alone also caught `vite build --mode
|
|
15
|
+
// development` (the platform's validation build), where instrumenting
|
|
16
|
+
// user code is pure risk: an injection bug there fails the build on
|
|
17
|
+
// code that doesn't exist on disk.
|
|
18
|
+
apply: (config: UserConfig, env: ConfigEnv) =>
|
|
19
|
+
env.command === "serve" && config.mode === "development",
|
|
13
20
|
enforce: "pre",
|
|
14
21
|
order: "pre",
|
|
15
22
|
transformIndexHtml(html: any) {
|