@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.
- package/bin/svelte-ssr-server.js +44 -34
- package/package.json +1 -1
- package/src/ssr/render.js +18 -18
- package/src/utils.js +1 -1
- package/src/ssr/loadComponent.js +0 -25
package/bin/svelte-ssr-server.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
|
|
2
1
|
import http from 'node:http';
|
|
3
|
-
import fs
|
|
2
|
+
import fs from 'node:fs';
|
|
4
3
|
import path from 'node:path';
|
|
5
|
-
import {
|
|
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, {
|
|
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
|
-
|
|
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
|
-
|
|
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}
|
|
60
|
+
logger(`Rendering component: ${basename}...`, false, errorLog);
|
|
62
61
|
|
|
63
|
-
//
|
|
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 =
|
|
66
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
82
|
-
logger(`
|
|
83
|
-
res.writeHead(500, {
|
|
86
|
+
|
|
87
|
+
logger(`Render error: ${err}`, true, errorLog);
|
|
88
|
+
res.writeHead(500, {'Content-Type': 'application/json'});
|
|
84
89
|
res.end(JSON.stringify({
|
|
85
|
-
|
|
86
|
-
|
|
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, {
|
|
99
|
+
res.writeHead(404, {'Content-Type': 'application/json'});
|
|
95
100
|
res.end(JSON.stringify({
|
|
96
|
-
|
|
101
|
+
status: 'FAILED'
|
|
102
|
+
}));
|
|
97
103
|
});
|
|
98
104
|
|
|
99
105
|
// LOGGING
|
|
100
|
-
function logger(msg,
|
|
101
|
-
|
|
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
package/src/ssr/render.js
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
18
|
-
|
|
18
|
+
const props = await readPropsFromStdin();
|
|
19
|
+
console.log(`Props read: «${JSON.stringify(props)}»`);
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
const {
|
|
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
|
-
|
|
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: '
|
|
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="
|
|
7
|
+
<div class="client-side-svelte-render-error"
|
|
8
8
|
style="
|
|
9
9
|
padding: 1.5rem;
|
|
10
10
|
margin: 1rem 0;
|
package/src/ssr/loadComponent.js
DELETED
|
@@ -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
|
-
}
|