@distilled.cloud/cloudflare-rolldown-plugin 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/factory.d.ts +19 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/factory.js +30 -0
- package/dist/factory.js.map +1 -0
- package/dist/options.d.ts +26 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +1 -0
- package/dist/options.js.map +1 -0
- package/dist/plugin.d.ts +3 -6
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +10 -11
- package/dist/plugin.js.map +1 -1
- package/dist/plugins/additional-modules.d.ts +1 -2
- package/dist/plugins/additional-modules.d.ts.map +1 -1
- package/dist/plugins/additional-modules.js +67 -53
- package/dist/plugins/additional-modules.js.map +1 -1
- package/dist/plugins/cloudflare-externals.d.ts +1 -2
- package/dist/plugins/cloudflare-externals.d.ts.map +1 -1
- package/dist/plugins/cloudflare-externals.js +36 -15
- package/dist/plugins/cloudflare-externals.js.map +1 -1
- package/dist/plugins/index.d.ts +7 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +7 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/nodejs-compat.d.ts +9 -3
- package/dist/plugins/nodejs-compat.d.ts.map +1 -1
- package/dist/plugins/nodejs-compat.js +178 -115
- package/dist/plugins/nodejs-compat.js.map +1 -1
- package/dist/plugins/options.d.ts +1 -5
- package/dist/plugins/options.d.ts.map +1 -1
- package/dist/plugins/options.js +128 -23
- package/dist/plugins/options.js.map +1 -1
- package/dist/plugins/virtual-modules.d.ts +3 -0
- package/dist/plugins/virtual-modules.d.ts.map +1 -0
- package/dist/plugins/virtual-modules.js +125 -0
- package/dist/plugins/virtual-modules.js.map +1 -0
- package/dist/plugins/wasm-init.d.ts +1 -2
- package/dist/plugins/wasm-init.d.ts.map +1 -1
- package/dist/plugins/wasm-init.js +15 -13
- package/dist/plugins/wasm-init.js.map +1 -1
- package/package.json +16 -1
- package/src/factory.ts +60 -0
- package/src/options.ts +25 -0
- package/src/plugin.ts +22 -18
- package/src/plugins/additional-modules.ts +89 -55
- package/src/plugins/cloudflare-externals.ts +36 -16
- package/src/plugins/index.ts +6 -0
- package/src/plugins/nodejs-compat.ts +197 -140
- package/src/plugins/options.ts +145 -26
- package/src/plugins/virtual-modules.ts +135 -0
- package/src/plugins/wasm-init.ts +15 -14
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { createPlugin } from "../factory.js";
|
|
2
|
+
// oxlint-disable-next-line no-control-regex
|
|
3
|
+
const VIRTUAL_MODULE_REGEXP = /^\0distilled:.*$/;
|
|
4
|
+
export const WORKER_ENTRY_PREFIX = "\0distilled:worker-entry:";
|
|
5
|
+
const USER_ENTRY_PREFIX = "\0distilled:user-entry:";
|
|
6
|
+
const PEAR_ENTRY_PREFIX = "\0distilled:pear-entry:";
|
|
7
|
+
const INJECT_PREFIX = "\0distilled:inject:";
|
|
8
|
+
const EXPORT_TYPES_ID = "\0distilled:export-types";
|
|
9
|
+
export const virtualModulesPlugin = createPlugin("virtual-modules", (options) => {
|
|
10
|
+
let unenvApi;
|
|
11
|
+
const inject = () => {
|
|
12
|
+
if (!unenvApi)
|
|
13
|
+
return [];
|
|
14
|
+
return [
|
|
15
|
+
...unenvApi.polyfill.map((module) => `import "${module}";`),
|
|
16
|
+
...Object.keys(unenvApi.inject).map((injectedName) => `import "${INJECT_PREFIX}${injectedName}";`),
|
|
17
|
+
];
|
|
18
|
+
};
|
|
19
|
+
return {
|
|
20
|
+
shared: {
|
|
21
|
+
buildStart({ plugins }) {
|
|
22
|
+
unenvApi = plugins.find((plugin) => "name" in plugin && plugin.name === "distilled-cloudflare:nodejs-unenv")?.api;
|
|
23
|
+
},
|
|
24
|
+
resolveId: {
|
|
25
|
+
filter: { id: VIRTUAL_MODULE_REGEXP },
|
|
26
|
+
handler(id) {
|
|
27
|
+
if (id.startsWith(WORKER_ENTRY_PREFIX) ||
|
|
28
|
+
id.startsWith(PEAR_ENTRY_PREFIX) ||
|
|
29
|
+
id.startsWith(INJECT_PREFIX) ||
|
|
30
|
+
id === EXPORT_TYPES_ID) {
|
|
31
|
+
return { id };
|
|
32
|
+
}
|
|
33
|
+
if (id.startsWith(USER_ENTRY_PREFIX)) {
|
|
34
|
+
return this.resolve(id.slice(USER_ENTRY_PREFIX.length), undefined, {
|
|
35
|
+
isEntry: true,
|
|
36
|
+
kind: "import-statement",
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
load: {
|
|
42
|
+
filter: { id: VIRTUAL_MODULE_REGEXP },
|
|
43
|
+
handler(id) {
|
|
44
|
+
if (id.startsWith(WORKER_ENTRY_PREFIX)) {
|
|
45
|
+
const userEntryId = id.replace(WORKER_ENTRY_PREFIX, USER_ENTRY_PREFIX);
|
|
46
|
+
return [
|
|
47
|
+
...inject(),
|
|
48
|
+
`import { getExportTypes } from "${EXPORT_TYPES_ID}";`,
|
|
49
|
+
...(options.exports
|
|
50
|
+
? [`export { ${options.exports.join(", ")} } from "${userEntryId}";`]
|
|
51
|
+
: [
|
|
52
|
+
`import * as userEntry from "${userEntryId}";`,
|
|
53
|
+
`export * from "${userEntryId}";`,
|
|
54
|
+
`export default userEntry.default ?? {};`,
|
|
55
|
+
]),
|
|
56
|
+
"if (import.meta.hot) {",
|
|
57
|
+
" import.meta.hot.accept((module) => {",
|
|
58
|
+
" const exportTypes = getExportTypes(module);",
|
|
59
|
+
' import.meta.hot.send("distilled-cloudflare:worker-export-types", exportTypes);',
|
|
60
|
+
" });",
|
|
61
|
+
"}",
|
|
62
|
+
].join("\n");
|
|
63
|
+
}
|
|
64
|
+
if (id === EXPORT_TYPES_ID) {
|
|
65
|
+
return `
|
|
66
|
+
import {
|
|
67
|
+
WorkerEntrypoint,
|
|
68
|
+
DurableObject,
|
|
69
|
+
WorkflowEntrypoint,
|
|
70
|
+
} from "cloudflare:workers";
|
|
71
|
+
|
|
72
|
+
const baseClasses = new Map([
|
|
73
|
+
["WorkerEntrypoint", WorkerEntrypoint],
|
|
74
|
+
["DurableObject", DurableObject],
|
|
75
|
+
["WorkflowEntrypoint", WorkflowEntrypoint],
|
|
76
|
+
]);
|
|
77
|
+
|
|
78
|
+
export function getExportTypes(module) {
|
|
79
|
+
const exportTypes = {};
|
|
80
|
+
|
|
81
|
+
for (const [key, value] of Object.entries(module)) {
|
|
82
|
+
if (key === "default") {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
let exportType;
|
|
87
|
+
|
|
88
|
+
if (typeof value === "function") {
|
|
89
|
+
for (const [type, baseClass] of baseClasses) {
|
|
90
|
+
if (baseClass.prototype.isPrototypeOf(value.prototype)) {
|
|
91
|
+
exportType = type;
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!exportType) {
|
|
97
|
+
exportType = "DurableObject";
|
|
98
|
+
}
|
|
99
|
+
} else if (typeof value === "object" && value !== null) {
|
|
100
|
+
exportType = "WorkerEntrypoint";
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
exportTypes[key] = exportType;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return exportTypes;
|
|
107
|
+
}`;
|
|
108
|
+
}
|
|
109
|
+
if (id.startsWith(INJECT_PREFIX)) {
|
|
110
|
+
const injectedName = id.slice(INJECT_PREFIX.length);
|
|
111
|
+
const moduleSpecifier = unenvApi?.inject[injectedName];
|
|
112
|
+
if (!moduleSpecifier) {
|
|
113
|
+
throw new Error(`Expected module specifier for "${injectedName}" to be defined`);
|
|
114
|
+
}
|
|
115
|
+
return [
|
|
116
|
+
`import ${injectedName} from "${moduleSpecifier}";`,
|
|
117
|
+
`globalThis.${injectedName} = ${injectedName};`,
|
|
118
|
+
].join("\n");
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
//# sourceMappingURL=virtual-modules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtual-modules.js","sourceRoot":"","sources":["../../src/plugins/virtual-modules.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wasm-init.d.ts","sourceRoot":"","sources":["../../src/plugins/wasm-init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"wasm-init.d.ts","sourceRoot":"","sources":["../../src/plugins/wasm-init.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,cAAc,2CAexB,CAAC"}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
|
+
import { createPlugin } from "../factory.js";
|
|
1
2
|
import { sanitizePath } from "../utils.js";
|
|
2
3
|
const WASM_INIT_QUERY = /\.wasm\?init$/;
|
|
3
|
-
export const wasmInitPlugin = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
4
|
+
export const wasmInitPlugin = createPlugin("wasm-init", () => ({
|
|
5
|
+
shared: {
|
|
6
|
+
load: {
|
|
7
|
+
filter: { id: WASM_INIT_QUERY },
|
|
8
|
+
handler(id) {
|
|
9
|
+
return [
|
|
10
|
+
`import wasmModule from "${sanitizePath(id)}";`,
|
|
11
|
+
`export default async (imports) => {`,
|
|
12
|
+
` const result = await WebAssembly.instantiate(wasmModule, imports);`,
|
|
13
|
+
` return "instance" in result ? result.instance : result;`,
|
|
14
|
+
`};`,
|
|
15
|
+
].join("\n");
|
|
16
|
+
},
|
|
15
17
|
},
|
|
16
18
|
},
|
|
17
|
-
};
|
|
19
|
+
}));
|
|
18
20
|
//# sourceMappingURL=wasm-init.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wasm-init.js","sourceRoot":"","sources":["../../src/plugins/wasm-init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"wasm-init.js","sourceRoot":"","sources":["../../src/plugins/wasm-init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,eAAe,GAAG,eAAe,CAAC;AAExC,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;IAC7D,MAAM,EAAE;QACN,IAAI,EAAE;YACJ,MAAM,EAAE,EAAE,EAAE,EAAE,eAAe,EAAE;YAC/B,OAAO,CAAC,EAAE;gBACR,OAAO;oBACL,2BAA2B,YAAY,CAAC,EAAE,CAAC,IAAI;oBAC/C,qCAAqC;oBACrC,sEAAsE;oBACtE,2DAA2D;oBAC3D,IAAI;iBACL,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACf,CAAC;SACF;KACF;CACF,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@distilled.cloud/cloudflare-rolldown-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Rolldown plugin for Cloudflare Workers.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -35,6 +35,14 @@
|
|
|
35
35
|
"bun": "./src/plugin.ts",
|
|
36
36
|
"types": "./dist/plugin.d.ts",
|
|
37
37
|
"import": "./dist/plugin.js"
|
|
38
|
+
},
|
|
39
|
+
"./plugins": {
|
|
40
|
+
"types": "./dist/plugins/index.d.ts",
|
|
41
|
+
"import": "./dist/plugins/index.js"
|
|
42
|
+
},
|
|
43
|
+
"./options": {
|
|
44
|
+
"types": "./dist/options.d.ts",
|
|
45
|
+
"import": "./dist/options.js"
|
|
38
46
|
}
|
|
39
47
|
},
|
|
40
48
|
"publishConfig": {
|
|
@@ -51,14 +59,21 @@
|
|
|
51
59
|
},
|
|
52
60
|
"dependencies": {
|
|
53
61
|
"@cloudflare/unenv-preset": "^2.16.0",
|
|
62
|
+
"magic-string": "^0.30.21",
|
|
54
63
|
"unenv": "^2.0.0-rc.24"
|
|
55
64
|
},
|
|
56
65
|
"devDependencies": {
|
|
57
66
|
"@cloudflare/workers-types": "^4.20260310.1",
|
|
58
67
|
"@distilled.cloud/test-utils": "0.0.0",
|
|
68
|
+
"vite": "^8.0.3",
|
|
59
69
|
"vitest": "^4.1.1"
|
|
60
70
|
},
|
|
61
71
|
"peerDependencies": {
|
|
62
72
|
"rolldown": "^1.0.0-rc.9"
|
|
73
|
+
},
|
|
74
|
+
"peerDependenciesMeta": {
|
|
75
|
+
"rolldown": {
|
|
76
|
+
"optional": true
|
|
77
|
+
}
|
|
63
78
|
}
|
|
64
79
|
}
|
package/src/factory.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type * as rolldown from "rolldown";
|
|
2
|
+
import type * as vite from "vite";
|
|
3
|
+
import type { CloudflarePluginOptions } from "./options.js";
|
|
4
|
+
|
|
5
|
+
export interface PluginInput<A = any> {
|
|
6
|
+
shared?: Omit<rolldown.Plugin<A>, "name">;
|
|
7
|
+
rolldown?: Omit<rolldown.Plugin<A>, "name">;
|
|
8
|
+
vite?: Omit<vite.Plugin<A>, "name">;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface NullablePluginOutput<A = any> {
|
|
12
|
+
rolldown: (options: CloudflarePluginOptions) => rolldown.Plugin<A> | null;
|
|
13
|
+
vite: (options: CloudflarePluginOptions) => vite.Plugin<A> | null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface PluginOutput<A = any> {
|
|
17
|
+
rolldown: (options: CloudflarePluginOptions) => rolldown.Plugin<A>;
|
|
18
|
+
vite: (options: CloudflarePluginOptions) => vite.Plugin<A>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function createPlugin<TName extends string, A = any>(
|
|
22
|
+
pluginName: TName,
|
|
23
|
+
make: (options: CloudflarePluginOptions) => PluginInput<A>,
|
|
24
|
+
): PluginOutput<A>;
|
|
25
|
+
|
|
26
|
+
export function createPlugin<TName extends string, A = any>(
|
|
27
|
+
pluginName: TName,
|
|
28
|
+
make: (options: CloudflarePluginOptions) => PluginInput<A> | undefined,
|
|
29
|
+
): NullablePluginOutput<A>;
|
|
30
|
+
|
|
31
|
+
export function createPlugin<TName extends string, A = any>(
|
|
32
|
+
pluginName: TName,
|
|
33
|
+
make: (options: CloudflarePluginOptions) => PluginInput<A> | undefined,
|
|
34
|
+
): PluginOutput<A> | NullablePluginOutput<A> {
|
|
35
|
+
const name = `distilled-cloudflare:${pluginName}`;
|
|
36
|
+
return {
|
|
37
|
+
rolldown: (options: CloudflarePluginOptions) => {
|
|
38
|
+
const plugin = make(options);
|
|
39
|
+
if (!plugin) return null;
|
|
40
|
+
return {
|
|
41
|
+
name,
|
|
42
|
+
...plugin.shared,
|
|
43
|
+
...plugin.rolldown,
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
vite: (options: CloudflarePluginOptions) => {
|
|
47
|
+
const plugin = make(options);
|
|
48
|
+
if (!plugin) return null;
|
|
49
|
+
return {
|
|
50
|
+
name,
|
|
51
|
+
sharedDuringBuild: true,
|
|
52
|
+
applyToEnvironment(environment) {
|
|
53
|
+
return environment.name !== "client";
|
|
54
|
+
},
|
|
55
|
+
...plugin.shared,
|
|
56
|
+
...plugin.vite,
|
|
57
|
+
} as vite.Plugin;
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
package/src/options.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface CloudflarePluginOptions {
|
|
2
|
+
/**
|
|
3
|
+
* The compatibility date to use. This is optional, but should be defined to avoid unexpected behavior.
|
|
4
|
+
* @default undefined
|
|
5
|
+
*/
|
|
6
|
+
compatibilityDate?: string;
|
|
7
|
+
/**
|
|
8
|
+
* The compatibility flags to enable.
|
|
9
|
+
* @default []
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* cloudflare({ compatibilityDate: "2026-04-01", compatibilityFlags: ["nodejs_compat"] });
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
compatibilityFlags?: Array<string>;
|
|
16
|
+
/**
|
|
17
|
+
* The exports to include in the bundle.
|
|
18
|
+
* By default, all exports are included. However, if you only want to include certain exports, you can use this option.
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* cloudflare({ exports: ["default"] });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
exports?: Array<string>;
|
|
25
|
+
}
|
package/src/plugin.ts
CHANGED
|
@@ -1,24 +1,28 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import type * as rolldown from "rolldown";
|
|
2
|
+
import type { CloudflarePluginOptions } from "./options.js";
|
|
3
|
+
import {
|
|
4
|
+
additionalModulesPlugin,
|
|
5
|
+
cloudflareExternalsPlugin,
|
|
6
|
+
nodejsAlsPlugin,
|
|
7
|
+
nodejsImportWarningPlugin,
|
|
8
|
+
nodejsUnenvPlugin,
|
|
9
|
+
optionsPlugin,
|
|
10
|
+
virtualModulesPlugin,
|
|
11
|
+
wasmInitPlugin,
|
|
12
|
+
} from "./plugins/index.js";
|
|
7
13
|
|
|
8
|
-
export
|
|
9
|
-
compatibilityDate?: string;
|
|
10
|
-
compatibilityFlags?: Array<string>;
|
|
11
|
-
}
|
|
14
|
+
export type CloudflarePlugin = (options?: CloudflarePluginOptions) => Array<rolldown.Plugin | null>;
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const cloudflare: CloudflarePlugin = async (options = {}) => {
|
|
16
|
+
const cloudflare: CloudflarePlugin = (options = {}) => {
|
|
16
17
|
return [
|
|
17
|
-
|
|
18
|
-
cloudflareExternalsPlugin,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
optionsPlugin.rolldown(options),
|
|
19
|
+
cloudflareExternalsPlugin.rolldown(options),
|
|
20
|
+
nodejsAlsPlugin.rolldown(options),
|
|
21
|
+
nodejsImportWarningPlugin.rolldown(options),
|
|
22
|
+
nodejsUnenvPlugin.rolldown(options),
|
|
23
|
+
virtualModulesPlugin.rolldown(options),
|
|
24
|
+
wasmInitPlugin.rolldown(options),
|
|
25
|
+
additionalModulesPlugin.rolldown(options),
|
|
22
26
|
];
|
|
23
27
|
};
|
|
24
28
|
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
+
import MagicString from "magic-string";
|
|
1
2
|
import path from "node:path";
|
|
2
|
-
import
|
|
3
|
+
import type {
|
|
4
|
+
Plugin,
|
|
5
|
+
PluginContext,
|
|
6
|
+
RenderedChunk,
|
|
7
|
+
RolldownMagicString,
|
|
8
|
+
SourceMap,
|
|
9
|
+
} from "rolldown";
|
|
10
|
+
import { createPlugin } from "../factory.js";
|
|
3
11
|
import { sanitizePath } from "../utils.js";
|
|
4
12
|
|
|
5
13
|
const MODULE_RULES = [
|
|
@@ -12,71 +20,97 @@ const MODULE_REFERENCE_PATTERN = `__CLOUDFLARE_MODULE__(${MODULE_RULES.map((rule
|
|
|
12
20
|
const MODULE_REFERENCE_REGEX = new RegExp(MODULE_REFERENCE_PATTERN);
|
|
13
21
|
const MODULE_REFERENCE_GLOBAL_REGEX = new RegExp(MODULE_REFERENCE_PATTERN, "g");
|
|
14
22
|
|
|
15
|
-
export
|
|
23
|
+
export const additionalModulesPlugin = createPlugin("additional-modules", () => {
|
|
16
24
|
const additionalModulePaths = new Set<string>();
|
|
17
|
-
|
|
18
25
|
return {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
// hotUpdate(options) {
|
|
26
|
-
// if (additionalModulePaths.has(options.file)) {
|
|
27
|
-
// void options.server.restart();
|
|
28
|
-
// return [];
|
|
29
|
-
// }
|
|
30
|
-
// },
|
|
31
|
-
resolveId: {
|
|
32
|
-
filter: { id: MODULE_RULES.map((rule) => rule.pattern) },
|
|
33
|
-
async handler(source, importer, options) {
|
|
34
|
-
const resolved = await this.resolve(source, importer, options);
|
|
35
|
-
if (!resolved) {
|
|
36
|
-
return;
|
|
26
|
+
vite: {
|
|
27
|
+
enforce: "pre",
|
|
28
|
+
hotUpdate(options) {
|
|
29
|
+
if (additionalModulePaths.has(options.file)) {
|
|
30
|
+
void options.server.restart();
|
|
31
|
+
return [];
|
|
37
32
|
}
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
shared: {
|
|
36
|
+
resolveId: {
|
|
37
|
+
filter: { id: MODULE_RULES.map((rule) => rule.pattern) },
|
|
38
|
+
async handler(source, importer, options) {
|
|
39
|
+
const resolved = await this.resolve(source, importer, options);
|
|
40
|
+
if (!resolved) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
38
43
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
const rule = MODULE_RULES.find((rule) => rule.pattern.test(resolved.id));
|
|
45
|
+
if (!rule) {
|
|
46
|
+
return resolved;
|
|
47
|
+
}
|
|
43
48
|
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
const filePath = sanitizePath(resolved.id);
|
|
50
|
+
additionalModulePaths.add(filePath);
|
|
46
51
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
52
|
+
return {
|
|
53
|
+
id: moduleReferenceId(rule.type, filePath),
|
|
54
|
+
external: true,
|
|
55
|
+
};
|
|
56
|
+
},
|
|
51
57
|
},
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
magicString.update(match.index, match.index + full.length, importPath);
|
|
71
|
-
}
|
|
72
|
-
if (magicString) {
|
|
73
|
-
return magicString;
|
|
74
|
-
}
|
|
58
|
+
renderChunk: {
|
|
59
|
+
filter: { code: { include: MODULE_REFERENCE_REGEX } },
|
|
60
|
+
handler: withMagicString(async function (code, chunk, magicString) {
|
|
61
|
+
const matches = code.matchAll(MODULE_REFERENCE_GLOBAL_REGEX);
|
|
62
|
+
for (const match of matches) {
|
|
63
|
+
const [full, , id] = match;
|
|
64
|
+
const source = await this.fs.readFile(id);
|
|
65
|
+
const referenceId = this.emitFile({
|
|
66
|
+
type: "asset",
|
|
67
|
+
name: path.basename(id),
|
|
68
|
+
source,
|
|
69
|
+
});
|
|
70
|
+
const fileName = this.getFileName(referenceId);
|
|
71
|
+
const relativePath = path.relative(path.dirname(chunk.fileName), fileName);
|
|
72
|
+
const importPath = relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
|
|
73
|
+
magicString.update(match.index, match.index + full.length, importPath);
|
|
74
|
+
}
|
|
75
|
+
}),
|
|
75
76
|
},
|
|
76
77
|
},
|
|
77
78
|
};
|
|
78
|
-
}
|
|
79
|
+
});
|
|
79
80
|
|
|
80
81
|
function moduleReferenceId(type: "CompiledWasm" | "Data" | "Text", id: string) {
|
|
81
82
|
return `__CLOUDFLARE_MODULE__${type}__${id}__CLOUDFLARE_MODULE__` as const;
|
|
82
83
|
}
|
|
84
|
+
|
|
85
|
+
type PluginHandler<T extends keyof Plugin> = Plugin[T] extends infer T
|
|
86
|
+
? T extends (...args: any) => any
|
|
87
|
+
? T
|
|
88
|
+
: never
|
|
89
|
+
: never;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Returns a `renderChunk` handler that transforms the chunk using a magic string.
|
|
93
|
+
* Uses Rolldown's native magic string if available, or the `magic-string` library otherwise.
|
|
94
|
+
*/
|
|
95
|
+
function withMagicString(
|
|
96
|
+
renderChunk: (
|
|
97
|
+
this: PluginContext,
|
|
98
|
+
code: string,
|
|
99
|
+
chunk: RenderedChunk,
|
|
100
|
+
magicString: MagicString | RolldownMagicString,
|
|
101
|
+
) => Promise<void>,
|
|
102
|
+
): PluginHandler<"renderChunk"> {
|
|
103
|
+
return async function (code, chunk, outputOptions, meta) {
|
|
104
|
+
const magicString = meta.magicString ?? new MagicString(code);
|
|
105
|
+
await renderChunk.call(this, code, chunk, magicString);
|
|
106
|
+
if ("isRolldownMagicString" in magicString && magicString.isRolldownMagicString) {
|
|
107
|
+
return magicString;
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
code: magicString.toString(),
|
|
111
|
+
map: outputOptions.sourcemap
|
|
112
|
+
? (magicString.generateMap({ hires: "boundary" }) as SourceMap)
|
|
113
|
+
: null,
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { createPlugin } from "../factory.js";
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const CLOUDFLARE_BUILT_IN_MODULES = [
|
|
4
4
|
"cloudflare:email",
|
|
5
5
|
"cloudflare:node",
|
|
6
6
|
"cloudflare:sockets",
|
|
@@ -8,19 +8,39 @@ const CLOUDFLARE_BUILTIN_MODULES = [
|
|
|
8
8
|
"cloudflare:workflows",
|
|
9
9
|
];
|
|
10
10
|
|
|
11
|
-
export const cloudflareExternalsPlugin
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
export const cloudflareExternalsPlugin = createPlugin("cloudflare-externals", () => {
|
|
12
|
+
return {
|
|
13
|
+
rolldown: {
|
|
14
|
+
resolveId: {
|
|
15
|
+
filter: { id: /^cloudflare:/ },
|
|
16
|
+
handler(id) {
|
|
17
|
+
if (!CLOUDFLARE_BUILT_IN_MODULES.includes(id)) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
return {
|
|
22
|
+
id,
|
|
23
|
+
external: true,
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
},
|
|
24
27
|
},
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
vite: {
|
|
29
|
+
configEnvironment(name) {
|
|
30
|
+
if (name === "client") {
|
|
31
|
+
// Some frameworks allow users to mix client and server code in the same file and then extract the server code.
|
|
32
|
+
// As the dependency optimization may happen before the server code is extracted, we should exclude Cloudflare built-ins from client optimization.
|
|
33
|
+
return { optimizeDeps: { exclude: CLOUDFLARE_BUILT_IN_MODULES } };
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
resolve: {
|
|
37
|
+
builtins: CLOUDFLARE_BUILT_IN_MODULES,
|
|
38
|
+
},
|
|
39
|
+
optimizeDeps: {
|
|
40
|
+
exclude: CLOUDFLARE_BUILT_IN_MODULES,
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
});
|