@base44-preview/vite-plugin 1.0.46-pr.136.11ca3d8 → 1.0.46-pr.136.6f6c15f
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 +7 -3
- package/compat/workerd-enter-with.mjs +18 -5
- package/compat/workerd-ws.cjs +78 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -6
- package/dist/index.js.map +1 -1
- package/dist/utils.d.ts +1 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +4 -0
- package/dist/utils.js.map +1 -1
- package/dist/workerd-compat-plugin.d.ts +17 -5
- package/dist/workerd-compat-plugin.d.ts.map +1 -1
- package/dist/workerd-compat-plugin.js +179 -32
- package/dist/workerd-compat-plugin.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +4 -6
- package/src/utils.ts +5 -0
- package/src/workerd-compat-plugin.ts +200 -34
package/README.md
CHANGED
|
@@ -61,14 +61,18 @@ dependency optimizer, for esbuild (Vite 7) and Rolldown (Vite 8):
|
|
|
61
61
|
- **`ws`** resolves to `compat/workerd-ws.cjs`, a `ws`-shaped client over workerd's
|
|
62
62
|
native WebSocket. The package's own browser build only throws. `WebSocketServer`
|
|
63
63
|
throws too: server code can open sockets but not listen.
|
|
64
|
-
- **`AsyncLocalStorage.enterWith()`**, which workerd
|
|
65
|
-
that calls it first imports `compat/workerd-enter-with.mjs`.
|
|
64
|
+
- **`AsyncLocalStorage.enterWith()`**, which always throws in workerd, becomes a
|
|
65
|
+
no-op. A module that calls it first imports `compat/workerd-enter-with.mjs`. The
|
|
66
|
+
no-op is global to the isolate: any code that relies on `enterWith()` to
|
|
67
|
+
propagate state gets nothing, silently, instead of an exception. Use `run()`.
|
|
66
68
|
- **`createRequire()` in dev** gets its argument's query string dropped. Optimized
|
|
67
69
|
dependencies carry Vite's `?v=` query, which workerd rejects. Builds are left
|
|
68
70
|
byte-for-byte alone.
|
|
69
71
|
|
|
70
72
|
Stagehand 3 needs all three. `@base44/functions-compiler` applies the first two to
|
|
71
|
-
backend functions.
|
|
73
|
+
backend functions. Cloudflare's `nodejs_compat` flag does not cover any of them:
|
|
74
|
+
its `node:http` client cannot upgrade a connection, which `ws` needs, `enterWith()`
|
|
75
|
+
throws by design, and `createRequire()` rejects queries.
|
|
72
76
|
|
|
73
77
|
### Build-status endpoint
|
|
74
78
|
|
|
@@ -1,7 +1,20 @@
|
|
|
1
|
-
// Imported ahead of any Cloudflare Workers server module that calls enterWith
|
|
2
|
-
// by the base44-workerd-compat plugin. workerd
|
|
3
|
-
// AsyncLocalStorage.enterWith
|
|
4
|
-
// context they also pass explicitly, so a no-op
|
|
1
|
+
// Imported ahead of any Cloudflare Workers server module that calls enterWith,
|
|
2
|
+
// by the base44-workerd-compat plugin. workerd defines
|
|
3
|
+
// AsyncLocalStorage.prototype.enterWith but makes it always throw; libraries such
|
|
4
|
+
// as Stagehand call it to seed a context they also pass explicitly, so a no-op
|
|
5
|
+
// keeps them working.
|
|
6
|
+
//
|
|
7
|
+
// The no-op is global: any caller in the isolate that relies on enterWith to
|
|
8
|
+
// propagate state gets nothing instead of an exception. Storing the value per
|
|
9
|
+
// instance instead would leak it across the concurrent requests an isolate
|
|
10
|
+
// serves, which is worse. A runtime whose enterWith works is left alone.
|
|
5
11
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6
12
|
|
|
7
|
-
AsyncLocalStorage.prototype.enterWith
|
|
13
|
+
const native = AsyncLocalStorage.prototype.enterWith;
|
|
14
|
+
let works = false;
|
|
15
|
+
try {
|
|
16
|
+
native.call(new AsyncLocalStorage(), undefined);
|
|
17
|
+
works = true;
|
|
18
|
+
} catch {}
|
|
19
|
+
|
|
20
|
+
if (!works) AsyncLocalStorage.prototype.enterWith = function enterWith() {};
|
package/compat/workerd-ws.cjs
CHANGED
|
@@ -3,14 +3,23 @@
|
|
|
3
3
|
// build needs node:net; workerd has a native WebSocket client, so this is a
|
|
4
4
|
// `ws`-shaped client over it. Kept in step with @base44/functions-compiler's copy.
|
|
5
5
|
"use strict";
|
|
6
|
+
const CONNECTING = 0;
|
|
7
|
+
const OPEN = 1;
|
|
8
|
+
const CLOSING = 2;
|
|
9
|
+
const CLOSED = 3;
|
|
6
10
|
const toBuffer = (value) => (globalThis.Buffer ? globalThis.Buffer.from(value) : value);
|
|
11
|
+
// The WHATWG close() that workerd implements accepts fewer codes than `ws` does.
|
|
12
|
+
const isWhatwgCloseCode = (code) => code === 1000 || (code >= 3000 && code <= 4999);
|
|
13
|
+
const later = (fn, ...args) => queueMicrotask(() => fn(...args));
|
|
7
14
|
class WebSocket {
|
|
8
|
-
static CONNECTING =
|
|
9
|
-
static OPEN =
|
|
10
|
-
static CLOSING =
|
|
11
|
-
static CLOSED =
|
|
15
|
+
static CONNECTING = CONNECTING;
|
|
16
|
+
static OPEN = OPEN;
|
|
17
|
+
static CLOSING = CLOSING;
|
|
18
|
+
static CLOSED = CLOSED;
|
|
12
19
|
#socket;
|
|
13
20
|
#listeners = new Map();
|
|
21
|
+
#maxListeners = 10;
|
|
22
|
+
#terminated = false;
|
|
14
23
|
constructor(address, protocols) {
|
|
15
24
|
this.#socket = new globalThis.WebSocket(String(address), typeof protocols === "string" || Array.isArray(protocols) ? protocols : undefined);
|
|
16
25
|
try { this.#socket.binaryType = "arraybuffer"; } catch {}
|
|
@@ -20,14 +29,18 @@ class WebSocket {
|
|
|
20
29
|
this.emit("message", toBuffer(isBinary ? new Uint8Array(event.data) : event.data), isBinary);
|
|
21
30
|
});
|
|
22
31
|
this.#socket.addEventListener("error", (event) => this.emit("error", event.error ?? new Error(event.message || "WebSocket error")));
|
|
23
|
-
this.#socket.addEventListener("close", (event) =>
|
|
32
|
+
this.#socket.addEventListener("close", (event) => {
|
|
33
|
+
if (!this.#terminated) this.emit("close", event.code, toBuffer(event.reason ?? ""));
|
|
34
|
+
});
|
|
24
35
|
}
|
|
25
|
-
get readyState() { return this.#socket.readyState; }
|
|
36
|
+
get readyState() { return this.#terminated ? CLOSED : this.#socket.readyState; }
|
|
26
37
|
get url() { return this.#socket.url; }
|
|
27
38
|
get protocol() { return this.#socket.protocol; }
|
|
28
|
-
on(name, listener) { return this.#add(name, listener, false); }
|
|
29
|
-
addListener(name, listener) { return this.#add(name, listener, false); }
|
|
30
|
-
once(name, listener) { return this.#add(name, listener, true); }
|
|
39
|
+
on(name, listener) { return this.#add(name, listener, false, false); }
|
|
40
|
+
addListener(name, listener) { return this.#add(name, listener, false, false); }
|
|
41
|
+
once(name, listener) { return this.#add(name, listener, true, false); }
|
|
42
|
+
prependListener(name, listener) { return this.#add(name, listener, false, true); }
|
|
43
|
+
prependOnceListener(name, listener) { return this.#add(name, listener, true, true); }
|
|
31
44
|
off(name, listener) { return this.removeListener(name, listener); }
|
|
32
45
|
removeListener(name, listener) {
|
|
33
46
|
const listeners = this.#listeners.get(name);
|
|
@@ -39,7 +52,13 @@ class WebSocket {
|
|
|
39
52
|
else this.#listeners.delete(name);
|
|
40
53
|
return this;
|
|
41
54
|
}
|
|
55
|
+
listeners(name) { return (this.#listeners.get(name) ?? []).map((entry) => entry.listener); }
|
|
56
|
+
listenerCount(name) { return this.#listeners.get(name)?.length ?? 0; }
|
|
57
|
+
eventNames() { return [...this.#listeners.keys()].filter((name) => this.listenerCount(name) > 0); }
|
|
58
|
+
setMaxListeners(count) { this.#maxListeners = count; return this; }
|
|
59
|
+
getMaxListeners() { return this.#maxListeners; }
|
|
42
60
|
emit(name, ...args) {
|
|
61
|
+
// Dispatch to a snapshot, as Node's EventEmitter does.
|
|
43
62
|
const listeners = this.#listeners.get(name) ?? [];
|
|
44
63
|
this.#listeners.set(name, listeners.filter((entry) => !entry.once));
|
|
45
64
|
for (const entry of listeners) entry.listener.apply(this, args);
|
|
@@ -49,27 +68,68 @@ class WebSocket {
|
|
|
49
68
|
const done = typeof options === "function" ? options : callback;
|
|
50
69
|
try {
|
|
51
70
|
this.#socket.send(data);
|
|
52
|
-
done?.();
|
|
53
71
|
} catch (error) {
|
|
54
72
|
if (!done) throw error;
|
|
55
|
-
done
|
|
73
|
+
later(done, error);
|
|
74
|
+
return;
|
|
56
75
|
}
|
|
76
|
+
// `ws` reports completion asynchronously; so does this.
|
|
77
|
+
if (done) later(done);
|
|
78
|
+
}
|
|
79
|
+
// workerd answers the peer's pings itself but cannot send one. A keepalive
|
|
80
|
+
// loop waiting for "pong" would otherwise kill a healthy socket, so an open
|
|
81
|
+
// socket answers with one.
|
|
82
|
+
ping(data, mask, callback) {
|
|
83
|
+
const done = [data, mask, callback].find((arg) => typeof arg === "function");
|
|
84
|
+
if (this.readyState === OPEN) later(() => this.emit("pong", toBuffer("")));
|
|
85
|
+
if (done) later(done);
|
|
86
|
+
}
|
|
87
|
+
pong(data, mask, callback) {
|
|
88
|
+
const done = [data, mask, callback].find((arg) => typeof arg === "function");
|
|
89
|
+
if (done) later(done);
|
|
57
90
|
}
|
|
58
|
-
close(code, reason) {
|
|
59
|
-
|
|
60
|
-
|
|
91
|
+
close(code, reason) {
|
|
92
|
+
try {
|
|
93
|
+
this.#socket.close(code, reason);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
// A code `ws` accepts but WHATWG close() rejects, such as 1001.
|
|
96
|
+
if (code === undefined || isWhatwgCloseCode(code)) throw error;
|
|
97
|
+
this.#socket.close(1000, reason);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// `ws` tears the connection down at once. workerd has no abrupt close, so the
|
|
101
|
+
// socket is closed normally and "close" is reported now, not on the reply.
|
|
102
|
+
terminate() {
|
|
103
|
+
if (this.#terminated || this.#socket.readyState === CLOSED) return;
|
|
104
|
+
this.#terminated = true;
|
|
105
|
+
try { this.#socket.close(); } catch {}
|
|
106
|
+
later(() => this.emit("close", 1006, toBuffer("")));
|
|
107
|
+
}
|
|
108
|
+
#add(name, listener, once, prepend) {
|
|
61
109
|
const listeners = this.#listeners.get(name) ?? [];
|
|
62
|
-
listeners.
|
|
110
|
+
if (prepend) listeners.unshift({ listener, once });
|
|
111
|
+
else listeners.push({ listener, once });
|
|
63
112
|
this.#listeners.set(name, listeners);
|
|
64
113
|
return this;
|
|
65
114
|
}
|
|
66
115
|
}
|
|
116
|
+
Object.assign(WebSocket.prototype, { CONNECTING, OPEN, CLOSING, CLOSED });
|
|
117
|
+
const unavailable = (what) => new Error(`ws ${what} is not available in Cloudflare Workers server code, which only supports the ws WebSocket client.`);
|
|
67
118
|
class WebSocketServer {
|
|
68
|
-
constructor() {
|
|
69
|
-
|
|
70
|
-
|
|
119
|
+
constructor() { throw unavailable("WebSocketServer"); }
|
|
120
|
+
}
|
|
121
|
+
class Receiver {
|
|
122
|
+
constructor() { throw unavailable("Receiver"); }
|
|
123
|
+
}
|
|
124
|
+
class Sender {
|
|
125
|
+
constructor() { throw unavailable("Sender"); }
|
|
71
126
|
}
|
|
127
|
+
function createWebSocketStream() { throw unavailable("createWebSocketStream"); }
|
|
72
128
|
module.exports = WebSocket;
|
|
73
129
|
module.exports.WebSocket = WebSocket;
|
|
74
130
|
module.exports.WebSocketServer = WebSocketServer;
|
|
131
|
+
module.exports.Server = WebSocketServer;
|
|
132
|
+
module.exports.Receiver = Receiver;
|
|
133
|
+
module.exports.Sender = Sender;
|
|
134
|
+
module.exports.createWebSocketStream = createWebSocketStream;
|
|
75
135
|
module.exports.default = WebSocket;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAc,MAAM,MAAM,CAAC;AAU/C,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAc,MAAM,MAAM,CAAC;AAU/C,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAiBlD,eAAO,MAAM,uBAAuB,UAWnC,CAAC;AAeF,MAAM,CAAC,OAAO,UAAU,UAAU,CAChC,IAAI,GAAE;IACJ,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CACvB,iBA2PP"}
|
package/dist/index.js
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { loadEnv
|
|
2
|
+
import { loadEnv } from "vite";
|
|
3
3
|
import { errorOverlayPlugin } from "./error-overlay-plugin.js";
|
|
4
4
|
import { visualEditPlugin } from "./visual-edit-plugin.js";
|
|
5
|
-
import { filterPackagesInProject } from "./utils.js";
|
|
5
|
+
import { filterPackagesInProject, isVite8OrLater } from "./utils.js";
|
|
6
6
|
import { htmlInjectionsPlugin } from "./html-injections-plugin.js";
|
|
7
7
|
import { buildStatusPlugin } from "./build-status-plugin.js";
|
|
8
8
|
import { base44RuntimePlugin } from "./base44-runtime-plugin.js";
|
|
9
9
|
import { workerdCompatPlugin } from "./workerd-compat-plugin.js";
|
|
10
10
|
import { routeRequestLogPlugin } from "./route-request-log/vite-plugin.js";
|
|
11
11
|
const isRunningInSandbox = !!process.env.MODAL_SANDBOX_ID;
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// treat .js files as JSX, since app code routinely puts JSX in .js.
|
|
15
|
-
const isVite8OrLater = Number(viteVersion.split(".")[0]) >= 8;
|
|
12
|
+
// Both optimizer spellings mean the same thing here: treat .js files as JSX,
|
|
13
|
+
// since app code routinely puts JSX in .js.
|
|
16
14
|
const jsxInJsFiles = isVite8OrLater
|
|
17
15
|
? { rolldownOptions: { moduleTypes: { ".js": "jsx" } } }
|
|
18
16
|
: { esbuildOptions: { loader: { ".js": "jsx" } } };
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAG3E,MAAM,kBAAkB,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;AAE1D,6EAA6E;AAC7E,4CAA4C;AAC5C,MAAM,YAAY,GAAG,cAAc;IACjC,CAAC,CAAC,EAAE,eAAe,EAAE,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;IACxD,CAAC,CAAC,EAAE,cAAc,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AAErD,0EAA0E;AAC1E,8EAA8E;AAC9E,+EAA+E;AAC/E,8EAA8E;AAC9E,4EAA4E;AAC5E,2EAA2E;AAC3E,yDAAyD;AACzD,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,OAAO;IACP,mBAAmB;IACnB,uBAAuB;IACvB,WAAW;IACX,kBAAkB;IAClB,kBAAkB;IAClB,eAAe;IACf,QAAQ;IACR,QAAQ;IACR,aAAa;CACd,CAAC;AAEF,MAAM,kBAAkB,GAAG;IACzB,mHAAmH;IACnH,sDAAsD;IACtD,4EAA4E;IAC5E,iFAAiF;CAClF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,MAAM,4BAA4B,GAAG;IACnC,8DAA8D;IAC9D,gEAAgE;IAChE,iEAAiE;CAClE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,MAAM,CAAC,OAAO,UAAU,UAAU,CAChC,OAMI,EAAE;IAEN,MAAM,EACJ,gBAAgB,GAAG,KAAK,EACxB,WAAW,GAAG,KAAK,EACnB,kBAAkB,GAAG,KAAK,EAC1B,eAAe,GAAG,KAAK,EACvB,gBAAgB,GAAG,KAAK,GACzB,GAAG,IAAI,CAAC;IAET,OAAO;QACL;YACE,IAAI,EAAE,QAAQ;YACd,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;gBAC9B,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,MAAM,CAAC;gBAC9C,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,IAAI,aAAa,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;gBAErD,IAAI,CAAC,kBAAkB,IAAI,OAAO,KAAK,OAAO,IAAI,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC;oBAC1E,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;gBAC5C,CAAC;gBAED,OAAO;oBACL,OAAO,EAAE;wBACP,KAAK,EAAE;4BACL,IAAI,EAAE,OAAO;yBACd;qBACF;oBACD,GAAG,CAAC,gBAAgB;wBAClB,CAAC,CAAC;4BACE,MAAM,EAAE;gCACN,gCAAgC,EAAE,IAAI,CAAC,SAAS,CAC9C,GAAG,CAAC,kBAAkB,CACvB;gCACD,qCAAqC,EAAE,IAAI,CAAC,SAAS,CACnD,GAAG,CAAC,uBAAuB,CAC5B;6BACF;yBACF;wBACH,CAAC,CAAC,EAAE,CAAC;oBACP,GAAG,CAAC,kBAAkB;wBACpB,CAAC,CAAE;4BACC,QAAQ,EAAE,OAAO;4BACjB,MAAM,EAAE;gCACN,IAAI,EAAE,IAAI;gCACV,IAAI,EAAE,SAAS,EAAE,8CAA8C;gCAC/D,IAAI,EAAE,IAAI;gCACV,UAAU,EAAE,IAAI;gCAChB,oDAAoD;gCACpD,YAAY,EAAE,IAAI;gCAClB,EAAE,EAAE;oCACF,MAAM,EAAE,IAAI;oCACZ,6FAA6F;oCAC7F,IAAI,EAAE;wCACJ,MAAM;wCACN,QAAQ;wCACR,aAAa;wCACb,YAAY;wCACZ,8FAA8F;wCAC9F,sFAAsF;wCACtF,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,KAAK;qCACzD;iCACF;gCACD,+DAA+D;gCAC/D,iEAAiE;gCACjE,+DAA+D;gCAC/D,uCAAuC;gCACvC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe;oCAC7B,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,EAAE;oCAChD,CAAC,CAAC,EAAE,CAAC;gCACP,KAAK,EAAE;oCACL,gEAAgE;oCAChE,UAAU,EAAE,IAAI;oCAChB,QAAQ,EAAE,GAAG,EAAE,uCAAuC;oCACtD,yDAAyD;oCACzD,gBAAgB,EAAE;wCAChB,kBAAkB,EAAE,GAAG;wCACvB,YAAY,EAAE,EAAE;qCACjB;iCACF;6BACF;4BACD,KAAK,EAAE;gCACL,aAAa,EAAE;oCACb,MAAM,CAAC,OAAO,EAAE,IAAI;wCAClB,sCAAsC;wCACtC,IACE,OAAO,CAAC,IAAI,KAAK,mBAAmB;4CACpC,OAAO,CAAC,IAAI,KAAK,gBAAgB,EACjC,CAAC;4CACD,MAAM,IAAI,KAAK,CAAC,iBAAiB,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;wCACtD,CAAC;wCACD,iCAAiC;wCACjC,IAAI,CAAC,OAAO,CAAC,CAAC;oCAChB,CAAC;iCACF;6BACF;yBACsB;wBAC3B,CAAC,CAAC,CAAC,GAAG,EAAE;4BACJ,IAAI,GAAG,CAAC,wBAAwB,EAAE,CAAC;gCACjC,OAAO,CAAC,GAAG,CACT,mCAAmC,GAAG,CAAC,wBAAwB,EAAE,CAClE,CAAC;gCACF,OAAO;oCACL,MAAM,EAAE;wCACN,KAAK,EAAE;4CACL,MAAM,EAAE;gDACN,MAAM,EAAE,GAAG,CAAC,wBAAwB;gDACpC,YAAY,EAAE,IAAI;6CACnB;yCACF;qCACF;iCACF,CAAC;4BACJ,CAAC;4BACD,OAAO,CAAC,GAAG,CACT,OAAO,KAAK,OAAO;gCACjB,CAAC,CAAC,kBAAkB;gCACpB,CAAC,CAAC,+DAA+D,CACpE,CAAC;4BACF,OAAO,EAAE,CAAC;wBACZ,CAAC,CAAC,EAAE,CAAC;oBACT,YAAY,EAAE;wBACZ,GAAG,CAAC,kBAAkB;4BACpB,CAAC,CAAC;gCACE,OAAO,EAAE,uBAAuB,CAC9B,uBAAuB,EACvB,IAAI,CACL;6BACF;4BACH,CAAC,CAAC,EAAE,CAAC;wBACP,GAAG,YAAY;qBAChB;iBACF,CAAC;YACJ,CAAC;YACD,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO;gBACvC,yEAAyE;gBACzE,2EAA2E;gBAC3E,IAAI,gBAAgB,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;oBACrD,MAAM,kBAAkB,GAAG,MAAM,IAAI,CAAC,OAAO,CAC3C,MAAM,EACN,QAAQ,EACR,OAAO,CACR,CAAC;oBAEF,IAAI,kBAAkB,EAAE,CAAC;wBACvB,OAAO,kBAAkB,CAAC;oBAC5B,CAAC;oBAED,iFAAiF;oBACjF,uEAAuE;oBACvE,8CAA8C;oBAC9C,IACE,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,CAAC;wBACrC,MAAM,CAAC,UAAU,CAAC,eAAe,CAAC,EAClC,CAAC;wBACD,OAAO,IAAI,CAAC,OAAO,CACjB,MAAM,CAAC,OAAO,CAAC,iBAAiB,EAAE,cAAc,CAAC,EACjD,QAAQ,EACR,OAAO,CACR,CAAC;oBACJ,CAAC;oBAED,iEAAiE;oBACjE,IACE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC;wBAC5B,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC;4BAC1C,MAAM,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,EAC7C,CAAC;wBACD,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;oBACzD,CAAC;oBAED,IAAI,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;wBACjC,OAAO,IAAI,CAAC,OAAO,CACjB,yCAAyC,EACzC,QAAQ,EACR,OAAO,CACR,CAAC;oBACJ,CAAC;oBAED,IAAI,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;wBAClC,OAAO,IAAI,CAAC,OAAO,CACjB,0CAA0C,EAC1C,QAAQ,EACR,OAAO,CACR,CAAC;oBACJ,CAAC;oBAED,IAAI,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;wBACrC,OAAO,IAAI,CAAC,OAAO,CACjB,6CAA6C,EAC7C,QAAQ,EACR,OAAO,CACR,CAAC;oBACJ,CAAC;oBAED,IAAI,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;wBAC/B,OAAO,IAAI,CAAC,OAAO,CACjB,uCAAuC,EACvC,QAAQ,EACR,OAAO,CACR,CAAC;oBACJ,CAAC;gBACH,CAAC;gBAED,OAAO,IAAI,CAAC;YACd,CAAC;SACQ;QACX,GAAG,CAAC,kBAAkB;YACpB,CAAC,CAAC;gBACE;oBACE,IAAI,EAAE,YAAY;oBAClB,eAAe,CAAC,MAAM;wBACpB,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;4BACxC,yBAAyB;4BACzB,GAAG,CAAC,SAAS,CAAC,iBAAiB,EAAE,UAAU,CAAC,CAAC;4BAC7C,GAAG,CAAC,SAAS,CAAC,yBAAyB,EAAE,oBAAoB,CAAC,CAAC;4BAC/D,IAAI,EAAE,CAAC;wBACT,CAAC,CAAC,CAAC;oBACL,CAAC;iBACQ;gBACX,kBAAkB,EAAE;gBACpB,gBAAgB,EAAE;aACnB;YACH,CAAC,CAAC,EAAE,CAAC;QACP,yEAAyE;QACzE,GAAG,oBAAoB,CAAC;YACtB,WAAW;YACX,kBAAkB;YAClB,eAAe;YACf,gBAAgB;YAChB,WAAW,EAAE,kBAAkB;SAChC,CAAC;QACF,yEAAyE;QACzE,iEAAiE;QACjE,sEAAsE;QACtE,wEAAwE;QACxE,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,2BAA2B,KAAK,GAAG;YACjD,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC;YACvB,CAAC,CAAC,EAAE,CAAC;QACP,yEAAyE;QACzE,2EAA2E;QAC3E,yEAAyE;QACzE,iEAAiE;QACjE,mBAAmB,EAAE;QACrB,+EAA+E;QAC/E,wEAAwE;QACxE,mBAAmB,EAAE;QACrB,wEAAwE;QACxE,wEAAwE;QACxE,2EAA2E;QAC3E,4EAA4E;QAC5E,qBAAqB,EAAE;KACxB,CAAC;AACJ,CAAC"}
|
package/dist/utils.d.ts
CHANGED
package/dist/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,cAAc,SAAyC,CAAC;AAcrE,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,EAAE,EAClB,IAAI,EAAE,MAAM,GACX,MAAM,EAAE,CAmBV"}
|
package/dist/utils.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { readFileSync, existsSync } from "fs";
|
|
2
2
|
import { join } from "path";
|
|
3
|
+
import { version as viteVersion } from "vite";
|
|
4
|
+
// Vite 8 pre-bundles deps with Rolldown instead of esbuild and deprecates
|
|
5
|
+
// `optimizeDeps.esbuildOptions`.
|
|
6
|
+
export const isVite8OrLater = Number(viteVersion.split(".")[0]) >= 8;
|
|
3
7
|
/**
|
|
4
8
|
* The package that owns an optimizeDeps entry. Deep entries like
|
|
5
9
|
* `react-dom/client` are separate entries to Vite's optimizer but are declared
|
package/dist/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,MAAM,CAAC;AAE9C,0EAA0E;AAC1E,iCAAiC;AACjC,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAErE;;;;GAIG;AACH,SAAS,aAAa,CAAC,KAAa;IAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;QAC1B,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QAChC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,QAAkB,EAClB,IAAY;IAEZ,IAAI,CAAC;QACH,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;QACnD,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;YACjC,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC;QACvE,MAAM,OAAO,GAAG;YACd,GAAG,WAAW,CAAC,YAAY;YAC3B,GAAG,WAAW,CAAC,eAAe;YAC9B,GAAG,WAAW,CAAC,gBAAgB;SAChC,CAAC;QAEF,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,CAAC;IACjE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,sCAAsC,EAAE,KAAK,CAAC,CAAC;QAC5D,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
|
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
import type { Plugin } from "vite";
|
|
2
2
|
export declare const WORKERD_WS_ADAPTER: string;
|
|
3
3
|
export declare const WORKERD_ENTER_WITH_PATCH: string;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
export interface PatchOptions {
|
|
5
|
+
/** Also route `createRequire` calls through the query-dropping wrapper. */
|
|
6
|
+
createRequire: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Patches a workerd server module: imports the enterWith no-op ahead of a module
|
|
10
|
+
* that calls `.enterWith()`, and, with `createRequire`, routes node:module's
|
|
11
|
+
* `createRequire` through a wrapper that drops the id's query. Code is inserted
|
|
12
|
+
* on the first line after any shebang or directive prologue, so strict mode
|
|
13
|
+
* holds and line numbers stay put. Returns null when nothing applies.
|
|
14
|
+
*/
|
|
15
|
+
export declare function patchServerModule(code: string, id: string, options: PatchOptions): string | null;
|
|
16
|
+
export interface WorkerdCompatOptions {
|
|
17
|
+
/** Which dependency optimizer to hook. Defaults to the installed Vite's. */
|
|
18
|
+
rolldown?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare function workerdCompatPlugin({ rolldown }?: WorkerdCompatOptions): Plugin;
|
|
9
21
|
//# sourceMappingURL=workerd-compat-plugin.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workerd-compat-plugin.d.ts","sourceRoot":"","sources":["../src/workerd-compat-plugin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"workerd-compat-plugin.d.ts","sourceRoot":"","sources":["../src/workerd-compat-plugin.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAsB,MAAM,EAAE,MAAM,MAAM,CAAC;AA4BvD,eAAO,MAAM,kBAAkB,QAA+B,CAAC;AAC/D,eAAO,MAAM,wBAAwB,QAAuC,CAAC;AA8G7E,MAAM,WAAW,YAAY;IAC3B,2EAA2E;IAC3E,aAAa,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI,CAiEhG;AAoDD,MAAM,WAAW,oBAAoB;IACnC,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,mBAAmB,CAAC,EAAE,QAAyB,EAAE,GAAE,oBAAyB,GAAG,MAAM,CAqBpG"}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
-
import {
|
|
3
|
+
import { parse } from "@babel/parser";
|
|
4
|
+
import { default as traverse } from "@babel/traverse";
|
|
5
|
+
import { normalizePath } from "vite";
|
|
6
|
+
import { isVite8OrLater } from "./utils.js";
|
|
4
7
|
/**
|
|
5
|
-
* Closes
|
|
6
|
-
* them) in full-stack server code
|
|
7
|
-
* for backend functions:
|
|
8
|
+
* Closes three workerd gaps that break Node-targeted npm clients (Stagehand among
|
|
9
|
+
* them) in full-stack server code. @base44/functions-compiler covers the first
|
|
10
|
+
* two for backend functions:
|
|
8
11
|
*
|
|
9
12
|
* - `ws`: its exports map sends the "browser" condition (which Cloudflare's Vite
|
|
10
13
|
* plugin resolves with) to a stub that throws on use. It is served as a
|
|
@@ -20,37 +23,180 @@ import { version as viteVersion } from "vite";
|
|
|
20
23
|
* Only environments that resolve with the "workerd" condition are touched, so
|
|
21
24
|
* the browser bundle and a Node-run server keep the real modules.
|
|
22
25
|
*/
|
|
23
|
-
|
|
26
|
+
// Vite ids use forward slashes on every platform, so these must too.
|
|
27
|
+
const compatFile = (name) => normalizePath(fileURLToPath(new URL(`../compat/${name}`, import.meta.url)));
|
|
24
28
|
export const WORKERD_WS_ADAPTER = compatFile("workerd-ws.cjs");
|
|
25
29
|
export const WORKERD_ENTER_WITH_PATCH = compatFile("workerd-enter-with.mjs");
|
|
26
30
|
const isWorkerd = (conditions) => !!conditions?.includes("workerd");
|
|
31
|
+
// `ws` exports only its root, so a deep import never resolves to begin with.
|
|
27
32
|
const redirect = (id) => (id === "ws" ? WORKERD_WS_ADAPTER : null);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
// JSON, CSS and the like reach a "pre" transform raw. Virtual ids often have no
|
|
34
|
+
// extension at all, and are JavaScript.
|
|
35
|
+
const NON_SCRIPT_FILE = /\.(?![cm]?[jt]sx?$)[a-z0-9]+$/i;
|
|
36
|
+
const NODE_MODULE = new Set(["module", "node:module"]);
|
|
37
|
+
const CREATE_REQUIRE_IMPL = "__b44CreateRequireImpl";
|
|
38
|
+
const CREATE_REQUIRE = "__b44CreateRequire";
|
|
39
|
+
// @babel/traverse is CommonJS: Node's ESM interop nests the function under
|
|
40
|
+
// `default`, while bundlers and Vitest hand it over directly.
|
|
41
|
+
const traverseAst = (traverse.default ??
|
|
42
|
+
traverse);
|
|
43
|
+
const pathOf = (id) => id.split("?")[0] ?? id;
|
|
44
|
+
function parserPlugins(file) {
|
|
45
|
+
if (/\.tsx$/.test(file))
|
|
46
|
+
return [["typescript", "jsx"]];
|
|
47
|
+
if (/\.[cm]?ts$/.test(file))
|
|
48
|
+
return [["typescript"]];
|
|
49
|
+
// Apps routinely put JSX in .js, but JSX parsing can misread plain JS, so it
|
|
50
|
+
// is only the fallback.
|
|
51
|
+
return [[], ["jsx"]];
|
|
52
|
+
}
|
|
53
|
+
function parseModule(code, file) {
|
|
54
|
+
for (const plugins of parserPlugins(file)) {
|
|
55
|
+
try {
|
|
56
|
+
return parse(code, {
|
|
57
|
+
// A module is ESM only if it has ESM syntax: text that merely looks
|
|
58
|
+
// like an import, inside a string or comment, does not count.
|
|
59
|
+
sourceType: /\.c[jt]s$/.test(file) ? "script" : /\.m[jt]s$/.test(file) ? "module" : "unambiguous",
|
|
60
|
+
allowReturnOutsideFunction: true,
|
|
61
|
+
allowAwaitOutsideFunction: true,
|
|
62
|
+
plugins,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Try the next plugin set.
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
const isRequireOfNodeModule = (node) => node?.type === "CallExpression" &&
|
|
72
|
+
node.callee.type === "Identifier" &&
|
|
73
|
+
node.callee.name === "require" &&
|
|
74
|
+
node.arguments[0]?.type === "StringLiteral" &&
|
|
75
|
+
NODE_MODULE.has(node.arguments[0].value);
|
|
76
|
+
const keyName = (key) => key.type === "Identifier" ? key.name : key.type === "StringLiteral" ? key.value : undefined;
|
|
77
|
+
/** Whether `name` at `path` is node:module's createRequire, under any alias. */
|
|
78
|
+
function bindsCreateRequire(path, name) {
|
|
79
|
+
const binding = path.scope.getBinding(name);
|
|
80
|
+
if (!binding)
|
|
81
|
+
return false;
|
|
82
|
+
const decl = binding.path.node;
|
|
83
|
+
const parent = binding.path.parent;
|
|
84
|
+
if (decl.type === "ImportSpecifier") {
|
|
85
|
+
return (parent.type === "ImportDeclaration" &&
|
|
86
|
+
NODE_MODULE.has(parent.source.value) &&
|
|
87
|
+
keyName(decl.imported) === "createRequire");
|
|
33
88
|
}
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
89
|
+
// const { createRequire } = require("node:module")
|
|
90
|
+
if (decl.type === "VariableDeclarator" && decl.id.type === "ObjectPattern" && isRequireOfNodeModule(decl.init)) {
|
|
91
|
+
return decl.id.properties.some((prop) => prop.type === "ObjectProperty" &&
|
|
92
|
+
keyName(prop.key) === "createRequire" &&
|
|
93
|
+
prop.value.type === "Identifier" &&
|
|
94
|
+
prop.value.name === name);
|
|
95
|
+
}
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
/** Whether `name` at `path` is node:module itself, as a default, namespace or required binding. */
|
|
99
|
+
function bindsNodeModule(path, name) {
|
|
100
|
+
const binding = path.scope.getBinding(name);
|
|
101
|
+
if (!binding)
|
|
102
|
+
return false;
|
|
103
|
+
const decl = binding.path.node;
|
|
104
|
+
const parent = binding.path.parent;
|
|
105
|
+
if (decl.type === "ImportDefaultSpecifier" || decl.type === "ImportNamespaceSpecifier") {
|
|
106
|
+
return parent.type === "ImportDeclaration" && NODE_MODULE.has(parent.source.value);
|
|
107
|
+
}
|
|
108
|
+
return decl.type === "VariableDeclarator" && decl.id.type === "Identifier" && isRequireOfNodeModule(decl.init);
|
|
37
109
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
110
|
+
/** The callee of a call that reaches node:module's createRequire, or null. */
|
|
111
|
+
function createRequireCallee(path) {
|
|
112
|
+
const callee = path.node.callee;
|
|
113
|
+
if (callee.type === "Identifier") {
|
|
114
|
+
return bindsCreateRequire(path, callee.name) ? callee : null;
|
|
115
|
+
}
|
|
116
|
+
if (callee.type !== "MemberExpression" || callee.computed || keyName(callee.property) !== "createRequire") {
|
|
43
117
|
return null;
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return
|
|
118
|
+
}
|
|
119
|
+
const object = callee.object;
|
|
120
|
+
if (object.type === "Identifier")
|
|
121
|
+
return bindsNodeModule(path, object.name) ? callee : null;
|
|
122
|
+
return isRequireOfNodeModule(object) ? callee : null;
|
|
49
123
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
124
|
+
/**
|
|
125
|
+
* Patches a workerd server module: imports the enterWith no-op ahead of a module
|
|
126
|
+
* that calls `.enterWith()`, and, with `createRequire`, routes node:module's
|
|
127
|
+
* `createRequire` through a wrapper that drops the id's query. Code is inserted
|
|
128
|
+
* on the first line after any shebang or directive prologue, so strict mode
|
|
129
|
+
* holds and line numbers stay put. Returns null when nothing applies.
|
|
130
|
+
*/
|
|
131
|
+
export function patchServerModule(code, id, options) {
|
|
132
|
+
const file = pathOf(id);
|
|
133
|
+
if (NON_SCRIPT_FILE.test(file.slice(file.lastIndexOf("/") + 1)) || file === WORKERD_ENTER_WITH_PATCH)
|
|
134
|
+
return null;
|
|
135
|
+
// The AST makes the call; this only skips files that cannot contain one,
|
|
136
|
+
// including calls a formatter split across lines.
|
|
137
|
+
const mayEnterWith = code.includes("enterWith");
|
|
138
|
+
const mayCreateRequire = options.createRequire && code.includes("createRequire") && !code.includes(CREATE_REQUIRE_IMPL);
|
|
139
|
+
if (!mayEnterWith && !mayCreateRequire)
|
|
140
|
+
return null;
|
|
141
|
+
const ast = parseModule(code, file);
|
|
142
|
+
if (!ast)
|
|
143
|
+
return null;
|
|
144
|
+
let callsEnterWith = false;
|
|
145
|
+
const callees = [];
|
|
146
|
+
const visit = (path) => {
|
|
147
|
+
const callee = path.node.callee;
|
|
148
|
+
if (mayEnterWith &&
|
|
149
|
+
(callee.type === "MemberExpression" || callee.type === "OptionalMemberExpression") &&
|
|
150
|
+
!callee.computed &&
|
|
151
|
+
keyName(callee.property) === "enterWith") {
|
|
152
|
+
callsEnterWith = true;
|
|
153
|
+
}
|
|
154
|
+
const target = mayCreateRequire ? createRequireCallee(path) : null;
|
|
155
|
+
if (target)
|
|
156
|
+
callees.push(target);
|
|
157
|
+
};
|
|
158
|
+
traverseAst(ast, { CallExpression: visit, OptionalCallExpression: visit });
|
|
159
|
+
if (!callsEnterWith && callees.length === 0)
|
|
160
|
+
return null;
|
|
161
|
+
const isEsm = ast.program.sourceType === "module";
|
|
162
|
+
let prefix = "";
|
|
163
|
+
if (callsEnterWith) {
|
|
164
|
+
const patch = JSON.stringify(WORKERD_ENTER_WITH_PATCH);
|
|
165
|
+
// An ESM import in a CommonJS module would turn it into ESM; require it there.
|
|
166
|
+
prefix += isEsm ? `import ${patch};` : `require(${patch});`;
|
|
167
|
+
}
|
|
168
|
+
if (callees.length > 0) {
|
|
169
|
+
prefix += isEsm
|
|
170
|
+
? `import { createRequire as ${CREATE_REQUIRE_IMPL} } from "node:module";`
|
|
171
|
+
: `const { createRequire: ${CREATE_REQUIRE_IMPL} } = require("node:module");`;
|
|
172
|
+
prefix += `const ${CREATE_REQUIRE} = (path) => ${CREATE_REQUIRE_IMPL}(String(path).replace(/[?#].*$/, ""));`;
|
|
173
|
+
}
|
|
174
|
+
// A shebang line cannot be followed on the same line, so the code goes at the
|
|
175
|
+
// start of the next one.
|
|
176
|
+
const { interpreter, directives } = ast.program;
|
|
177
|
+
let afterInterpreter = 0;
|
|
178
|
+
if (interpreter) {
|
|
179
|
+
const newline = code.indexOf("\n", interpreter.end);
|
|
180
|
+
if (newline === -1)
|
|
181
|
+
prefix = `\n${prefix}`;
|
|
182
|
+
afterInterpreter = newline === -1 ? code.length : newline + 1;
|
|
183
|
+
}
|
|
184
|
+
const insertAt = Math.max(afterInterpreter, ...directives.map((d) => d.end));
|
|
185
|
+
// A directive may end without a semicolon, and code cannot follow it directly.
|
|
186
|
+
if (insertAt > afterInterpreter && code[insertAt - 1] !== ";")
|
|
187
|
+
prefix = `;${prefix}`;
|
|
188
|
+
const edits = [
|
|
189
|
+
{ start: insertAt, end: insertAt, text: prefix },
|
|
190
|
+
...callees.map((node) => ({ start: node.start, end: node.end, text: CREATE_REQUIRE })),
|
|
191
|
+
].sort((a, b) => b.start - a.start);
|
|
192
|
+
let out = code;
|
|
193
|
+
for (const edit of edits)
|
|
194
|
+
out = out.slice(0, edit.start) + edit.text + out.slice(edit.end);
|
|
195
|
+
return out;
|
|
53
196
|
}
|
|
197
|
+
const devTransform = (code, id) => patchServerModule(code, id, { createRequire: true });
|
|
198
|
+
// Every edit keeps lines in place, so the input's source map still holds.
|
|
199
|
+
const transformResult = (code) => (code === null ? null : { code, map: null });
|
|
54
200
|
// Dev pre-bundles dependencies without running Vite plugins, so the dependency
|
|
55
201
|
// optimizer, which only runs in dev, needs its own copy. Each copy checks the
|
|
56
202
|
// build's conditions itself: Cloudflare's plugin sets them after ours has run.
|
|
@@ -61,7 +207,8 @@ function esbuildOptimizerPlugin() {
|
|
|
61
207
|
if (!isWorkerd(build.initialOptions.conditions))
|
|
62
208
|
return;
|
|
63
209
|
build.onResolve({ filter: /^ws$/ }, () => ({ path: WORKERD_WS_ADAPTER }));
|
|
64
|
-
|
|
210
|
+
// Other namespaces hold virtual modules with no file to read.
|
|
211
|
+
build.onLoad({ filter: /\.[cm]?js$/, namespace: "file" }, async (args) => {
|
|
65
212
|
const code = devTransform(await readFile(args.path, "utf8"), args.path);
|
|
66
213
|
return code === null ? undefined : { contents: code, loader: "js" };
|
|
67
214
|
});
|
|
@@ -76,12 +223,11 @@ function rolldownOptimizerPlugin() {
|
|
|
76
223
|
active = isWorkerd(options.resolve?.conditionNames);
|
|
77
224
|
},
|
|
78
225
|
resolveId: (id) => (active ? redirect(id) : null),
|
|
79
|
-
transform: (code, id) => (active ? devTransform(code, id) : null),
|
|
226
|
+
transform: (code, id) => (active ? transformResult(devTransform(code, id)) : null),
|
|
80
227
|
};
|
|
81
228
|
}
|
|
82
229
|
const OPTIMIZED_DEP = /[\\/]node_modules[\\/]\.vite[\\/]/;
|
|
83
|
-
|
|
84
|
-
export function workerdCompatPlugin() {
|
|
230
|
+
export function workerdCompatPlugin({ rolldown = isVite8OrLater } = {}) {
|
|
85
231
|
return {
|
|
86
232
|
name: "base44-workerd-compat",
|
|
87
233
|
enforce: "pre",
|
|
@@ -89,9 +235,10 @@ export function workerdCompatPlugin() {
|
|
|
89
235
|
configEnvironment(name) {
|
|
90
236
|
if (name === "client")
|
|
91
237
|
return;
|
|
92
|
-
const optimizeDeps =
|
|
238
|
+
const optimizeDeps = rolldown
|
|
93
239
|
? { rolldownOptions: { plugins: [rolldownOptimizerPlugin()] } }
|
|
94
240
|
: { esbuildOptions: { plugins: [esbuildOptimizerPlugin()] } };
|
|
241
|
+
// Vite 7's types do not know `rolldownOptions`, hence the cast.
|
|
95
242
|
return { optimizeDeps };
|
|
96
243
|
},
|
|
97
244
|
resolveId: (id) => redirect(id),
|
|
@@ -99,7 +246,7 @@ export function workerdCompatPlugin() {
|
|
|
99
246
|
// The optimizer already patched its output.
|
|
100
247
|
if (OPTIMIZED_DEP.test(id))
|
|
101
248
|
return null;
|
|
102
|
-
return this.environment.mode === "dev"
|
|
249
|
+
return transformResult(patchServerModule(code, id, { createRequire: this.environment.mode === "dev" }));
|
|
103
250
|
},
|
|
104
251
|
};
|
|
105
252
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workerd-compat-plugin.js","sourceRoot":"","sources":["../src/workerd-compat-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"workerd-compat-plugin.js","sourceRoot":"","sources":["../src/workerd-compat-plugin.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import type { Plugin, UserConfig } from "vite";
|
|
3
|
-
import { loadEnv
|
|
3
|
+
import { loadEnv } from "vite";
|
|
4
4
|
import { errorOverlayPlugin } from "./error-overlay-plugin.js";
|
|
5
5
|
import { visualEditPlugin } from "./visual-edit-plugin.js";
|
|
6
|
-
import { filterPackagesInProject } from "./utils.js";
|
|
6
|
+
import { filterPackagesInProject, isVite8OrLater } from "./utils.js";
|
|
7
7
|
import { htmlInjectionsPlugin } from "./html-injections-plugin.js";
|
|
8
8
|
import { buildStatusPlugin } from "./build-status-plugin.js";
|
|
9
9
|
import { base44RuntimePlugin } from "./base44-runtime-plugin.js";
|
|
@@ -13,10 +13,8 @@ export type { DocumentScript } from "./consts.js";
|
|
|
13
13
|
|
|
14
14
|
const isRunningInSandbox = !!process.env.MODAL_SANDBOX_ID;
|
|
15
15
|
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
// treat .js files as JSX, since app code routinely puts JSX in .js.
|
|
19
|
-
const isVite8OrLater = Number(viteVersion.split(".")[0]) >= 8;
|
|
16
|
+
// Both optimizer spellings mean the same thing here: treat .js files as JSX,
|
|
17
|
+
// since app code routinely puts JSX in .js.
|
|
20
18
|
const jsxInJsFiles = isVite8OrLater
|
|
21
19
|
? { rolldownOptions: { moduleTypes: { ".js": "jsx" } } }
|
|
22
20
|
: { esbuildOptions: { loader: { ".js": "jsx" } } };
|
package/src/utils.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { readFileSync, existsSync } from "fs";
|
|
2
2
|
import { join } from "path";
|
|
3
|
+
import { version as viteVersion } from "vite";
|
|
4
|
+
|
|
5
|
+
// Vite 8 pre-bundles deps with Rolldown instead of esbuild and deprecates
|
|
6
|
+
// `optimizeDeps.esbuildOptions`.
|
|
7
|
+
export const isVite8OrLater = Number(viteVersion.split(".")[0]) >= 8;
|
|
3
8
|
|
|
4
9
|
/**
|
|
5
10
|
* The package that owns an optimizeDeps entry. Deep entries like
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { parse, type ParserPlugin } from "@babel/parser";
|
|
4
|
+
import { default as traverse, type NodePath } from "@babel/traverse";
|
|
5
|
+
import type * as t from "@babel/types";
|
|
3
6
|
import type { EnvironmentOptions, Plugin } from "vite";
|
|
4
|
-
import {
|
|
7
|
+
import { normalizePath } from "vite";
|
|
8
|
+
import { isVite8OrLater } from "./utils.js";
|
|
5
9
|
|
|
6
10
|
/**
|
|
7
|
-
* Closes
|
|
8
|
-
* them) in full-stack server code
|
|
9
|
-
* for backend functions:
|
|
11
|
+
* Closes three workerd gaps that break Node-targeted npm clients (Stagehand among
|
|
12
|
+
* them) in full-stack server code. @base44/functions-compiler covers the first
|
|
13
|
+
* two for backend functions:
|
|
10
14
|
*
|
|
11
15
|
* - `ws`: its exports map sends the "browser" condition (which Cloudflare's Vite
|
|
12
16
|
* plugin resolves with) to a stub that throws on use. It is served as a
|
|
@@ -23,8 +27,9 @@ import { version as viteVersion } from "vite";
|
|
|
23
27
|
* the browser bundle and a Node-run server keep the real modules.
|
|
24
28
|
*/
|
|
25
29
|
|
|
30
|
+
// Vite ids use forward slashes on every platform, so these must too.
|
|
26
31
|
const compatFile = (name: string) =>
|
|
27
|
-
fileURLToPath(new URL(`../compat/${name}`, import.meta.url));
|
|
32
|
+
normalizePath(fileURLToPath(new URL(`../compat/${name}`, import.meta.url)));
|
|
28
33
|
|
|
29
34
|
export const WORKERD_WS_ADAPTER = compatFile("workerd-ws.cjs");
|
|
30
35
|
export const WORKERD_ENTER_WITH_PATCH = compatFile("workerd-enter-with.mjs");
|
|
@@ -32,39 +37,195 @@ export const WORKERD_ENTER_WITH_PATCH = compatFile("workerd-enter-with.mjs");
|
|
|
32
37
|
const isWorkerd = (conditions: readonly string[] | undefined) =>
|
|
33
38
|
!!conditions?.includes("workerd");
|
|
34
39
|
|
|
40
|
+
// `ws` exports only its root, so a deep import never resolves to begin with.
|
|
35
41
|
const redirect = (id: string) => (id === "ws" ? WORKERD_WS_ADAPTER : null);
|
|
36
42
|
|
|
37
|
-
|
|
43
|
+
// JSON, CSS and the like reach a "pre" transform raw. Virtual ids often have no
|
|
44
|
+
// extension at all, and are JavaScript.
|
|
45
|
+
const NON_SCRIPT_FILE = /\.(?![cm]?[jt]sx?$)[a-z0-9]+$/i;
|
|
46
|
+
const NODE_MODULE = new Set(["module", "node:module"]);
|
|
47
|
+
const CREATE_REQUIRE_IMPL = "__b44CreateRequireImpl";
|
|
48
|
+
const CREATE_REQUIRE = "__b44CreateRequire";
|
|
38
49
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
50
|
+
// @babel/traverse is CommonJS: Node's ESM interop nests the function under
|
|
51
|
+
// `default`, while bundlers and Vitest hand it over directly.
|
|
52
|
+
const traverseAst = ((traverse as unknown as { default?: typeof traverse }).default ??
|
|
53
|
+
traverse) as unknown as typeof traverse.default;
|
|
54
|
+
|
|
55
|
+
const pathOf = (id: string) => id.split("?")[0] ?? id;
|
|
56
|
+
|
|
57
|
+
function parserPlugins(file: string): ParserPlugin[][] {
|
|
58
|
+
if (/\.tsx$/.test(file)) return [["typescript", "jsx"]];
|
|
59
|
+
if (/\.[cm]?ts$/.test(file)) return [["typescript"]];
|
|
60
|
+
// Apps routinely put JSX in .js, but JSX parsing can misread plain JS, so it
|
|
61
|
+
// is only the fallback.
|
|
62
|
+
return [[], ["jsx"]];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function parseModule(code: string, file: string): t.File | null {
|
|
66
|
+
for (const plugins of parserPlugins(file)) {
|
|
67
|
+
try {
|
|
68
|
+
return parse(code, {
|
|
69
|
+
// A module is ESM only if it has ESM syntax: text that merely looks
|
|
70
|
+
// like an import, inside a string or comment, does not count.
|
|
71
|
+
sourceType: /\.c[jt]s$/.test(file) ? "script" : /\.m[jt]s$/.test(file) ? "module" : "unambiguous",
|
|
72
|
+
allowReturnOutsideFunction: true,
|
|
73
|
+
allowAwaitOutsideFunction: true,
|
|
74
|
+
plugins,
|
|
75
|
+
});
|
|
76
|
+
} catch {
|
|
77
|
+
// Try the next plugin set.
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const isRequireOfNodeModule = (node: t.Node | null | undefined): boolean =>
|
|
84
|
+
node?.type === "CallExpression" &&
|
|
85
|
+
node.callee.type === "Identifier" &&
|
|
86
|
+
node.callee.name === "require" &&
|
|
87
|
+
node.arguments[0]?.type === "StringLiteral" &&
|
|
88
|
+
NODE_MODULE.has(node.arguments[0].value);
|
|
89
|
+
|
|
90
|
+
const keyName = (key: t.Node): string | undefined =>
|
|
91
|
+
key.type === "Identifier" ? key.name : key.type === "StringLiteral" ? key.value : undefined;
|
|
92
|
+
|
|
93
|
+
/** Whether `name` at `path` is node:module's createRequire, under any alias. */
|
|
94
|
+
function bindsCreateRequire(path: NodePath, name: string): boolean {
|
|
95
|
+
const binding = path.scope.getBinding(name);
|
|
96
|
+
if (!binding) return false;
|
|
97
|
+
const decl = binding.path.node;
|
|
98
|
+
const parent = binding.path.parent;
|
|
99
|
+
if (decl.type === "ImportSpecifier") {
|
|
100
|
+
return (
|
|
101
|
+
parent.type === "ImportDeclaration" &&
|
|
102
|
+
NODE_MODULE.has(parent.source.value) &&
|
|
103
|
+
keyName(decl.imported) === "createRequire"
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
// const { createRequire } = require("node:module")
|
|
107
|
+
if (decl.type === "VariableDeclarator" && decl.id.type === "ObjectPattern" && isRequireOfNodeModule(decl.init)) {
|
|
108
|
+
return decl.id.properties.some(
|
|
109
|
+
(prop) =>
|
|
110
|
+
prop.type === "ObjectProperty" &&
|
|
111
|
+
keyName(prop.key) === "createRequire" &&
|
|
112
|
+
prop.value.type === "Identifier" &&
|
|
113
|
+
prop.value.name === name,
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Whether `name` at `path` is node:module itself, as a default, namespace or required binding. */
|
|
120
|
+
function bindsNodeModule(path: NodePath, name: string): boolean {
|
|
121
|
+
const binding = path.scope.getBinding(name);
|
|
122
|
+
if (!binding) return false;
|
|
123
|
+
const decl = binding.path.node;
|
|
124
|
+
const parent = binding.path.parent;
|
|
125
|
+
if (decl.type === "ImportDefaultSpecifier" || decl.type === "ImportNamespaceSpecifier") {
|
|
126
|
+
return parent.type === "ImportDeclaration" && NODE_MODULE.has(parent.source.value);
|
|
127
|
+
}
|
|
128
|
+
return decl.type === "VariableDeclarator" && decl.id.type === "Identifier" && isRequireOfNodeModule(decl.init);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** The callee of a call that reaches node:module's createRequire, or null. */
|
|
132
|
+
function createRequireCallee(path: NodePath<t.CallExpression | t.OptionalCallExpression>): t.Node | null {
|
|
133
|
+
const callee = path.node.callee;
|
|
134
|
+
if (callee.type === "Identifier") {
|
|
135
|
+
return bindsCreateRequire(path, callee.name) ? callee : null;
|
|
136
|
+
}
|
|
137
|
+
if (callee.type !== "MemberExpression" || callee.computed || keyName(callee.property) !== "createRequire") {
|
|
42
138
|
return null;
|
|
43
139
|
}
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
return
|
|
140
|
+
const object = callee.object;
|
|
141
|
+
if (object.type === "Identifier") return bindsNodeModule(path, object.name) ? callee : null;
|
|
142
|
+
return isRequireOfNodeModule(object) ? callee : null;
|
|
47
143
|
}
|
|
48
144
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
/** Strips the query from `createRequire` arguments, for dev-served modules. */
|
|
53
|
-
export function withQueryFreeCreateRequire(code: string): string | null {
|
|
54
|
-
if (!code.match(CREATE_REQUIRE_CALL) || code.includes("__b44CreateRequireImpl")) return null;
|
|
55
|
-
const wrapper =
|
|
56
|
-
"const __b44CreateRequire = (path) => __b44CreateRequireImpl(String(path).replace(/[?#].*$/, \"\"));";
|
|
57
|
-
const binding = ESM_SYNTAX.test(code)
|
|
58
|
-
? 'import { createRequire as __b44CreateRequireImpl } from "node:module";'
|
|
59
|
-
: 'const { createRequire: __b44CreateRequireImpl } = require("node:module");';
|
|
60
|
-
return binding + wrapper + code.replace(CREATE_REQUIRE_CALL, "__b44CreateRequire(");
|
|
145
|
+
export interface PatchOptions {
|
|
146
|
+
/** Also route `createRequire` calls through the query-dropping wrapper. */
|
|
147
|
+
createRequire: boolean;
|
|
61
148
|
}
|
|
62
149
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
150
|
+
/**
|
|
151
|
+
* Patches a workerd server module: imports the enterWith no-op ahead of a module
|
|
152
|
+
* that calls `.enterWith()`, and, with `createRequire`, routes node:module's
|
|
153
|
+
* `createRequire` through a wrapper that drops the id's query. Code is inserted
|
|
154
|
+
* on the first line after any shebang or directive prologue, so strict mode
|
|
155
|
+
* holds and line numbers stay put. Returns null when nothing applies.
|
|
156
|
+
*/
|
|
157
|
+
export function patchServerModule(code: string, id: string, options: PatchOptions): string | null {
|
|
158
|
+
const file = pathOf(id);
|
|
159
|
+
if (NON_SCRIPT_FILE.test(file.slice(file.lastIndexOf("/") + 1)) || file === WORKERD_ENTER_WITH_PATCH) return null;
|
|
160
|
+
// The AST makes the call; this only skips files that cannot contain one,
|
|
161
|
+
// including calls a formatter split across lines.
|
|
162
|
+
const mayEnterWith = code.includes("enterWith");
|
|
163
|
+
const mayCreateRequire =
|
|
164
|
+
options.createRequire && code.includes("createRequire") && !code.includes(CREATE_REQUIRE_IMPL);
|
|
165
|
+
if (!mayEnterWith && !mayCreateRequire) return null;
|
|
166
|
+
|
|
167
|
+
const ast = parseModule(code, file);
|
|
168
|
+
if (!ast) return null;
|
|
169
|
+
|
|
170
|
+
let callsEnterWith = false;
|
|
171
|
+
const callees: t.Node[] = [];
|
|
172
|
+
const visit = (path: NodePath<t.CallExpression | t.OptionalCallExpression>) => {
|
|
173
|
+
const callee = path.node.callee;
|
|
174
|
+
if (
|
|
175
|
+
mayEnterWith &&
|
|
176
|
+
(callee.type === "MemberExpression" || callee.type === "OptionalMemberExpression") &&
|
|
177
|
+
!callee.computed &&
|
|
178
|
+
keyName(callee.property) === "enterWith"
|
|
179
|
+
) {
|
|
180
|
+
callsEnterWith = true;
|
|
181
|
+
}
|
|
182
|
+
const target = mayCreateRequire ? createRequireCallee(path) : null;
|
|
183
|
+
if (target) callees.push(target);
|
|
184
|
+
};
|
|
185
|
+
traverseAst(ast, { CallExpression: visit, OptionalCallExpression: visit });
|
|
186
|
+
if (!callsEnterWith && callees.length === 0) return null;
|
|
187
|
+
|
|
188
|
+
const isEsm = ast.program.sourceType === "module";
|
|
189
|
+
let prefix = "";
|
|
190
|
+
if (callsEnterWith) {
|
|
191
|
+
const patch = JSON.stringify(WORKERD_ENTER_WITH_PATCH);
|
|
192
|
+
// An ESM import in a CommonJS module would turn it into ESM; require it there.
|
|
193
|
+
prefix += isEsm ? `import ${patch};` : `require(${patch});`;
|
|
194
|
+
}
|
|
195
|
+
if (callees.length > 0) {
|
|
196
|
+
prefix += isEsm
|
|
197
|
+
? `import { createRequire as ${CREATE_REQUIRE_IMPL} } from "node:module";`
|
|
198
|
+
: `const { createRequire: ${CREATE_REQUIRE_IMPL} } = require("node:module");`;
|
|
199
|
+
prefix += `const ${CREATE_REQUIRE} = (path) => ${CREATE_REQUIRE_IMPL}(String(path).replace(/[?#].*$/, ""));`;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// A shebang line cannot be followed on the same line, so the code goes at the
|
|
203
|
+
// start of the next one.
|
|
204
|
+
const { interpreter, directives } = ast.program;
|
|
205
|
+
let afterInterpreter = 0;
|
|
206
|
+
if (interpreter) {
|
|
207
|
+
const newline = code.indexOf("\n", interpreter.end!);
|
|
208
|
+
if (newline === -1) prefix = `\n${prefix}`;
|
|
209
|
+
afterInterpreter = newline === -1 ? code.length : newline + 1;
|
|
210
|
+
}
|
|
211
|
+
const insertAt = Math.max(afterInterpreter, ...directives.map((d) => d.end!));
|
|
212
|
+
// A directive may end without a semicolon, and code cannot follow it directly.
|
|
213
|
+
if (insertAt > afterInterpreter && code[insertAt - 1] !== ";") prefix = `;${prefix}`;
|
|
214
|
+
|
|
215
|
+
const edits = [
|
|
216
|
+
{ start: insertAt, end: insertAt, text: prefix },
|
|
217
|
+
...callees.map((node) => ({ start: node.start!, end: node.end!, text: CREATE_REQUIRE })),
|
|
218
|
+
].sort((a, b) => b.start - a.start);
|
|
219
|
+
let out = code;
|
|
220
|
+
for (const edit of edits) out = out.slice(0, edit.start) + edit.text + out.slice(edit.end);
|
|
221
|
+
return out;
|
|
66
222
|
}
|
|
67
223
|
|
|
224
|
+
const devTransform = (code: string, id: string) => patchServerModule(code, id, { createRequire: true });
|
|
225
|
+
|
|
226
|
+
// Every edit keeps lines in place, so the input's source map still holds.
|
|
227
|
+
const transformResult = (code: string | null) => (code === null ? null : { code, map: null });
|
|
228
|
+
|
|
68
229
|
// Structural esbuild types: esbuild is Vite's dependency, not ours.
|
|
69
230
|
interface EsbuildBuild {
|
|
70
231
|
initialOptions: { conditions?: string[] };
|
|
@@ -73,7 +234,7 @@ interface EsbuildBuild {
|
|
|
73
234
|
callback: (args: { path: string }) => { path: string } | undefined,
|
|
74
235
|
): void;
|
|
75
236
|
onLoad(
|
|
76
|
-
options: { filter: RegExp },
|
|
237
|
+
options: { filter: RegExp; namespace: string },
|
|
77
238
|
callback: (args: { path: string }) => Promise<{ contents: string; loader: "js" } | undefined>,
|
|
78
239
|
): void;
|
|
79
240
|
}
|
|
@@ -87,7 +248,8 @@ function esbuildOptimizerPlugin() {
|
|
|
87
248
|
setup(build: EsbuildBuild) {
|
|
88
249
|
if (!isWorkerd(build.initialOptions.conditions)) return;
|
|
89
250
|
build.onResolve({ filter: /^ws$/ }, () => ({ path: WORKERD_WS_ADAPTER }));
|
|
90
|
-
|
|
251
|
+
// Other namespaces hold virtual modules with no file to read.
|
|
252
|
+
build.onLoad({ filter: /\.[cm]?js$/, namespace: "file" }, async (args) => {
|
|
91
253
|
const code = devTransform(await readFile(args.path, "utf8"), args.path);
|
|
92
254
|
return code === null ? undefined : { contents: code, loader: "js" };
|
|
93
255
|
});
|
|
@@ -103,15 +265,18 @@ function rolldownOptimizerPlugin() {
|
|
|
103
265
|
active = isWorkerd(options.resolve?.conditionNames);
|
|
104
266
|
},
|
|
105
267
|
resolveId: (id: string) => (active ? redirect(id) : null),
|
|
106
|
-
transform: (code: string, id: string) => (active ? devTransform(code, id) : null),
|
|
268
|
+
transform: (code: string, id: string) => (active ? transformResult(devTransform(code, id)) : null),
|
|
107
269
|
};
|
|
108
270
|
}
|
|
109
271
|
|
|
110
272
|
const OPTIMIZED_DEP = /[\\/]node_modules[\\/]\.vite[\\/]/;
|
|
111
273
|
|
|
112
|
-
|
|
274
|
+
export interface WorkerdCompatOptions {
|
|
275
|
+
/** Which dependency optimizer to hook. Defaults to the installed Vite's. */
|
|
276
|
+
rolldown?: boolean;
|
|
277
|
+
}
|
|
113
278
|
|
|
114
|
-
export function workerdCompatPlugin(): Plugin {
|
|
279
|
+
export function workerdCompatPlugin({ rolldown = isVite8OrLater }: WorkerdCompatOptions = {}): Plugin {
|
|
115
280
|
return {
|
|
116
281
|
name: "base44-workerd-compat",
|
|
117
282
|
enforce: "pre",
|
|
@@ -119,16 +284,17 @@ export function workerdCompatPlugin(): Plugin {
|
|
|
119
284
|
isWorkerd(environment.config.resolve.conditions),
|
|
120
285
|
configEnvironment(name) {
|
|
121
286
|
if (name === "client") return;
|
|
122
|
-
const optimizeDeps =
|
|
287
|
+
const optimizeDeps = rolldown
|
|
123
288
|
? { rolldownOptions: { plugins: [rolldownOptimizerPlugin()] } }
|
|
124
289
|
: { esbuildOptions: { plugins: [esbuildOptimizerPlugin()] } };
|
|
290
|
+
// Vite 7's types do not know `rolldownOptions`, hence the cast.
|
|
125
291
|
return { optimizeDeps } as EnvironmentOptions;
|
|
126
292
|
},
|
|
127
293
|
resolveId: (id) => redirect(id),
|
|
128
294
|
transform(code, id) {
|
|
129
295
|
// The optimizer already patched its output.
|
|
130
296
|
if (OPTIMIZED_DEP.test(id)) return null;
|
|
131
|
-
return this.environment.mode === "dev"
|
|
297
|
+
return transformResult(patchServerModule(code, id, { createRequire: this.environment.mode === "dev" }));
|
|
132
298
|
},
|
|
133
299
|
};
|
|
134
300
|
}
|