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