Skip to content

Commit 3bb8c78

Browse files
committed
basic websockets - closes #6
1 parent 84d243b commit 3bb8c78

File tree

5 files changed

+72
-11
lines changed

5 files changed

+72
-11
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
},
2525
"type": "module",
2626
"dependencies": {
27-
"marked": "^4.0.15"
27+
"marked": "^4.0.15",
28+
"ws": "^8.6.0"
2829
}
2930
}

src/lib/client/adapters/filesystem/index.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@ export async function create() {
88

99
const { id, port } = await res.json();
1010

11+
const ws = new WebSocket('ws://localhost:4567');
12+
13+
ws.addEventListener('message', (event) => {
14+
const payload = JSON.parse(event.data);
15+
if (payload.id === id) {
16+
console[payload.type === 'stdout' ? 'log' : 'error'](payload.data);
17+
}
18+
});
19+
1120
return {
1221
base: `http://localhost:${port}`,
1322

src/routes/backend/[id].js

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,31 @@ import fs from 'node:fs';
22
import path from 'node:path';
33
import { spawn } from 'node:child_process';
44
import { createRequire } from 'node:module';
5+
import { broadcast } from './_ws';
56

6-
const require = createRequire(import.meta.url);
7-
const sveltekit_pkg_file = require.resolve('@sveltejs/kit/package.json');
8-
const sveltekit_pkg = JSON.parse(fs.readFileSync(sveltekit_pkg_file, 'utf-8'));
9-
const sveltekit = path.resolve(sveltekit_pkg_file, '..', sveltekit_pkg.bin['svelte-kit']);
7+
/**
8+
* @typedef {{
9+
* process: import('child_process').ChildProcess,
10+
* files: string[]
11+
* }} App */
1012

11-
// poor man's HMR, pending Vite fix
13+
// poor man's HMR, pending https://github.com/vitejs/vite/issues/7887
1214
if (globalThis.__apps) {
1315
globalThis.__apps.forEach((app) => {
1416
app.process.kill();
1517
});
1618
}
1719

18-
/** @type {Map<string, { process: import('child_process').ChildProcess, files: string[] }>} */
20+
const require = createRequire(import.meta.url);
21+
const sveltekit_pkg_file = require.resolve('@sveltejs/kit/package.json');
22+
const sveltekit_pkg = JSON.parse(fs.readFileSync(sveltekit_pkg_file, 'utf-8'));
23+
const sveltekit = path.resolve(sveltekit_pkg_file, '..', sveltekit_pkg.bin['svelte-kit']);
24+
25+
/** @type {Map<string, App>} */
1926
const apps = new Map();
2027
globalThis.__apps = apps;
2128

22-
/** @type {import('./[id]').RequestHandler} */
29+
/** @type {import('./__types/[id]').RequestHandler} */
2330
export async function put({ request, params, url }) {
2431
const { id } = params;
2532
const port = /** @type {string} */ (url.searchParams.get('port'));
@@ -67,7 +74,7 @@ export async function put({ request, params, url }) {
6774
};
6875
}
6976

70-
/** @type {import('./[id]').RequestHandler} */
77+
/** @type {import('./__types/[id]').RequestHandler} */
7178
export async function del({ params }) {
7279
const { id } = params;
7380
const dir = `.apps/${id}`;
@@ -90,8 +97,15 @@ function launch(id, port) {
9097
const cwd = `.apps/${id}`;
9198

9299
const process = spawn(`${sveltekit}`, ['dev', '--port', port], {
93-
cwd,
94-
stdio: 'inherit' // TODO send to the client via a webworker?
100+
cwd
101+
});
102+
103+
process.stdout.on('data', (data) => {
104+
broadcast({ id, data: data.toString(), type: 'stdout' });
105+
});
106+
107+
process.stderr.on('data', (data) => {
108+
broadcast({ id, data: data.toString(), type: 'stderr' });
95109
});
96110

97111
return process;

src/routes/backend/_ws.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// import './websocket.js';
2+
import { WebSocketServer } from 'ws';
3+
4+
// poor man's HMR, pending https://github.com/vitejs/vite/issues/7887
5+
if (globalThis.__wss) {
6+
globalThis.__wss.close();
7+
}
8+
9+
const wss = new WebSocketServer({ port: 4567 });
10+
globalThis.__wss = wss;
11+
12+
/** @type {Set<import('ws').WebSocket>} */
13+
const connections = new Set();
14+
15+
wss.on('connection', (ws) => {
16+
connections.add(ws);
17+
18+
ws.on('close', () => {
19+
connections.delete(ws);
20+
});
21+
});
22+
23+
export const ready = new Promise((fulfil) => {
24+
wss.on('listening', () => {
25+
fulfil(undefined);
26+
});
27+
});
28+
29+
/** @param {any} data */
30+
export function broadcast(data) {
31+
for (const connection of connections) {
32+
connection.send(JSON.stringify(data));
33+
}
34+
}

src/routes/backend/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import fs from 'node:fs';
2+
import { ready } from './_ws';
23

34
fs.rmSync('.apps', { recursive: true, force: true });
45
fs.mkdirSync('.apps', { recursive: true });
@@ -11,6 +12,8 @@ export async function post() {
1112

1213
fs.mkdirSync(`.apps/${id}`);
1314

15+
await ready;
16+
1417
return {
1518
status: 201, // should this be a 200?
1619
body: {

0 commit comments

Comments
 (0)