rsbuild-plugin-cloudflare 0.0.0 → 0.0.2

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/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ Copyright (c) 2020 Cloudflare, Inc. <wrangler@cloudflare.com>
2
+
3
+ Permission is hereby granted, free of charge, to any
4
+ person obtaining a copy of this software and associated
5
+ documentation files (the "Software"), to deal in the
6
+ Software without restriction, including without
7
+ limitation the rights to use, copy, modify, merge,
8
+ publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software
10
+ is furnished to do so, subject to the following
11
+ conditions:
12
+
13
+ The above copyright notice and this permission notice
14
+ shall be included in all copies or substantial portions
15
+ of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
18
+ ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19
+ TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20
+ PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21
+ SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
24
+ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25
+ DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,246 @@
1
- # rsbuild-plugin-cloudflare
1
+ # `rsbuild-plugin-cloudflare`
2
2
 
3
- This is a placeholder release. The plugin isn't published yet.
3
+ [![npm](https://img.shields.io/npm/v/rsbuild-plugin-cloudflare)](https://www.npmjs.com/package/rsbuild-plugin-cloudflare)
4
+
5
+ An experimental [Rsbuild](https://rsbuild.rs) plugin for Cloudflare Workers. It
6
+ runs your Workers in workerd during `rsbuild dev` and `rsbuild preview`, and
7
+ builds them, with your client assets, during `rsbuild build` into a Cloudflare
8
+ Build Output that you can deploy with `cf deploy --prebuilt`.
9
+
10
+ It's built on the internals of
11
+ [`@cloudflare/vite-plugin`](https://developers.cloudflare.com/workers/vite-plugin/),
12
+ and accepts the same options.
13
+
14
+ > **Using TanStack Start?** Follow the [TanStack Start guide](#tanstack-start):
15
+ > the framework's server environment has to be set as the Worker's, or every
16
+ > request fails.
17
+
18
+ ## Usage
19
+
20
+ ```ts
21
+ // rsbuild.config.ts
22
+ import { cloudflare } from "rsbuild-plugin-cloudflare";
23
+ import { defineConfig } from "@rsbuild/core";
24
+
25
+ export default defineConfig({
26
+ plugins: [cloudflare()],
27
+ });
28
+ ```
29
+
30
+ The Worker is configured in `cloudflare.config.ts`, as for the Vite plugin.
31
+
32
+ ### Options
33
+
34
+ The options are those of the Vite plugin's `cloudflare()` (e.g. `config`,
35
+ `auxiliaryWorkers`, `persistState`, `inspectorPort`, `remoteBindings`), apart
36
+ from `tunnel`, and with `rsbuildEnvironment` in place of `viteEnvironment`
37
+ (see [Worker environments](#worker-environments)), plus:
38
+
39
+ - `envDir`: the directory to load `.env` and `.dev.vars` files from, or `false`
40
+ to skip them. Defaults to the project root.
41
+ - `envMode`: the mode used to load `cloudflare.config.ts`, `.env.[mode]` and
42
+ `.dev.vars.[mode]`. Defaults to Rsbuild's mode.
43
+
44
+ ### Worker environments
45
+
46
+ Each Worker is built by an
47
+ [Rsbuild environment](https://rsbuild.rs/config/environments). The entry
48
+ Worker's is named `cloudflare`, unless `rsbuildEnvironment.name` is set.
49
+ Auxiliary Workers' are named as in the Vite plugin, unless their own
50
+ `rsbuildEnvironment.name` is set. `rsbuildEnvironment` replaces the Vite
51
+ plugin's `viteEnvironment`, without `childEnvironments`.
52
+
53
+ To change how a Worker is built, configure its environment in Rsbuild's
54
+ `environments` config. The plugin merges its settings in, and yours take
55
+ precedence, apart from `source.entry`, `output.target` and `output.module`,
56
+ which the plugin always sets so that the Worker runs in workerd, and
57
+ `output.distPath.root`, which it sets to the Worker's Build Output location, as
58
+ the Vite plugin does. The Worker's entry keeps the
59
+ [layer](https://rspack.rs/config/entry#entrydescriptionlayer) of the entries
60
+ that it replaces, if they're all in the same one (e.g. TanStack Start's server
61
+ entry, with React Server Components).
62
+
63
+ ```ts
64
+ export default defineConfig({
65
+ plugins: [cloudflare()],
66
+ environments: {
67
+ cloudflare: { output: { minify: true } },
68
+ },
69
+ });
70
+ ```
71
+
72
+ ### Frameworks
73
+
74
+ As with the Vite plugin, put `cloudflare()` before the framework's plugins, and
75
+ set `rsbuildEnvironment.name` to the framework's server environment. The plugin
76
+ builds that environment for workerd, whatever target the framework sets.
77
+
78
+ In dev, the Worker environment's `loadBundle()` returns a module whose `fetch`
79
+ sends requests to the Worker in workerd, so frameworks that serve their server
80
+ bundle through `loadBundle()`, such as
81
+ [TanStack Start](https://tanstack.com/start), run it in workerd.
82
+
83
+ #### TanStack Start
84
+
85
+ To run a [TanStack Start](https://tanstack.com/start) app that's built with
86
+ Rsbuild (e.g. one created from TanStack's Rsbuild template) on Workers:
87
+
88
+ 1. Install the plugin, and [`cf`](https://www.npmjs.com/package/cf) for
89
+ `cf/config` and `cf deploy`:
90
+
91
+ ```sh
92
+ pnpm add -D rsbuild-plugin-cloudflare cf
93
+ ```
94
+
95
+ 2. Configure the Worker in `cloudflare.config.ts`, with TanStack Start's server
96
+ entry as its entrypoint. TanStack Start uses Node.js APIs, such as
97
+ `AsyncLocalStorage`. From compatibility date `2026-08-04`,
98
+ [Node.js compatibility](https://developers.cloudflare.com/workers/runtime-apis/nodejs/)
99
+ is on by default; with an earlier date, add the `nodejs_compat` flag.
100
+
101
+ ```ts
102
+ // cloudflare.config.ts
103
+ import { defineConfig } from "cf/config";
104
+
105
+ export default defineConfig({
106
+ worker: {
107
+ name: "my-tanstack-start-app",
108
+ entrypoint: "@tanstack/react-start/server-entry",
109
+ compatibilityDate: "2026-10-19",
110
+ },
111
+ });
112
+ ```
113
+
114
+ If the app has its own
115
+ [server entry](https://tanstack.com/start/latest/docs/framework/react/guide/server-entry-point)
116
+ (e.g. `src/server.ts`), make that the entrypoint instead (e.g.
117
+ `entrypoint: "./src/server.ts"`). The Worker runs its entrypoint, so with
118
+ TanStack Start's it would bypass the app's.
119
+
120
+ 3. Add `cloudflare()` before `tanstackStart()`, with `rsbuildEnvironment.name`
121
+ set to TanStack Start's server environment, `ssr`. This is required: without
122
+ it, the plugin builds the entrypoint in its own `cloudflare` environment,
123
+ without TanStack Start's build setup, and every request fails (e.g. with
124
+ `tsrStartManifest is not a function`).
125
+
126
+ ```ts
127
+ // rsbuild.config.ts
128
+ import { defineConfig } from "@rsbuild/core";
129
+ import { pluginReact } from "@rsbuild/plugin-react";
130
+ import { tanstackStart } from "@tanstack/react-start/plugin/rsbuild";
131
+ import { cloudflare } from "rsbuild-plugin-cloudflare";
132
+
133
+ export default defineConfig({
134
+ plugins: [
135
+ pluginReact(),
136
+ cloudflare({ rsbuildEnvironment: { name: "ssr" } }),
137
+ tanstackStart(),
138
+ ],
139
+ });
140
+ ```
141
+
142
+ 4. Replace the template's scripts. Its `start` script runs the server in
143
+ Node.js, so it doesn't apply; `rsbuild preview` runs the build in workerd.
144
+
145
+ ```json
146
+ {
147
+ "scripts": {
148
+ "dev": "rsbuild dev",
149
+ "build": "rsbuild build",
150
+ "preview": "rsbuild preview",
151
+ "deploy": "rsbuild build && cf deploy --prebuilt"
152
+ }
153
+ }
154
+ ```
155
+
156
+ 5. Add `.cloudflare` to `.gitignore`. It holds the bindings' local state, the
157
+ Build Output, and the Worker's types, which are generated to
158
+ `.cloudflare/types`: add that to `tsconfig.json`'s `include` to use them.
159
+
160
+ Server functions and server routes can then use the Worker's bindings:
161
+
162
+ ```ts
163
+ import { createServerFn } from "@tanstack/react-start";
164
+ import { env } from "cloudflare:workers";
165
+
166
+ const getGreeting = createServerFn().handler(() => env.GREETING);
167
+ ```
168
+
169
+ See [`packages/e2e/fixtures/tanstack-start`](https://github.com/james-elicx/rsbuild-plugin-cloudflare/tree/main/packages/e2e/fixtures/tanstack-start) for
170
+ a complete app.
171
+
172
+ [React Server Components](https://tanstack.com/start/latest/docs/framework/react/guide/server-components)
173
+ run in the Worker too, once they're enabled with `rsc: { enabled: true }` in
174
+ `tanstackStart()`'s options. TanStack Start resolves `react-server-dom-rspack`
175
+ from the app's root, so add it as a dependency. See
176
+ [`packages/e2e/fixtures/tanstack-start-rsc`](https://github.com/james-elicx/rsbuild-plugin-cloudflare/tree/main/packages/e2e/fixtures/tanstack-start-rsc).
177
+
178
+ ## Differences from the Vite plugin
179
+
180
+ The plugin replaces Vite's module runner with Rsbuild's bundles, so behaviour
181
+ that depends on how Vite works internally isn't available:
182
+
183
+ - Workers are rebuilt and reloaded when their code changes; there's no in-Worker
184
+ HMR (`import.meta.hot`).
185
+ - Uncaught errors in the entry Worker aren't returned to the dev server with
186
+ the `MF-Experimental-Error-Stack` header, as the Vite plugin's module runner
187
+ does, so there's no error overlay or source-mapped stack: the browser gets a
188
+ plain-text `500` response.
189
+ - Child environments, the hot channel, `bundledDev`, middleware mode, custom
190
+ `buildApp`s and Vite plugins (e.g. for virtual modules) don't apply.
191
+ - Prerendering isn't supported, as Rsbuild has no equivalent of `buildApp`. The
192
+ prerender Worker is still built and written to the Build Output.
193
+ - Containers aren't supported yet: in dev and preview, a warning is logged and
194
+ Container-backed Durable Objects fail; in a build, a warning is logged and no
195
+ Container images or Container output are written.
196
+ - `tunnel` and the Vite CLI shortcuts aren't supported.
197
+ - The Local Explorer hint that the Vite plugin prints for AI agents isn't
198
+ printed.
199
+
200
+ Other differences:
201
+
202
+ - Rsbuild serves `/` and `*.html` itself, so the plugin intercepts page
203
+ navigations (`GET` and `HEAD` requests for `.html` paths or paths without an
204
+ extension, apart from Rsbuild's HMR path and paths starting with `/__` or
205
+ `/rsbuild-`) and sends them to the Workers. These requests reach the Workers
206
+ before Rsbuild's `server.proxy`.
207
+ - In dev, Rsbuild also serves the Worker environments' output (e.g.
208
+ `/index.js` and `/index.js.map`), as it serves the assets of every
209
+ `web-worker` environment.
210
+ - When workerd restarts, the Vite plugin restarts the dev server; the Rsbuild
211
+ bundles don't depend on workerd's state, so the plugin doesn't.
212
+ - Setting `output.externals` (other than Node.js built-ins) for a Worker's
213
+ environment logs a warning, where the Vite plugin rejects `resolve.external`,
214
+ as Rsbuild also applies top-level externals to every environment.
215
+ - Config changes (e.g. to `cloudflare.config.ts` or `.dev.vars`) restart
216
+ Rsbuild's dev server, which closes the old server first: a broken config
217
+ leaves no server running, whereas the Vite plugin keeps the old one. Miniflare
218
+ is recreated rather than updated.
219
+ - The Rsbuild CLI loads `.env`, `.env.local`, `.env.[mode]` and
220
+ `.env.[mode].local` into `process.env`, using its own env mode and directory
221
+ rather than `envMode` and `envDir`. `process.env` takes precedence over the
222
+ plugin's `.env` files, so these values override the Worker's `.env` values. A
223
+ `.dev.vars` file is used on its own, so it isn't affected.
224
+ - The top-level `output.minify` setting for JavaScript, and the top-level
225
+ `resolve.extensions`, `resolve.conditionNames` and `resolve.mainFields`, don't
226
+ apply to Workers: the plugin sets these for the Worker environments, and
227
+ Rsbuild uses an environment's settings over the top-level ones. Set them in
228
+ `environments.<name>` instead. The top-level `output.sourceMap`, and the
229
+ `output.minify` setting for CSS, do apply.
230
+ - Without `source.entry` or client environments, a client is built from
231
+ Rsbuild's default entry (`src/index.*`) only when `index.html` exists at the
232
+ project root, where Vite builds one whenever `index.html` exists. The default
233
+ entry mustn't be a Worker's entrypoint, but an entrypoint that's an alias or a
234
+ bare specifier isn't recognised as it. Rsbuild doesn't use that `index.html`
235
+ as the page's template unless `html.template` is set to it. Without a client,
236
+ as in the Vite plugin, the client output has only the public assets (and the
237
+ assets that the entry Worker imports), and `assetsOnly` requires public assets
238
+ or a prerender Worker.
239
+ - `devOnly` and `assetsOnly` functions are called when the config is resolved,
240
+ to choose the Worker environments to build, rather than lazily at build time.
241
+ - Additional modules (e.g. `.wasm` and `.txt` imports) are emitted at the root
242
+ of the Worker's output directory, with hashed names, rather than in `assets/`.
243
+ - SWC lowers `using` declarations in the Worker build, which Vite keeps.
244
+ - No "Debug" URL is printed, but `/__debug` works.
245
+ - Miniflare's message about updating the compatibility date mentions
246
+ `@cloudflare/vite-plugin`.
@@ -0,0 +1,43 @@
1
+ import { createRequire } from "node:module";
2
+
3
+ //#region ../../workers-sdk/packages/workers-utils/dist/chunk-53YJWLG7.mjs
4
+ const require$1 = createRequire(import.meta.url || (typeof __filename === "string" ? __filename : "/"));
5
+ var __create = Object.create;
6
+ var __defProp = Object.defineProperty;
7
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
8
+ var __getOwnPropNames = Object.getOwnPropertyNames;
9
+ var __getProtoOf = Object.getPrototypeOf;
10
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
11
+ var __name = (target, value) => __defProp(target, "name", {
12
+ value,
13
+ configurable: true
14
+ });
15
+ var __require = /* @__PURE__ */ ((x) => typeof require$1 !== "undefined" ? require$1 : typeof Proxy !== "undefined" ? new Proxy(x, { get: (a, b) => (typeof require$1 !== "undefined" ? require$1 : a)[b] }) : x)(function(x) {
16
+ if (typeof require$1 !== "undefined") return require$1.apply(this, arguments);
17
+ throw Error("Dynamic require of \"" + x + "\" is not supported");
18
+ });
19
+ var __commonJS = (cb, mod) => function __require2() {
20
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
21
+ };
22
+ var __export = (target, all) => {
23
+ for (var name in all) __defProp(target, name, {
24
+ get: all[name],
25
+ enumerable: true
26
+ });
27
+ };
28
+ var __copyProps = (to, from, except, desc) => {
29
+ if (from && typeof from === "object" || typeof from === "function") {
30
+ for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
31
+ get: () => from[key],
32
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
33
+ });
34
+ }
35
+ return to;
36
+ };
37
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
38
+ value: mod,
39
+ enumerable: true
40
+ }) : target, mod));
41
+
42
+ //#endregion
43
+ export { __toESM as a, __require as i, __export as n, __name as r, __commonJS as t };
@@ -0,0 +1,123 @@
1
+ import { InputWorkerConfig, ParsedInputWorkerConfig } from "@cloudflare/config";
2
+ import { RsbuildPlugin } from "@rsbuild/core";
3
+
4
+ //#region ../../workers-sdk/packages/vite-plugin-cloudflare/src/plugin-config.d.ts
5
+
6
+ type PersistState = boolean | {
7
+ path: string;
8
+ };
9
+ type TunnelConfig = {
10
+ autoStart?: boolean;
11
+ name?: string;
12
+ /** Email addresses or domain patterns allowed to authenticate to a Quick Tunnel. */
13
+ allowedMail?: string[];
14
+ };
15
+ interface BaseWorkerOptions {
16
+ viteEnvironment?: {
17
+ name?: string;
18
+ childEnvironments?: string[];
19
+ };
20
+ }
21
+ /**
22
+ * Whether this Worker is only used during development and should not be built for production.
23
+ * Can be a boolean or a function that returns a boolean. The function is evaluated lazily
24
+ * at build time, allowing frameworks to provide the value after initialization.
25
+ */
26
+ type DevOnly = boolean | (() => boolean);
27
+ interface EntryWorkerOptions extends BaseWorkerOptions {
28
+ config?: EntryWorkerConfigCustomizer;
29
+ /**
30
+ * Whether the entry Worker should be omitted from the production build.
31
+ * Can be a boolean or a function that returns a boolean. The function is
32
+ * evaluated lazily at build time, allowing frameworks to provide the value
33
+ * after initialization.
34
+ *
35
+ * When set, an assets-only Build Output config is emitted. This enables using
36
+ * server-side code in development but producing a fully static app for
37
+ * deployment.
38
+ */
39
+ assetsOnly?: DevOnly;
40
+ }
41
+ interface AuxiliaryWorkerOptions extends BaseWorkerOptions {
42
+ /** Configure an auxiliary Worker. */
43
+ config: WorkerConfigProvider;
44
+ devOnly?: DevOnly;
45
+ }
46
+ interface PrerenderWorkerOptions extends BaseWorkerOptions {
47
+ config: WorkerConfigProvider;
48
+ }
49
+ interface TypeGenerationOptions {
50
+ /**
51
+ * Whether to auto-generate `.cloudflare/types/index.d.ts`. Defaults to
52
+ * `true`.
53
+ */
54
+ generate?: boolean;
55
+ /**
56
+ * Whether to include the Worker's runtime types (generated from the
57
+ * project's compatibility date and flags) in the generated
58
+ * `.cloudflare/types/index.d.ts`. Defaults to `true`.
59
+ */
60
+ includeRuntime?: boolean;
61
+ }
62
+ interface Experimental {
63
+ /** Experimental support for handling the _headers and _redirects files during Vite dev mode. */
64
+ headersAndRedirectsDevModeSupport?: boolean;
65
+ }
66
+ type EntryWorkerConfigCustomizer = Partial<ParsedInputWorkerConfig> | ((config: ParsedInputWorkerConfig) => Partial<ParsedInputWorkerConfig> | void);
67
+ type WorkerConfigProvider = InputWorkerConfig | ((options: {
68
+ entryWorkerConfig: ParsedInputWorkerConfig;
69
+ }) => InputWorkerConfig);
70
+ interface PluginConfig$1 extends EntryWorkerOptions {
71
+ auxiliaryWorkers?: AuxiliaryWorkerOptions[];
72
+ /** Configuration for a dedicated prerender Worker. */
73
+ prerenderWorker?: PrerenderWorkerOptions;
74
+ persistState?: PersistState;
75
+ inspectorPort?: number | false;
76
+ remoteBindings?: boolean;
77
+ tunnel?: boolean | TunnelConfig;
78
+ /**
79
+ * Options for generating Worker types from `cloudflare.config.ts`. Type
80
+ * generation is skipped when the file does not exist.
81
+ */
82
+ types?: TypeGenerationOptions;
83
+ experimental?: Experimental;
84
+ }
85
+ //#endregion
86
+ //#region src/index.d.ts
87
+ /** Options for the Rsbuild environment that builds a Worker. */
88
+ interface RsbuildEnvironmentOptions {
89
+ /**
90
+ * The Rsbuild environment that builds the Worker, in place of the Vite
91
+ * plugin's `viteEnvironment`. `name` is its key in Rsbuild's
92
+ * `environments` config.
93
+ */
94
+ rsbuildEnvironment?: {
95
+ name?: string;
96
+ };
97
+ }
98
+ /** A Worker's options in the Vite plugin, with `rsbuildEnvironment` in place of `viteEnvironment`. */
99
+ type RsbuildWorkerOptions<T> = Omit<T, "viteEnvironment"> & RsbuildEnvironmentOptions;
100
+ /**
101
+ * The same options as the Vite plugin's `cloudflare()`, apart from the tunnel,
102
+ * with `rsbuildEnvironment` in place of `viteEnvironment`.
103
+ */
104
+ interface PluginConfig extends RsbuildWorkerOptions<Omit<PluginConfig$1, "tunnel" | "auxiliaryWorkers" | "prerenderWorker">> {
105
+ auxiliaryWorkers?: Array<RsbuildWorkerOptions<NonNullable<PluginConfig$1["auxiliaryWorkers"]>[number]>>;
106
+ prerenderWorker?: RsbuildWorkerOptions<NonNullable<PluginConfig$1["prerenderWorker"]>>;
107
+ /** The directory to load `.env` and `.dev.vars` files from, or `false` to skip them. Defaults to the project root. */
108
+ envDir?: string | false;
109
+ /** The mode used to load `cloudflare.config.ts`, `.env.[mode]` and `.dev.vars.[mode]`. Defaults to Rsbuild's mode. */
110
+ envMode?: string;
111
+ }
112
+ /**
113
+ * Rsbuild plugin that builds the Workers defined in `cloudflare.config.ts` and
114
+ * the plugin options with rspack and runs them in workerd (via Miniflare)
115
+ * during `rsbuild dev`. `rsbuild build` writes the Build Output Specification
116
+ * to `.cloudflare/output`, which `rsbuild preview` runs in workerd.
117
+ *
118
+ * @param options Plugin options.
119
+ * @returns An Rsbuild plugin.
120
+ */
121
+ declare function cloudflare(options?: PluginConfig): RsbuildPlugin;
122
+ //#endregion
123
+ export { PluginConfig, cloudflare };