@oselvar/sveltekit-add-worker-exports 0.1.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 +21 -0
- package/README.md +121 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.js +123 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Oselvar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# @oselvar/sveltekit-add-worker-exports
|
|
2
|
+
|
|
3
|
+
A Vite plugin that makes Durable Objects and Workflows work with SvelteKit on Cloudflare, in both dev and production.
|
|
4
|
+
|
|
5
|
+
**Build mode:** SvelteKit's `adapter-cloudflare` generates `_worker.js` with only a default export (the fetch handler). Cloudflare Workers requires Durable Object and Workflow classes to be **named exports**. This plugin post-processes the build output to merge your named exports with SvelteKit's default export.
|
|
6
|
+
|
|
7
|
+
**Dev mode:** `getPlatformProxy` (used by `adapter-cloudflare` in dev) can't run internal Durable Objects. This plugin starts a separate wrangler dev server that runs the real DO worker with hot-reload. Clients connect directly to it via WebSocket on a separate port.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add -D @oselvar/sveltekit-add-worker-exports
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`esbuild`, `vite`, and `wrangler` are peer dependencies -- your SvelteKit project already has them.
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
Create a file that exports your Durable Object and/or Workflow classes:
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
// src/lib/server/index.ts
|
|
23
|
+
export { MyDurableObject } from './MyDurableObject';
|
|
24
|
+
|
|
25
|
+
export default {
|
|
26
|
+
async fetch(request: Request, env: Env): Promise<Response> {
|
|
27
|
+
// Route WebSocket upgrades to Durable Objects (used during dev)
|
|
28
|
+
const url = new URL(request.url);
|
|
29
|
+
const match = url.pathname.match(/^\/ws\/(.+)$/);
|
|
30
|
+
if (match && request.headers.get('Upgrade') === 'websocket') {
|
|
31
|
+
const id = env.MY_DO.idFromName(match[1]);
|
|
32
|
+
return env.MY_DO.get(id).fetch(request);
|
|
33
|
+
}
|
|
34
|
+
return new Response('Not found', { status: 404 });
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Add the plugin to your `vite.config.ts` **after** `sveltekit()`:
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { sveltekit } from '@sveltejs/kit/vite';
|
|
43
|
+
import { addWorkerExports } from '@oselvar/sveltekit-add-worker-exports';
|
|
44
|
+
import { defineConfig } from 'vite';
|
|
45
|
+
|
|
46
|
+
export default defineConfig({
|
|
47
|
+
plugins: [
|
|
48
|
+
sveltekit(),
|
|
49
|
+
addWorkerExports({ entryPoint: 'src/lib/server/index.ts' })
|
|
50
|
+
]
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Dev mode: connecting to Durable Objects
|
|
55
|
+
|
|
56
|
+
In dev mode, the plugin starts a wrangler dev server on a separate port and injects `__DEV_WORKER_PORT__` as a compile-time constant. Use it to connect your client:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { dev } from '$app/environment';
|
|
60
|
+
|
|
61
|
+
let wsUrl: string;
|
|
62
|
+
if (dev) {
|
|
63
|
+
wsUrl = `ws://${window.location.hostname}:${__DEV_WORKER_PORT__}/ws/${id}`;
|
|
64
|
+
} else {
|
|
65
|
+
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
66
|
+
wsUrl = `${protocol}//${window.location.host}/ws/${id}`;
|
|
67
|
+
}
|
|
68
|
+
const ws = new WebSocket(wsUrl);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Add the type declaration to your `src/app.d.ts`:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
declare global {
|
|
75
|
+
const __DEV_WORKER_PORT__: number;
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The plugin auto-discovers your `wrangler.jsonc` (or `wrangler.toml`) and reads DO bindings, migrations, and compatibility settings from it. It overrides only the `main` entry point to use your source file instead of the SvelteKit build output.
|
|
80
|
+
|
|
81
|
+
## Options
|
|
82
|
+
|
|
83
|
+
| Option | Type | Required | Default | Description |
|
|
84
|
+
|--------|------|----------|---------|-------------|
|
|
85
|
+
| `entryPoint` | `string` | Yes | -- | Path to the file that exports your DO/Workflow classes |
|
|
86
|
+
| `outputDir` | `string` | No | `.svelte-kit/cloudflare` | Directory containing the SvelteKit-generated `_worker.js` |
|
|
87
|
+
| `wranglerConfig` | `string` | No | auto-discovered | Path to wrangler config file |
|
|
88
|
+
| `devPort` | `number` | No | `8787` | Port for the dev worker server |
|
|
89
|
+
|
|
90
|
+
## How it works
|
|
91
|
+
|
|
92
|
+
### Build mode
|
|
93
|
+
|
|
94
|
+
The plugin runs in the `closeBundle` hook (after SvelteKit's adapter has generated `_worker.js`):
|
|
95
|
+
|
|
96
|
+
1. Bundles your `entryPoint` with esbuild into `_extra_exports.js`
|
|
97
|
+
2. Renames the original `_worker.js` to `_sveltekit_worker.js`
|
|
98
|
+
3. Creates a new `_worker.js` that re-exports both:
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
export { default } from './_sveltekit_worker.js';
|
|
102
|
+
export * from './_extra_exports.js';
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The operation is idempotent -- if `_sveltekit_worker.js` already exists, the plugin skips.
|
|
106
|
+
|
|
107
|
+
### Dev mode
|
|
108
|
+
|
|
109
|
+
The plugin reads your wrangler config, creates a temporary config with `main` pointing to your `entryPoint`, and starts a wrangler dev server via `unstable_startWorker`. This gives you:
|
|
110
|
+
|
|
111
|
+
- Real workerd runtime (not emulated)
|
|
112
|
+
- Hot-reload when you change DO code
|
|
113
|
+
- Same WebSocket protocol as production
|
|
114
|
+
|
|
115
|
+
## Why this exists
|
|
116
|
+
|
|
117
|
+
SvelteKit's adapter-cloudflare does not support named exports from the worker entry point ([sveltejs/kit#1712](https://github.com/sveltejs/kit/issues/1712)). Additionally, `getPlatformProxy` (used for local dev) cannot run internal Durable Objects because it uses an empty worker script.
|
|
118
|
+
|
|
119
|
+
## License
|
|
120
|
+
|
|
121
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite plugin that makes Durable Objects and Workflows work with SvelteKit
|
|
3
|
+
* on Cloudflare, in both dev and production.
|
|
4
|
+
*
|
|
5
|
+
* **Build mode:** SvelteKit's adapter-cloudflare generates _worker.js with
|
|
6
|
+
* only a default export. Cloudflare requires DO/Workflow classes as named
|
|
7
|
+
* exports. This plugin post-processes the build output to merge them.
|
|
8
|
+
*
|
|
9
|
+
* **Dev mode:** `getPlatformProxy` (used by adapter-cloudflare in dev) can't
|
|
10
|
+
* run internal Durable Objects. This plugin starts a separate wrangler dev
|
|
11
|
+
* server via `unstable_startWorker` that runs the real DO worker. Clients
|
|
12
|
+
* connect directly to it via WebSocket on a separate port.
|
|
13
|
+
*
|
|
14
|
+
* Usage in vite.config.ts:
|
|
15
|
+
* addWorkerExports({ entryPoint: 'src/lib/server/index.ts' })
|
|
16
|
+
*
|
|
17
|
+
* @see https://github.com/sveltejs/kit/issues/1712
|
|
18
|
+
*/
|
|
19
|
+
import type { Plugin } from 'vite';
|
|
20
|
+
export interface AddWorkerExportsOptions {
|
|
21
|
+
/** File that exports Durable Object and/or Workflow classes */
|
|
22
|
+
entryPoint: string;
|
|
23
|
+
/** Directory containing the SvelteKit-generated _worker.js (default: .svelte-kit/cloudflare) */
|
|
24
|
+
outputDir?: string;
|
|
25
|
+
/** Override wrangler config path (default: auto-discovered by wrangler) */
|
|
26
|
+
wranglerConfig?: string;
|
|
27
|
+
/** Port for the dev worker server (default: 8787) */
|
|
28
|
+
devPort?: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Returns two Vite plugins: one for build (patches _worker.js) and one for
|
|
32
|
+
* dev (starts a wrangler dev server for Durable Objects).
|
|
33
|
+
*
|
|
34
|
+
* The dev plugin injects `__DEV_WORKER_PORT__` as a compile-time constant
|
|
35
|
+
* via Vite's `define`. Declare it in your app's type definitions:
|
|
36
|
+
*
|
|
37
|
+
* ```typescript
|
|
38
|
+
* // src/app.d.ts
|
|
39
|
+
* declare global {
|
|
40
|
+
* const __DEV_WORKER_PORT__: number;
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare function addWorkerExports(options: AddWorkerExportsOptions): Plugin[];
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite plugin that makes Durable Objects and Workflows work with SvelteKit
|
|
3
|
+
* on Cloudflare, in both dev and production.
|
|
4
|
+
*
|
|
5
|
+
* **Build mode:** SvelteKit's adapter-cloudflare generates _worker.js with
|
|
6
|
+
* only a default export. Cloudflare requires DO/Workflow classes as named
|
|
7
|
+
* exports. This plugin post-processes the build output to merge them.
|
|
8
|
+
*
|
|
9
|
+
* **Dev mode:** `getPlatformProxy` (used by adapter-cloudflare in dev) can't
|
|
10
|
+
* run internal Durable Objects. This plugin starts a separate wrangler dev
|
|
11
|
+
* server via `unstable_startWorker` that runs the real DO worker. Clients
|
|
12
|
+
* connect directly to it via WebSocket on a separate port.
|
|
13
|
+
*
|
|
14
|
+
* Usage in vite.config.ts:
|
|
15
|
+
* addWorkerExports({ entryPoint: 'src/lib/server/index.ts' })
|
|
16
|
+
*
|
|
17
|
+
* @see https://github.com/sveltejs/kit/issues/1712
|
|
18
|
+
*/
|
|
19
|
+
import { build } from 'esbuild';
|
|
20
|
+
import { access, readFile, rename, writeFile, unlink } from 'node:fs/promises';
|
|
21
|
+
import { resolve } from 'node:path';
|
|
22
|
+
import { parse as parseJsonc } from 'jsonc-parser';
|
|
23
|
+
const DEFAULT_DEV_PORT = 8787;
|
|
24
|
+
/**
|
|
25
|
+
* Returns two Vite plugins: one for build (patches _worker.js) and one for
|
|
26
|
+
* dev (starts a wrangler dev server for Durable Objects).
|
|
27
|
+
*
|
|
28
|
+
* The dev plugin injects `__DEV_WORKER_PORT__` as a compile-time constant
|
|
29
|
+
* via Vite's `define`. Declare it in your app's type definitions:
|
|
30
|
+
*
|
|
31
|
+
* ```typescript
|
|
32
|
+
* // src/app.d.ts
|
|
33
|
+
* declare global {
|
|
34
|
+
* const __DEV_WORKER_PORT__: number;
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export function addWorkerExports(options) {
|
|
39
|
+
return [buildPlugin(options), devPlugin(options)];
|
|
40
|
+
}
|
|
41
|
+
function buildPlugin(options) {
|
|
42
|
+
return {
|
|
43
|
+
name: 'add-worker-exports',
|
|
44
|
+
apply: 'build',
|
|
45
|
+
enforce: 'post',
|
|
46
|
+
async closeBundle() {
|
|
47
|
+
const outputDir = resolve(options.outputDir ?? '.svelte-kit/cloudflare');
|
|
48
|
+
const workerPath = resolve(outputDir, '_worker.js');
|
|
49
|
+
const sveltekitPath = resolve(outputDir, '_sveltekit_worker.js');
|
|
50
|
+
const exportsPath = resolve(outputDir, '_extra_exports.js');
|
|
51
|
+
// Skip if already patched (idempotent)
|
|
52
|
+
if (await exists(sveltekitPath)) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
// Skip if the adapter hasn't run yet (e.g. during SSR build phase)
|
|
56
|
+
if (!(await exists(workerPath))) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
// Bundle the named exports
|
|
60
|
+
await build({
|
|
61
|
+
entryPoints: [options.entryPoint],
|
|
62
|
+
bundle: true,
|
|
63
|
+
format: 'esm',
|
|
64
|
+
sourcemap: true,
|
|
65
|
+
target: 'esnext',
|
|
66
|
+
external: ['cloudflare:*'],
|
|
67
|
+
outfile: exportsPath
|
|
68
|
+
});
|
|
69
|
+
// Rename original worker and create merged entry point
|
|
70
|
+
await rename(workerPath, sveltekitPath);
|
|
71
|
+
await writeFile(workerPath, `export { default } from './_sveltekit_worker.js';\nexport * from './_extra_exports.js';\n`);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function devPlugin(options) {
|
|
76
|
+
const devPort = options.devPort ?? DEFAULT_DEV_PORT;
|
|
77
|
+
let worker = null;
|
|
78
|
+
let tempConfigPath = null;
|
|
79
|
+
return {
|
|
80
|
+
name: 'add-worker-exports-dev',
|
|
81
|
+
apply: 'serve',
|
|
82
|
+
config() {
|
|
83
|
+
return {
|
|
84
|
+
define: {
|
|
85
|
+
__DEV_WORKER_PORT__: JSON.stringify(devPort)
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
},
|
|
89
|
+
async configureServer(server) {
|
|
90
|
+
const { unstable_readConfig, unstable_startWorker } = await import('wrangler');
|
|
91
|
+
// Read the project's wrangler config (auto-discovers wrangler.jsonc/toml)
|
|
92
|
+
const wranglerConfig = unstable_readConfig(options.wranglerConfig ? { config: options.wranglerConfig } : {});
|
|
93
|
+
// Copy the raw config and override main, name, and dev port
|
|
94
|
+
const rawJson = await readFile(wranglerConfig.configPath, 'utf-8');
|
|
95
|
+
const devConfig = parseJsonc(rawJson);
|
|
96
|
+
devConfig.name = `${devConfig.name ?? 'sveltekit'}-dev-worker`;
|
|
97
|
+
devConfig.main = options.entryPoint;
|
|
98
|
+
devConfig.dev = { ...devConfig.dev, port: devPort };
|
|
99
|
+
delete devConfig.assets;
|
|
100
|
+
tempConfigPath = resolve('.dev-worker-wrangler.jsonc');
|
|
101
|
+
await writeFile(tempConfigPath, JSON.stringify(devConfig, null, '\t'));
|
|
102
|
+
worker = await unstable_startWorker({ config: tempConfigPath });
|
|
103
|
+
server.httpServer?.on('close', async () => {
|
|
104
|
+
if (worker) {
|
|
105
|
+
await worker.dispose();
|
|
106
|
+
worker = null;
|
|
107
|
+
}
|
|
108
|
+
if (tempConfigPath) {
|
|
109
|
+
await unlink(tempConfigPath).catch(() => { });
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
async function exists(path) {
|
|
116
|
+
try {
|
|
117
|
+
await access(path);
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@oselvar/sveltekit-add-worker-exports",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Vite plugin that adds Durable Object and Workflow exports to SvelteKit Cloudflare workers",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/oselvar/sveltekit-add-worker-exports"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"sveltekit",
|
|
25
|
+
"cloudflare",
|
|
26
|
+
"workers",
|
|
27
|
+
"durable-objects",
|
|
28
|
+
"workflows",
|
|
29
|
+
"vite-plugin"
|
|
30
|
+
],
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"esbuild": ">=0.17",
|
|
33
|
+
"vite": ">=5",
|
|
34
|
+
"wrangler": ">=4"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^22.0.0",
|
|
38
|
+
"esbuild": "^0.25.0",
|
|
39
|
+
"np": "^11.2.0",
|
|
40
|
+
"typescript": "^5.0.0",
|
|
41
|
+
"vite": "^6.0.0",
|
|
42
|
+
"wrangler": "^4.84.0"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsc",
|
|
46
|
+
"test": "tsc --noEmit",
|
|
47
|
+
"prepublishOnly": "tsc"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"jsonc-parser": "^3.3.1"
|
|
51
|
+
}
|
|
52
|
+
}
|