forked from sveltejs/kit
/
index.js
156 lines (132 loc) · 4.13 KB
/
index.js
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import fs from 'fs';
import http from 'http';
import https from 'https';
import { join, resolve } from 'path';
import sirv from 'sirv';
import { pathToFileURL } from 'url';
import { getRequest, setResponse } from '../../node.js';
import { __fetch_polyfill } from '../../install-fetch.js';
import { SVELTE_KIT, SVELTE_KIT_ASSETS } from '../constants.js';
/** @param {string} dir */
const mutable = (dir) =>
sirv(dir, {
etag: true,
maxAge: 0
});
/**
* @param {{
* port: number;
* host?: string;
* config: import('types/config').ValidatedConfig;
* https?: boolean;
* cwd?: string;
* }} opts
*/
export async function preview({
port,
host,
config,
https: use_https = false,
cwd = process.cwd()
}) {
__fetch_polyfill();
const app_file = resolve(cwd, `${SVELTE_KIT}/output/server/app.js`);
const manifest_file = resolve(cwd, `${SVELTE_KIT}/output/server/manifest.js`);
/** @type {import('types/internal').AppModule} */
const { App, override } = await import(pathToFileURL(app_file).href);
const { manifest } = await import(pathToFileURL(manifest_file).href);
/** @type {import('sirv').RequestHandler} */
const static_handler = fs.existsSync(config.kit.files.assets)
? mutable(config.kit.files.assets)
: (_req, _res, next) => {
if (!next) throw new Error('No next() handler is available');
return next();
};
const assets_handler = sirv(resolve(cwd, `${SVELTE_KIT}/output/client`), {
maxAge: 31536000,
immutable: true
});
const has_asset_path = !!config.kit.paths.assets;
override({
paths: {
base: config.kit.paths.base,
assets: has_asset_path ? SVELTE_KIT_ASSETS : config.kit.paths.base
},
prerendering: false,
protocol: use_https ? 'https' : 'http',
read: (file) => fs.readFileSync(join(config.kit.files.assets, file))
});
const app = new App(manifest);
/** @type {import('vite').UserConfig} */
const vite_config = (config.kit.vite && (await config.kit.vite())) || {};
const server = await get_server(use_https, vite_config, (req, res) => {
if (req.url == null) {
throw new Error('Invalid request url');
}
const initial_url = req.url;
const render_handler = async () => {
if (initial_url.startsWith(config.kit.paths.base)) {
const protocol = use_https ? 'https' : 'http';
const host = req.headers['host'];
let request;
try {
req.url = initial_url;
request = await getRequest(`${protocol}://${host}`, req);
} catch (/** @type {any} */ err) {
res.statusCode = err.status || 400;
return res.end(err.reason || 'Invalid request body');
}
setResponse(res, await app.render(request));
} else {
res.statusCode = 404;
res.end('Not found');
}
};
if (has_asset_path) {
if (initial_url.startsWith(SVELTE_KIT_ASSETS)) {
// custom assets path
req.url = initial_url.slice(SVELTE_KIT_ASSETS.length);
assets_handler(req, res, () => {
static_handler(req, res, render_handler);
});
} else {
render_handler();
}
} else {
if (initial_url.startsWith(config.kit.paths.base)) {
req.url = initial_url.slice(config.kit.paths.base.length);
}
assets_handler(req, res, () => {
static_handler(req, res, render_handler);
});
}
});
await server.listen(port, host || '0.0.0.0');
return Promise.resolve(server);
}
/**
* @param {boolean} use_https
* @param {import('vite').UserConfig} user_config
* @param {(req: http.IncomingMessage, res: http.ServerResponse) => void} handler
* @returns {Promise<import('net').Server>}
*/
async function get_server(use_https, user_config, handler) {
/** @type {https.ServerOptions} */
const https_options = {};
if (use_https) {
const secure_opts = user_config.server
? /** @type {import('tls').SecureContextOptions} */ (user_config.server.https)
: {};
if (secure_opts.key && secure_opts.cert) {
https_options.key = secure_opts.key.toString();
https_options.cert = secure_opts.cert.toString();
} else {
https_options.key = https_options.cert = (await import('./cert')).createCertificate();
}
}
return Promise.resolve(
use_https
? https.createServer(/** @type {https.ServerOptions} */ (https_options), handler)
: http.createServer(handler)
);
}