@csedl/svelte-on-rails 12.2.0 → 12.3.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.
@@ -1,10 +1,10 @@
1
-
2
1
  import http from 'node:http';
3
- import fs from 'node:fs';
4
- import path from 'node:path';
5
- import { render } from 'svelte/server';
6
- import { loadComponentModule } from "../src/ssr/loadComponent.js";
7
- import { componentRenderError} from "../src/utils.js";
2
+ import fs from 'node:fs';
3
+ import path, {dirname, resolve} from 'node:path';
4
+ import {render} from 'svelte/server';
5
+ import {loadComponentModule} from "../src/ssr/loadComponent.js";
6
+ import {componentRenderError} from "../src/utils.js";
7
+ import {fileURLToPath} from "node:url";
8
8
 
9
9
  const SOCKET_PATH = process.argv[2];
10
10
  const PORT = (/^\d+$/.test(SOCKET_PATH) ? SOCKET_PATH : null);
@@ -24,7 +24,7 @@ if (LOGFILE) {
24
24
  // Clean up old socket file
25
25
  if (SOCKET_PATH.startsWith('/') && fs.existsSync(SOCKET_PATH)) {
26
26
  fs.unlinkSync(SOCKET_PATH);
27
- logger(`Cleaned old socket: ${SOCKET_PATH}`);
27
+ logger(`Cleaned old socket: ${SOCKET_PATH}`, false);
28
28
  }
29
29
 
30
30
  const server = http.createServer(async (req, res) => {
@@ -34,7 +34,7 @@ const server = http.createServer(async (req, res) => {
34
34
  // Health check / ping
35
35
 
36
36
  if (req.method === 'GET' && (req.url === '/ping' || req.url === '/health')) {
37
- res.writeHead(200, { 'Content-Type': 'application/json' });
37
+ res.writeHead(200, {'Content-Type': 'application/json'});
38
38
  res.end(JSON.stringify({
39
39
  status: 'alive',
40
40
  uptime: process.uptime(),
@@ -48,42 +48,52 @@ const server = http.createServer(async (req, res) => {
48
48
 
49
49
  if (req.method === 'POST' && req.url === '/render') {
50
50
  let request_body = '';
51
- req.on('data', chunk => { request_body += chunk; });
51
+ let errorLog = []
52
+ req.on('data', chunk => {
53
+ request_body += chunk;
54
+ });
52
55
  req.on('end', async () => {
53
56
  let basename = 'unknown';
54
57
  try {
55
58
 
56
- // parsing request-body
59
+ logger(`Parsing request_body...`, false, errorLog);
60
+ const {component, props = {}} = JSON.parse(request_body);
57
61
 
58
- logger(`Parsing request_body...`);
59
- const { component, props = {} } = JSON.parse(request_body);
60
62
  basename = path.basename(component);
61
- logger(`Rendering component: ${basename} with props: ${JSON.stringify(props)}`);
63
+ logger(`Rendering component: ${basename}...`, false, errorLog);
62
64
 
63
- // lad component
65
+ // Import the module
66
+ logger(`Start import module: ${component}`, false, errorLog);
67
+ const module = await import(`file://${component}`);
68
+ logger(`Imported module typeof: ${typeof module}`, false, errorLog);
64
69
 
65
- const compiledComponent = await loadComponentModule(component);
66
- logger(`Component loaded: «${compiledComponent}»`);
70
+ const compiledComponent = module.default;
71
+ if (!compiledComponent) {
72
+ throw new Error(`Module at ${component} does not export a default component`);
73
+ }
67
74
 
68
- // render
75
+ logger(`rendering...`, false, errorLog);
76
+ const {body, head} = render(compiledComponent, {props});
77
+ logger(`Component rendered, content: «${body}», head: «${head}»`, false, errorLog);
69
78
 
70
- const { body, head } = render(compiledComponent, { props });
71
- logger(`Component rendered, content: «${body}», head: «${head}»`);
72
-
73
- res.writeHead(200, { 'Content-Type': 'application/json' });
79
+ res.writeHead(200, {'Content-Type': 'application/json'});
74
80
  res.end(JSON.stringify({
81
+ status: 'SUCCESS',
75
82
  html: body,
76
83
  head: head
77
84
  }));
78
85
 
79
- logger(`Successfully rendered: ${basename}`);
86
+ logger(`Successfully rendered: ${basename}`, false, errorLog);
87
+
80
88
  } catch (err) {
81
- logger(`Render error: ${err}`);
82
- logger(`body => «${request_body}»`);
83
- res.writeHead(500, { 'Content-Type': 'application/json' });
89
+
90
+ logger(`Render error: ${err}`, true, errorLog);
91
+ res.writeHead(500, {'Content-Type': 'application/json'});
84
92
  res.end(JSON.stringify({
93
+ status: 'FAILED',
85
94
  html: componentRenderError(basename, err, true),
86
- head: ''
95
+ head: '',
96
+ errorLog: errorLog
87
97
  }));
88
98
  }
89
99
  });
@@ -91,18 +101,23 @@ const server = http.createServer(async (req, res) => {
91
101
  }
92
102
 
93
103
  // Fallback 404
94
- res.writeHead(404, { 'Content-Type': 'application/json' });
104
+ res.writeHead(404, {'Content-Type': 'application/json'});
95
105
  res.end(JSON.stringify({
96
- error: 'Not found' }));
106
+ status: 'FAILED'
107
+ }));
97
108
  });
98
109
 
99
110
  // LOGGING
100
- function logger(msg, error = false) {
101
- if (error) {
111
+ function logger(msg, isError = false, errorLog = []) {
112
+
113
+ if (isError) {
114
+ errorLog.push(`ERROR => ${msg}`);
102
115
  console.error(msg);
103
116
  } else {
117
+ errorLog.push(msg);
104
118
  console.log(msg);
105
- };
119
+ }
120
+
106
121
  if (LOGFILE) {
107
122
  fs.appendFileSync(LOGFILE, `${new Date().toISOString()} ${msg}\n`);
108
123
  }
@@ -113,19 +128,19 @@ function logger(msg, error = false) {
113
128
  if (PORT) {
114
129
  // TCP mode (e.g. for debugging or non-Unix environments)
115
130
  server.listen(PORT, '127.0.0.1', () => {
116
- logger(`Svelte SSR listening on http://127.0.0.1:${PORT}`);
131
+ logger(`Svelte SSR listening on http://127.0.0.1:${PORT}`, false);
117
132
  });
118
133
  } else {
119
134
  // Preferred: Unix socket
120
135
  server.listen(SOCKET_PATH, () => {
121
136
  fs.chmodSync(SOCKET_PATH, 0o600); // restrict access
122
- logger(`Svelte SSR listening on unix socket: ${SOCKET_PATH}`);
137
+ logger(`Svelte SSR listening on unix socket: ${SOCKET_PATH}`, false);
123
138
  });
124
139
  }
125
140
 
126
141
  // Graceful shutdown
127
142
  process.on('SIGINT', () => {
128
- logger('Shutting down SSR server...');
143
+ logger('Shutting down SSR server...', false);
129
144
  server.close(() => {
130
145
  if (SOCKET_PATH.startsWith('/') && fs.existsSync(SOCKET_PATH)) {
131
146
  fs.unlinkSync(SOCKET_PATH);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@csedl/svelte-on-rails",
3
- "version": "12.2.0",
3
+ "version": "12.3.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",
package/src/ssr/render.js CHANGED
@@ -1,43 +1,44 @@
1
-
2
- import { render } from 'svelte/server';
3
- import { readPropsFromStdin } from "./readStdin.js";
4
- import { loadComponentModule } from "./loadComponent.js";
5
- import { componentRenderError } from "../utils.js";
1
+ import {render} from 'svelte/server';
2
+ import {readPropsFromStdin} from "./readStdin.js";
3
+ import {loadComponentModule} from "./loadComponent.js";
4
+ import {componentRenderError} from "../utils.js";
6
5
 
7
6
  const compiledComponentPath = process.argv[2];
8
7
 
9
8
 
10
9
  (async () => {
11
- console.log(`${performance.now()}<time>`);
12
- console.log(`[SOR] awaiting load component => «${compiledComponentPath}»`);
13
- const compiledComponent = await loadComponentModule(compiledComponentPath);
14
10
 
15
- console.log(`[SOR] Component loaded: «${compiledComponent}»`);
11
+ try {
12
+ console.log(`Awaiting load component: «${compiledComponentPath}»`);
13
+ const compiledComponent = await import(`file://${compiledComponentPath}`);
14
+
15
+ console.log(`Component loaded: «${compiledComponent}»`);
16
16
 
17
- const props = await readPropsFromStdin();
18
- console.log(`[SOR] props read: «${JSON.stringify(props)}»`);
17
+ const props = await readPropsFromStdin();
18
+ console.log(`Props read: «${JSON.stringify(props)}»`);
19
19
 
20
- try {
21
- const { body, head } = render(compiledComponent, { props });
20
+
21
+ const {body, head} = render(compiledComponent, {props});
22
22
 
23
23
  const res = {
24
24
  status: 'SUCCESS',
25
25
  html: body,
26
26
  head: head || '',
27
27
  };
28
- console.log(`<time>${performance.now()}`);
28
+
29
29
  console.log('$$ResponseSeparator$$' + JSON.stringify(res));
30
30
  } catch (error) {
31
+ console.error(`ERROR: ${error.message}`)
31
32
 
32
33
  const res = {
33
- status: 'SUCCESS',
34
+ status: 'FAILED',
34
35
  html: componentRenderError(compiledComponentPath, error, true),
35
36
  head: '',
36
37
  };
37
38
 
38
- console.log(`<time>${performance.now()}`);
39
39
  console.log('$$ResponseSeparator$$' + JSON.stringify(res));
40
40
  }
41
+
41
42
  })();
42
43
 
43
44
 
package/src/utils.js CHANGED
@@ -4,7 +4,7 @@ export function componentRenderError(component, error, ssr = false) {
4
4
  const ssrHint = 'This is Server Side rendered. When Hydrated, you will see a more detailed error message.'
5
5
 
6
6
  return (`
7
- <div class="svelte-on-rails-component-error${ssr ? '-server-side' : ''}"
7
+ <div class="svelte-on-rails-render-error ${ssr ? 'server-side-error' : 'client-side-error'}"
8
8
  style="
9
9
  padding: 1.5rem;
10
10
  margin: 1rem 0;
@@ -14,7 +14,7 @@ export function componentRenderError(component, error, ssr = false) {
14
14
  border-radius: 0.5rem;
15
15
  font-family: system-ui, sans-serif;
16
16
  ">
17
- <strong style="font-size: 1.2em;">Component failed to render${ssr ? ' server-side' : ''}</strong>
17
+ <strong style="font-size: 1.2em;">Component failed to render${ssr ? ' server-side' : ' client-side'}</strong>
18
18
 
19
19
  <p class="error-message"
20
20
  style="margin: 0.4rem 0 0.4rem;"