rsbuild-plugin-cloudflare 0.0.0 → 0.0.1

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,229 @@
1
- # rsbuild-plugin-cloudflare
1
+ # `rsbuild-plugin-cloudflare`
2
2
 
3
- This is a placeholder release. The plugin isn't published yet.
3
+ An experimental [Rsbuild](https://rsbuild.rs) plugin for Cloudflare Workers. It
4
+ runs your Workers in workerd during `rsbuild dev` and `rsbuild preview`, and
5
+ builds them, with your client assets, during `rsbuild build` into a Cloudflare
6
+ Build Output that you can deploy with `cf deploy --prebuilt`.
7
+
8
+ It's built on the internals of
9
+ [`@cloudflare/vite-plugin`](https://developers.cloudflare.com/workers/vite-plugin/),
10
+ and accepts the same options.
11
+
12
+ > **Using TanStack Start?** Follow the [TanStack Start guide](#tanstack-start):
13
+ > the framework's server environment has to be set as the Worker's, or every
14
+ > request fails.
15
+
16
+ ## Usage
17
+
18
+ ```ts
19
+ // rsbuild.config.ts
20
+ import { cloudflare } from "rsbuild-plugin-cloudflare";
21
+ import { defineConfig } from "@rsbuild/core";
22
+
23
+ export default defineConfig({
24
+ plugins: [cloudflare()],
25
+ });
26
+ ```
27
+
28
+ The Worker is configured in `cloudflare.config.ts`, as for the Vite plugin.
29
+
30
+ ### Options
31
+
32
+ The options are those of the Vite plugin's `cloudflare()` (e.g. `config`,
33
+ `auxiliaryWorkers`, `persistState`, `inspectorPort`, `remoteBindings`), apart
34
+ from `tunnel`, and with `rsbuildEnvironment` in place of `viteEnvironment`
35
+ (see [Worker environments](#worker-environments)), plus:
36
+
37
+ - `envDir`: the directory to load `.env` and `.dev.vars` files from, or `false`
38
+ to skip them. Defaults to the project root.
39
+ - `envMode`: the mode used to load `cloudflare.config.ts`, `.env.[mode]` and
40
+ `.dev.vars.[mode]`. Defaults to Rsbuild's mode.
41
+
42
+ ### Worker environments
43
+
44
+ Each Worker is built by an
45
+ [Rsbuild environment](https://rsbuild.rs/config/environments). The entry
46
+ Worker's is named `cloudflare`, unless `rsbuildEnvironment.name` is set.
47
+ Auxiliary Workers' are named as in the Vite plugin, unless their own
48
+ `rsbuildEnvironment.name` is set. `rsbuildEnvironment` replaces the Vite
49
+ plugin's `viteEnvironment`, without `childEnvironments`.
50
+
51
+ To change how a Worker is built, configure its environment in Rsbuild's
52
+ `environments` config. The plugin merges its settings in, and yours take
53
+ precedence, apart from `source.entry`, `output.target` and `output.module`,
54
+ which the plugin always sets so that the Worker runs in workerd, and
55
+ `output.distPath.root`, which it sets to the Worker's Build Output location, as
56
+ the Vite plugin does.
57
+
58
+ ```ts
59
+ export default defineConfig({
60
+ plugins: [cloudflare()],
61
+ environments: {
62
+ cloudflare: { output: { minify: true } },
63
+ },
64
+ });
65
+ ```
66
+
67
+ ### Frameworks
68
+
69
+ As with the Vite plugin, put `cloudflare()` before the framework's plugins, and
70
+ set `rsbuildEnvironment.name` to the framework's server environment. The plugin
71
+ builds that environment for workerd, whatever target the framework sets.
72
+
73
+ In dev, the Worker environment's `loadBundle()` returns a module whose `fetch`
74
+ sends requests to the Worker in workerd, so frameworks that serve their server
75
+ bundle through `loadBundle()`, such as
76
+ [TanStack Start](https://tanstack.com/start), run it in workerd.
77
+
78
+ #### TanStack Start
79
+
80
+ To run a [TanStack Start](https://tanstack.com/start) app that's built with
81
+ Rsbuild (e.g. one created from TanStack's Rsbuild template) on Workers:
82
+
83
+ 1. Install the plugin, and [`cf`](https://www.npmjs.com/package/cf) for
84
+ `cf/config` and `cf deploy`:
85
+
86
+ ```sh
87
+ pnpm add -D rsbuild-plugin-cloudflare cf
88
+ ```
89
+
90
+ 2. Configure the Worker in `cloudflare.config.ts`, with TanStack Start's server
91
+ entry as its entrypoint. TanStack Start uses Node.js APIs, such as
92
+ `AsyncLocalStorage`. From compatibility date `2026-08-04`,
93
+ [Node.js compatibility](https://developers.cloudflare.com/workers/runtime-apis/nodejs/)
94
+ is on by default; with an earlier date, add the `nodejs_compat` flag.
95
+
96
+ ```ts
97
+ // cloudflare.config.ts
98
+ import { defineConfig } from "cf/config";
99
+
100
+ export default defineConfig({
101
+ worker: {
102
+ name: "my-tanstack-start-app",
103
+ entrypoint: "@tanstack/react-start/server-entry",
104
+ compatibilityDate: "2026-10-19",
105
+ },
106
+ });
107
+ ```
108
+
109
+ 3. Add `cloudflare()` before `tanstackStart()`, with `rsbuildEnvironment.name`
110
+ set to TanStack Start's server environment, `ssr`. This is required: without
111
+ it, the plugin builds the entrypoint in its own `cloudflare` environment,
112
+ without TanStack Start's build setup, and every request fails (e.g. with
113
+ `tsrStartManifest is not a function`).
114
+
115
+ ```ts
116
+ // rsbuild.config.ts
117
+ import { defineConfig } from "@rsbuild/core";
118
+ import { pluginReact } from "@rsbuild/plugin-react";
119
+ import { tanstackStart } from "@tanstack/react-start/plugin/rsbuild";
120
+ import { cloudflare } from "rsbuild-plugin-cloudflare";
121
+
122
+ export default defineConfig({
123
+ plugins: [
124
+ pluginReact(),
125
+ cloudflare({ rsbuildEnvironment: { name: "ssr" } }),
126
+ tanstackStart(),
127
+ ],
128
+ });
129
+ ```
130
+
131
+ 4. Replace the template's scripts. Its `start` script runs the server in
132
+ Node.js, so it doesn't apply; `rsbuild preview` runs the build in workerd.
133
+
134
+ ```json
135
+ {
136
+ "scripts": {
137
+ "dev": "rsbuild dev",
138
+ "build": "rsbuild build",
139
+ "preview": "rsbuild preview",
140
+ "deploy": "rsbuild build && cf deploy --prebuilt"
141
+ }
142
+ }
143
+ ```
144
+
145
+ 5. Add `.cloudflare` to `.gitignore`. It holds the bindings' local state, the
146
+ Build Output, and the Worker's types, which are generated to
147
+ `.cloudflare/types`: add that to `tsconfig.json`'s `include` to use them.
148
+
149
+ Server functions and server routes can then use the Worker's bindings:
150
+
151
+ ```ts
152
+ import { createServerFn } from "@tanstack/react-start";
153
+ import { env } from "cloudflare:workers";
154
+
155
+ const getGreeting = createServerFn().handler(() => env.GREETING);
156
+ ```
157
+
158
+ See [`packages/e2e/fixtures/tanstack-start`](https://github.com/james-elicx/rsbuild-plugin-cloudflare/tree/main/packages/e2e/fixtures/tanstack-start) for
159
+ a complete app.
160
+
161
+ ## Differences from the Vite plugin
162
+
163
+ The plugin replaces Vite's module runner with Rsbuild's bundles, so behaviour
164
+ that depends on how Vite works internally isn't available:
165
+
166
+ - Workers are rebuilt and reloaded when their code changes; there's no in-Worker
167
+ HMR (`import.meta.hot`).
168
+ - Uncaught errors in the entry Worker aren't returned to the dev server with
169
+ the `MF-Experimental-Error-Stack` header, as the Vite plugin's module runner
170
+ does, so there's no error overlay or source-mapped stack: the browser gets a
171
+ plain-text `500` response.
172
+ - Child environments, the hot channel, `bundledDev`, middleware mode, custom
173
+ `buildApp`s and Vite plugins (e.g. for virtual modules) don't apply.
174
+ - Prerendering isn't supported, as Rsbuild has no equivalent of `buildApp`. The
175
+ prerender Worker is still built and written to the Build Output.
176
+ - Containers aren't supported yet: in dev and preview, a warning is logged and
177
+ Container-backed Durable Objects fail; in a build, a warning is logged and no
178
+ Container images or Container output are written.
179
+ - `tunnel` and the Vite CLI shortcuts aren't supported.
180
+ - The Local Explorer hint that the Vite plugin prints for AI agents isn't
181
+ printed.
182
+
183
+ Other differences:
184
+
185
+ - Rsbuild serves `/` and `*.html` itself, so the plugin intercepts page
186
+ navigations (`GET` and `HEAD` requests for `.html` paths or paths without an
187
+ extension, apart from Rsbuild's HMR path and paths starting with `/__` or
188
+ `/rsbuild-`) and sends them to the Workers. These requests reach the Workers
189
+ before Rsbuild's `server.proxy`.
190
+ - In dev, Rsbuild also serves the Worker environments' output (e.g.
191
+ `/index.js` and `/index.js.map`), as it serves the assets of every
192
+ `web-worker` environment.
193
+ - When workerd restarts, the Vite plugin restarts the dev server; the Rsbuild
194
+ bundles don't depend on workerd's state, so the plugin doesn't.
195
+ - Setting `output.externals` (other than Node.js built-ins) for a Worker's
196
+ environment logs a warning, where the Vite plugin rejects `resolve.external`,
197
+ as Rsbuild also applies top-level externals to every environment.
198
+ - Config changes (e.g. to `cloudflare.config.ts` or `.dev.vars`) restart
199
+ Rsbuild's dev server, which closes the old server first: a broken config
200
+ leaves no server running, whereas the Vite plugin keeps the old one. Miniflare
201
+ is recreated rather than updated.
202
+ - The Rsbuild CLI loads `.env`, `.env.local`, `.env.[mode]` and
203
+ `.env.[mode].local` into `process.env`, using its own env mode and directory
204
+ rather than `envMode` and `envDir`. `process.env` takes precedence over the
205
+ plugin's `.env` files, so these values override the Worker's `.env` values. A
206
+ `.dev.vars` file is used on its own, so it isn't affected.
207
+ - The top-level `output.minify` setting for JavaScript, and the top-level
208
+ `resolve.extensions`, `resolve.conditionNames` and `resolve.mainFields`, don't
209
+ apply to Workers: the plugin sets these for the Worker environments, and
210
+ Rsbuild uses an environment's settings over the top-level ones. Set them in
211
+ `environments.<name>` instead. The top-level `output.sourceMap`, and the
212
+ `output.minify` setting for CSS, do apply.
213
+ - Without `source.entry` or client environments, a client is built from
214
+ Rsbuild's default entry (`src/index.*`) only when `index.html` exists at the
215
+ project root, where Vite builds one whenever `index.html` exists. The default
216
+ entry mustn't be a Worker's entrypoint, but an entrypoint that's an alias or a
217
+ bare specifier isn't recognised as it. Rsbuild doesn't use that `index.html`
218
+ as the page's template unless `html.template` is set to it. Without a client,
219
+ as in the Vite plugin, the client output has only the public assets (and the
220
+ assets that the entry Worker imports), and `assetsOnly` requires public assets
221
+ or a prerender Worker.
222
+ - `devOnly` and `assetsOnly` functions are called when the config is resolved,
223
+ to choose the Worker environments to build, rather than lazily at build time.
224
+ - Additional modules (e.g. `.wasm` and `.txt` imports) are emitted at the root
225
+ of the Worker's output directory, with hashed names, rather than in `assets/`.
226
+ - SWC lowers `using` declarations in the Worker build, which Vite keeps.
227
+ - No "Debug" URL is printed, but `/__debug` works.
228
+ - Miniflare's message about updating the compatibility date mentions
229
+ `@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 };