-
-
Notifications
You must be signed in to change notification settings - Fork 263
/
Copy pathdev-server-plugin.ts
109 lines (101 loc) · 3 KB
/
dev-server-plugin.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// SSR dev server, middleware and error page source modified from
// https://github.com/solidjs/solid-start/blob/main/packages/start/dev/server.js
import { Connect, Plugin, ViteDevServer } from 'vite';
import * as path from 'path';
import * as fs from 'fs';
interface ServerOptions {
index?: string;
entryServer?: string;
}
export function devServerPlugin(options: ServerOptions): Plugin {
const entryServer = options.entryServer || 'src/main.server.ts';
const index = options.index || 'index.html';
return {
name: 'analogjs-dev-ssr-plugin',
config() {
return {
resolve: {
alias: {
'~analog/entry-server': entryServer,
},
},
};
},
configureServer(viteServer) {
return async () => {
remove_html_middlewares(viteServer.middlewares);
viteServer.middlewares.use(async (req, res) => {
let template = fs.readFileSync(
path.resolve(viteServer.config.root, index),
'utf-8'
);
template = await viteServer.transformIndexHtml(
req.originalUrl as string,
template
);
try {
const entryServer = (
await viteServer.ssrLoadModule('~analog/entry-server')
)['default'];
const result = await entryServer(req.originalUrl, template);
res.setHeader('Content-Type', 'text/html');
res.end(result);
} catch (e) {
viteServer && viteServer.ssrFixStacktrace(e as Error);
res.statusCode = 500;
res.end(`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Error</title>
<script type="module">
import { ErrorOverlay } from '/@vite/client'
document.body.appendChild(new ErrorOverlay(${JSON.stringify(
prepareError(req, e)
).replace(/</g, '\\u003c')}))
</script>
</head>
<body>
</body>
</html>
`);
}
});
};
},
};
}
/**
* Removes Vite internal middleware
*
* @param server
*/
function remove_html_middlewares(server: ViteDevServer['middlewares']) {
const html_middlewares = [
'viteIndexHtmlMiddleware',
'vite404Middleware',
'viteSpaFallbackMiddleware',
];
for (let i = server.stack.length - 1; i > 0; i--) {
// @ts-ignore
if (html_middlewares.includes(server.stack[i].handle.name)) {
server.stack.splice(i, 1);
}
}
}
/**
* Formats error for SSR message in error overlay
* @param req
* @param error
* @returns
*/
function prepareError(req: Connect.IncomingMessage, error: unknown) {
const e = error as Error;
return {
message: `An error occured while server rendering ${req.url}:\n\n\t${
typeof e === 'string' ? e : e.message
} `,
stack: typeof e === 'string' ? '' : e.stack,
};
}