@csedl/svelte-on-rails 12.0.0 → 12.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.
@@ -1,15 +1,11 @@
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
1
 
5
2
  import http from 'node:http';
6
3
  import fs from 'node:fs';
7
4
  import path from 'node:path';
8
5
  import { render } from 'svelte/server';
9
- import { readPropsFromStdin } from "../src/ssr/readStdin.js";
10
6
  import { loadComponentModule } from "../src/ssr/loadComponent.js";
7
+ import { componentRenderError} from "../src/utils.js";
11
8
 
12
- // Config from ENV or defaults
13
9
  const SOCKET_PATH = process.argv[2];
14
10
  const PORT = (/^\d+$/.test(SOCKET_PATH) ? SOCKET_PATH : null);
15
11
  const LOGFILE = process.env.SVELTE_SSR_SERVER_LOGFILE;
@@ -32,10 +28,11 @@ if (SOCKET_PATH.startsWith('/') && fs.existsSync(SOCKET_PATH)) {
32
28
  }
33
29
 
34
30
  const server = http.createServer(async (req, res) => {
35
- // Simple logging
31
+
36
32
  logger(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
37
33
 
38
34
  // Health check / ping
35
+
39
36
  if (req.method === 'GET' && (req.url === '/ping' || req.url === '/health')) {
40
37
  res.writeHead(200, { 'Content-Type': 'application/json' });
41
38
  res.end(JSON.stringify({
@@ -47,18 +44,20 @@ const server = http.createServer(async (req, res) => {
47
44
  return;
48
45
  }
49
46
 
50
- // SSR render endpoint (stub for now)
47
+ // Render
48
+
51
49
  if (req.method === 'POST' && req.url === '/render') {
52
50
  let request_body = '';
53
51
  req.on('data', chunk => { request_body += chunk; });
54
52
  req.on('end', async () => {
53
+ let basename = 'unknown';
55
54
  try {
56
55
 
57
56
  // parsing request-body
58
57
 
59
58
  logger(`Parsing request_body...`);
60
59
  const { component, props = {} } = JSON.parse(request_body);
61
- const basename = path.basename(component);
60
+ basename = path.basename(component);
62
61
  logger(`Rendering component: ${basename} with props: ${JSON.stringify(props)}`);
63
62
 
64
63
  // lad component
@@ -71,18 +70,9 @@ const server = http.createServer(async (req, res) => {
71
70
  const { body, head } = render(compiledComponent, { props });
72
71
  logger(`Component rendered, content: «${body}», head: «${head}»`);
73
72
 
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
73
  res.writeHead(200, { 'Content-Type': 'application/json' });
83
74
  res.end(JSON.stringify({
84
75
  html: body,
85
- css: dummyCss,
86
76
  head: head
87
77
  }));
88
78
 
@@ -91,7 +81,10 @@ const server = http.createServer(async (req, res) => {
91
81
  logger(`Render error: ${err}`);
92
82
  logger(`body => «${request_body}»`);
93
83
  res.writeHead(500, { 'Content-Type': 'application/json' });
94
- res.end(JSON.stringify({ error: 'SSR render failed', details: err.message }));
84
+ res.end(JSON.stringify({
85
+ html: componentRenderError(basename, err),
86
+ head: ''
87
+ }));
95
88
  }
96
89
  });
97
90
  return;
@@ -99,7 +92,8 @@ const server = http.createServer(async (req, res) => {
99
92
 
100
93
  // Fallback 404
101
94
  res.writeHead(404, { 'Content-Type': 'application/json' });
102
- res.end(JSON.stringify({ error: 'Not found' }));
95
+ res.end(JSON.stringify({
96
+ error: 'Not found' }));
103
97
  });
104
98
 
105
99
  // LOGGING
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@csedl/svelte-on-rails",
3
- "version": "12.0.0",
3
+ "version": "12.0.1",
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",
@@ -1,6 +1,7 @@
1
1
  import {mount, hydrate} from "svelte";
2
2
  import {debugLog} from "../logger.js";
3
- import { SvelteOnRails } from "../config.js";
3
+ import {SvelteOnRails} from "../config.js";
4
+ import {componentRenderError} from "../utils.js";
4
5
 
5
6
  // Store for tracking initialized Svelte component instances
6
7
  const svelteInstances = new WeakMap();
@@ -52,5 +53,10 @@ export async function initializeSvelteComponent(element) {
52
53
  } catch (e) {
53
54
  console.error(`[svelte-on-rails] Failed to ${action} ${componentKey}:`, e);
54
55
  element.setAttribute("data-svelte-status", "error");
56
+
57
+ element.innerHTML = componentRenderError(componentKey, e);
58
+
55
59
  }
56
- }
60
+ }
61
+
62
+
package/src/ssr/render.js CHANGED
@@ -2,6 +2,7 @@
2
2
  import { render } from 'svelte/server';
3
3
  import { readPropsFromStdin } from "./readStdin.js";
4
4
  import { loadComponentModule } from "./loadComponent.js";
5
+ import { componentRenderError } from "../utils.js";
5
6
 
6
7
  const compiledComponentPath = process.argv[2];
7
8
 
@@ -17,21 +18,25 @@ const compiledComponentPath = process.argv[2];
17
18
  console.log(`[svelte-on-rails:debug] props read: «${JSON.stringify(props)}»`);
18
19
 
19
20
  try {
20
- // Svelte 5+ SSR rendering (runes-compatible; signals omitted on server for perf)
21
- // Returns { body: string, head: string } — no 'html' or 'css' props
22
21
  const { body, head } = render(compiledComponent, { props });
23
22
 
24
23
  const res = {
25
24
  status: 'SUCCESS',
26
- html: body, // Use 'body' as the main HTML content (replaces old 'html')
27
- head: head || '', // Optional: Include <head> content (styles, meta, etc.)
28
- // Add bodyAttributes or other result props if needed in future
25
+ html: body,
26
+ head: head || '',
29
27
  };
30
28
  console.log(`<time>${performance.now()}`);
31
29
  console.log('[svelte-on-rails:successful-json-response]' + JSON.stringify(res));
32
30
  } catch (error) {
33
- console.error('[svelte-on-rails:debug] Error rendering component:', error);
34
- process.exit(1);
31
+
32
+ const res = {
33
+ status: 'SUCCESS',
34
+ html: componentRenderError(compiledComponentPath, error),
35
+ head: '',
36
+ };
37
+
38
+ console.log(`<time>${performance.now()}`);
39
+ console.log('[svelte-on-rails:successful-json-response]' + JSON.stringify(res));
35
40
  }
36
41
  })();
37
42
 
package/src/utils.js ADDED
@@ -0,0 +1,22 @@
1
+ export function componentRenderError(component, error) {
2
+ return (`
3
+ <div style="
4
+ padding: 1.5rem;
5
+ margin: 1rem 0;
6
+ border: 2px solid #ef4444;
7
+ background: #fef2f2;
8
+ color: #991b1b;
9
+ border-radius: 0.5rem;
10
+ font-family: system-ui, sans-serif;
11
+ ">
12
+ <strong style="font-size: 1.2em;">Component failed to render</strong>
13
+ <p style="margin: 0.75rem 0 0;">
14
+ <code>${component}</code><br>
15
+ ${error.message || 'Unknown rendering error'}
16
+ </p>
17
+ <small style="color: #7f1d1d; opacity: 0.8;">
18
+ Check browser console for full details. (Dev mode only?)
19
+ </small>
20
+ </div>
21
+ `)
22
+ }