@csedl/svelte-on-rails 11.0.4 → 12.0.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.
@@ -0,0 +1,141 @@
1
+ // app/javascript/ssr/svelte-ssr-server.js
2
+ // Minimal persistent SSR server for SvelteOnRails
3
+ // Listens on Unix socket (preferred) or TCP port fallback
4
+
5
+ import http from 'node:http';
6
+ import fs from 'node:fs';
7
+ import path from 'node:path';
8
+ import { render } from 'svelte/server';
9
+ import { readPropsFromStdin } from "../src/ssr/readStdin.js";
10
+ import { loadComponentModule } from "../src/ssr/loadComponent.js";
11
+
12
+ // Config from ENV or defaults
13
+ const SOCKET_PATH = process.argv[2];
14
+ const PORT = (/^\d+$/.test(SOCKET_PATH) ? SOCKET_PATH : null);
15
+ const LOGFILE = process.env.SVELTE_SSR_SERVER_LOGFILE;
16
+
17
+ if (!SOCKET_PATH && (process.argv.length <= 2)) {
18
+ console.error(`Missing first argument: socket path or port number.\nUsage:\nnode svelte-ssr-server.js /path/to/socket.sock\nnode svelte-ssr-server.js 3001`);
19
+ process.exit(1);
20
+ }
21
+
22
+ if (LOGFILE) {
23
+ console.log(`Logging to ${LOGFILE}`);
24
+ } else {
25
+ console.log(`No log file specified. Logging to stdout.`);
26
+ }
27
+
28
+ // Clean up old socket file
29
+ if (SOCKET_PATH.startsWith('/') && fs.existsSync(SOCKET_PATH)) {
30
+ fs.unlinkSync(SOCKET_PATH);
31
+ logger(`Cleaned old socket: ${SOCKET_PATH}`);
32
+ }
33
+
34
+ const server = http.createServer(async (req, res) => {
35
+ // Simple logging
36
+ logger(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
37
+
38
+ // Health check / ping
39
+ if (req.method === 'GET' && (req.url === '/ping' || req.url === '/health')) {
40
+ res.writeHead(200, { 'Content-Type': 'application/json' });
41
+ res.end(JSON.stringify({
42
+ status: 'alive',
43
+ uptime: process.uptime(),
44
+ pid: process.pid,
45
+ socket: SOCKET_PATH
46
+ }));
47
+ return;
48
+ }
49
+
50
+ // SSR render endpoint (stub for now)
51
+ if (req.method === 'POST' && req.url === '/render') {
52
+ let request_body = '';
53
+ req.on('data', chunk => { request_body += chunk; });
54
+ req.on('end', async () => {
55
+ try {
56
+
57
+ // parsing request-body
58
+
59
+ logger(`Parsing request_body...`);
60
+ const { component, props = {} } = JSON.parse(request_body);
61
+ const basename = path.basename(component);
62
+ logger(`Rendering component: ${basename} with props: ${JSON.stringify(props)}`);
63
+
64
+ // lad component
65
+
66
+ const compiledComponent = await loadComponentModule(component);
67
+ logger(`Component loaded: «${compiledComponent}»`);
68
+
69
+ // render
70
+
71
+ const { body, head } = render(compiledComponent, { props });
72
+ logger(`Component rendered, content: «${body}», head: «${head}»`);
73
+
74
+
75
+
76
+ // TODO: Replace with real Svelte SSR rendering
77
+ // Example: const { html, css, head } = YourSvelteComponent.render(props);
78
+ const dummyHtml = `<div data-component="${component}">Hello from SSR! Props: ${JSON.stringify(props)}</div>`;
79
+ const dummyCss = '';
80
+ const dummyHead = '<meta name="ssr-stub" content="placeholder">';
81
+
82
+ res.writeHead(200, { 'Content-Type': 'application/json' });
83
+ res.end(JSON.stringify({
84
+ html: body,
85
+ css: dummyCss,
86
+ head: head
87
+ }));
88
+
89
+ logger(`Successfully rendered: ${basename}`);
90
+ } catch (err) {
91
+ logger(`Render error: ${err}`);
92
+ logger(`body => «${request_body}»`);
93
+ res.writeHead(500, { 'Content-Type': 'application/json' });
94
+ res.end(JSON.stringify({ error: 'SSR render failed', details: err.message }));
95
+ }
96
+ });
97
+ return;
98
+ }
99
+
100
+ // Fallback 404
101
+ res.writeHead(404, { 'Content-Type': 'application/json' });
102
+ res.end(JSON.stringify({ error: 'Not found' }));
103
+ });
104
+
105
+ // LOGGING
106
+ function logger(msg, error = false) {
107
+ if (error) {
108
+ console.error(msg);
109
+ } else {
110
+ console.log(msg);
111
+ };
112
+ if (LOGFILE) {
113
+ fs.appendFileSync(LOGFILE, `${new Date().toISOString()} ${msg}\n`);
114
+ }
115
+ }
116
+
117
+
118
+ // Start server
119
+ if (PORT) {
120
+ // TCP mode (e.g. for debugging or non-Unix environments)
121
+ server.listen(PORT, '127.0.0.1', () => {
122
+ logger(`Svelte SSR listening on http://127.0.0.1:${PORT}`);
123
+ });
124
+ } else {
125
+ // Preferred: Unix socket
126
+ server.listen(SOCKET_PATH, () => {
127
+ fs.chmodSync(SOCKET_PATH, 0o600); // restrict access
128
+ logger(`Svelte SSR listening on unix socket: ${SOCKET_PATH}`);
129
+ });
130
+ }
131
+
132
+ // Graceful shutdown
133
+ process.on('SIGINT', () => {
134
+ logger('Shutting down SSR server...');
135
+ server.close(() => {
136
+ if (SOCKET_PATH.startsWith('/') && fs.existsSync(SOCKET_PATH)) {
137
+ fs.unlinkSync(SOCKET_PATH);
138
+ }
139
+ process.exit(0);
140
+ });
141
+ });
package/package.json CHANGED
@@ -1,9 +1,12 @@
1
1
  {
2
2
  "name": "@csedl/svelte-on-rails",
3
- "version": "11.0.4",
3
+ "version": "12.0.0",
4
4
  "description": "Client-side runtime for svelte-on-rails: hydration, SSR build support & Turbo Stream actions",
5
5
  "main": "index.js",
6
6
  "type": "module",
7
+ "engines": {
8
+ "node": ">=24.0.0"
9
+ },
7
10
  "scripts": {
8
11
  "build:package": "vite build"
9
12
  },
@@ -28,10 +31,7 @@
28
31
  "type": "git",
29
32
  "url": "https://gitlab.com/sedl/svelte-on-rails"
30
33
  },
31
- "keywords": [
32
- "svelte",
33
- "rails"
34
- ],
34
+ "keywords": [ "svelte", "rails"],
35
35
  "author": "Christian Sedlmair",
36
36
  "license": "LICENSE.md",
37
37
  "bugs": {
package/src/ssr/render.js CHANGED
@@ -7,10 +7,11 @@ const compiledComponentPath = process.argv[2];
7
7
 
8
8
 
9
9
  (async () => {
10
+ console.log(`${performance.now()}<time>`);
10
11
  console.log(`[svelte-on-rails:debug] awaiting load component => «${compiledComponentPath}»`);
11
12
  const compiledComponent = await loadComponentModule(compiledComponentPath);
12
13
 
13
- console.log(`[svelte-on-rails:debug] component read: «${compiledComponent}»`);
14
+ console.log(`[svelte-on-rails:debug] Component loaded: «${compiledComponent}»`);
14
15
 
15
16
  const props = await readPropsFromStdin();
16
17
  console.log(`[svelte-on-rails:debug] props read: «${JSON.stringify(props)}»`);
@@ -26,7 +27,7 @@ const compiledComponentPath = process.argv[2];
26
27
  head: head || '', // Optional: Include <head> content (styles, meta, etc.)
27
28
  // Add bodyAttributes or other result props if needed in future
28
29
  };
29
-
30
+ console.log(`<time>${performance.now()}`);
30
31
  console.log('[svelte-on-rails:successful-json-response]' + JSON.stringify(res));
31
32
  } catch (error) {
32
33
  console.error('[svelte-on-rails:debug] Error rendering component:', error);