@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.
- package/bin/svelte-ssr-server.js +49 -34
- package/package.json +1 -1
- package/src/ssr/render.js +17 -16
- package/src/utils.js +2 -2
package/bin/svelte-ssr-server.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
2
1
|
import http from 'node:http';
|
|
3
|
-
import fs
|
|
4
|
-
import path from 'node:path';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
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, {
|
|
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
|
-
|
|
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
|
-
|
|
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}
|
|
63
|
+
logger(`Rendering component: ${basename}...`, false, errorLog);
|
|
62
64
|
|
|
63
|
-
//
|
|
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 =
|
|
66
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
82
|
-
logger(`
|
|
83
|
-
res.writeHead(500, {
|
|
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, {
|
|
104
|
+
res.writeHead(404, {'Content-Type': 'application/json'});
|
|
95
105
|
res.end(JSON.stringify({
|
|
96
|
-
|
|
106
|
+
status: 'FAILED'
|
|
107
|
+
}));
|
|
97
108
|
});
|
|
98
109
|
|
|
99
110
|
// LOGGING
|
|
100
|
-
function logger(msg,
|
|
101
|
-
|
|
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
package/src/ssr/render.js
CHANGED
|
@@ -1,43 +1,44 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
18
|
-
|
|
17
|
+
const props = await readPropsFromStdin();
|
|
18
|
+
console.log(`Props read: «${JSON.stringify(props)}»`);
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
const {
|
|
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
|
-
|
|
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: '
|
|
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-
|
|
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;"
|