@sveltejs/kit 1.0.0-next.286 → 1.0.0-next.289

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,881 +1,170 @@
1
- import { b as SVELTE_KIT, m as mkdirp, h as rimraf, i as copy, $, j as logger } from '../cli.js';
2
- import { readFileSync, writeFileSync } from 'fs';
3
- import { resolve as resolve$1, join, dirname } from 'path';
4
- import { pathToFileURL, URL } from 'url';
5
- import { __fetch_polyfill } from '../install-fetch.js';
6
- import { g as generate_manifest } from './index4.js';
7
- import 'sade';
8
- import 'child_process';
9
- import 'net';
10
- import 'os';
1
+ import fs__default from 'fs';
2
+ import http from 'http';
3
+ import https from 'https';
4
+ import { resolve, join } from 'path';
5
+ import { s as sirv } from './build.js';
6
+ import { pathToFileURL } from 'url';
7
+ import { getRequest, setResponse } from '../node.js';
8
+ import { installFetch } from '../install-fetch.js';
9
+ import { b as SVELTE_KIT, S as SVELTE_KIT_ASSETS } from '../cli.js';
10
+ import 'querystring';
11
+ import 'stream';
11
12
  import 'node:http';
12
13
  import 'node:https';
13
14
  import 'node:zlib';
14
15
  import 'node:stream';
15
16
  import 'node:util';
16
17
  import 'node:url';
17
- import './misc.js';
18
-
19
- const absolute = /^([a-z]+:)?\/?\//;
20
- const scheme = /^[a-z]+:/;
21
-
22
- /**
23
- * @param {string} base
24
- * @param {string} path
25
- */
26
- function resolve(base, path) {
27
- if (scheme.test(path)) return path;
28
-
29
- const base_match = absolute.exec(base);
30
- const path_match = absolute.exec(path);
31
-
32
- if (!base_match) {
33
- throw new Error(`bad base path: "${base}"`);
34
- }
35
-
36
- const baseparts = path_match ? [] : base.slice(base_match[0].length).split('/');
37
- const pathparts = path_match ? path.slice(path_match[0].length).split('/') : path.split('/');
38
-
39
- baseparts.pop();
40
-
41
- for (let i = 0; i < pathparts.length; i += 1) {
42
- const part = pathparts[i];
43
- if (part === '.') continue;
44
- else if (part === '..') baseparts.pop();
45
- else baseparts.push(part);
46
- }
47
-
48
- const prefix = (path_match && path_match[0]) || (base_match && base_match[0]) || '';
49
-
50
- return `${prefix}${baseparts.join('/')}`;
51
- }
52
-
53
- /** @param {string} path */
54
- function is_root_relative(path) {
55
- return path[0] === '/' && path[1] !== '/';
56
- }
57
-
58
- /**
59
- * @param {string} path
60
- * @param {import('types').TrailingSlash} trailing_slash
61
- */
62
- function normalize_path(path, trailing_slash) {
63
- if (path === '/' || trailing_slash === 'ignore') return path;
64
-
65
- if (trailing_slash === 'never') {
66
- return path.endsWith('/') ? path.slice(0, -1) : path;
67
- } else if (trailing_slash === 'always' && /\/[^./]+$/.test(path)) {
68
- return path + '/';
69
- }
70
-
71
- return path;
72
- }
73
-
74
- /** @typedef {{
75
- * fn: () => Promise<any>,
76
- * fulfil: (value: any) => void,
77
- * reject: (error: Error) => void
78
- * }} Task */
79
-
80
- /** @param {number} concurrency */
81
- function queue(concurrency) {
82
- /** @type {Task[]} */
83
- const tasks = [];
84
-
85
- let current = 0;
86
-
87
- /** @type {(value?: any) => void} */
88
- let fulfil;
89
-
90
- /** @type {(error: Error) => void} */
91
- let reject;
92
-
93
- let closed = false;
94
-
95
- const done = new Promise((f, r) => {
96
- fulfil = f;
97
- reject = r;
98
- });
99
-
100
- done.catch(() => {
101
- // this is necessary in case a catch handler is never added
102
- // to the done promise by the user
103
- });
104
-
105
- function dequeue() {
106
- if (current < concurrency) {
107
- const task = tasks.shift();
108
-
109
- if (task) {
110
- current += 1;
111
- const promise = Promise.resolve(task.fn());
112
-
113
- promise
114
- .then(task.fulfil, (err) => {
115
- task.reject(err);
116
- reject(err);
117
- })
118
- .then(() => {
119
- current -= 1;
120
- dequeue();
121
- });
122
- } else if (current === 0) {
123
- closed = true;
124
- fulfil();
125
- }
126
- }
127
- }
128
-
129
- return {
130
- /** @param {() => any} fn */
131
- add: (fn) => {
132
- if (closed) throw new Error('Cannot add tasks to a queue that has ended');
133
-
134
- const promise = new Promise((fulfil, reject) => {
135
- tasks.push({ fn, fulfil, reject });
136
- });
137
-
138
- dequeue();
139
- return promise;
140
- },
141
-
142
- done: () => {
143
- if (current === 0) {
144
- closed = true;
145
- fulfil();
146
- }
147
-
148
- return done;
149
- }
150
- };
151
- }
152
-
153
- const DOCTYPE = 'DOCTYPE';
154
- const CDATA_OPEN = '[CDATA[';
155
- const CDATA_CLOSE = ']]>';
156
- const COMMENT_OPEN = '--';
157
- const COMMENT_CLOSE = '-->';
158
-
159
- const TAG_OPEN = /[a-zA-Z]/;
160
- const TAG_CHAR = /[a-zA-Z0-9]/;
161
- const ATTRIBUTE_NAME = /[^\t\n\f />"'=]/;
162
-
163
- const WHITESPACE = /[\s\n\r]/;
164
-
165
- /** @param {string} html */
166
- function crawl(html) {
167
- /** @type {string[]} */
168
- const hrefs = [];
169
-
170
- let i = 0;
171
- main: while (i < html.length) {
172
- const char = html[i];
173
-
174
- if (char === '<') {
175
- if (html[i + 1] === '!') {
176
- i += 2;
177
-
178
- if (html.substr(i, DOCTYPE.length).toUpperCase() === DOCTYPE) {
179
- i += DOCTYPE.length;
180
- while (i < html.length) {
181
- if (html[i++] === '>') {
182
- continue main;
183
- }
184
- }
185
- }
186
-
187
- // skip cdata
188
- if (html.substr(i, CDATA_OPEN.length) === CDATA_OPEN) {
189
- i += CDATA_OPEN.length;
190
- while (i < html.length) {
191
- if (html.substr(i, CDATA_CLOSE.length) === CDATA_CLOSE) {
192
- i += CDATA_CLOSE.length;
193
- continue main;
194
- }
195
-
196
- i += 1;
197
- }
198
- }
199
-
200
- // skip comments
201
- if (html.substr(i, COMMENT_OPEN.length) === COMMENT_OPEN) {
202
- i += COMMENT_OPEN.length;
203
- while (i < html.length) {
204
- if (html.substr(i, COMMENT_CLOSE.length) === COMMENT_CLOSE) {
205
- i += COMMENT_CLOSE.length;
206
- continue main;
207
- }
208
-
209
- i += 1;
210
- }
211
- }
212
- }
213
-
214
- // parse opening tags
215
- const start = ++i;
216
- if (TAG_OPEN.test(html[start])) {
217
- while (i < html.length) {
218
- if (!TAG_CHAR.test(html[i])) {
219
- break;
220
- }
221
-
222
- i += 1;
223
- }
224
-
225
- const tag = html.slice(start, i).toUpperCase();
226
-
227
- if (tag === 'SCRIPT' || tag === 'STYLE') {
228
- while (i < html.length) {
229
- if (
230
- html[i] === '<' &&
231
- html[i + 1] === '/' &&
232
- html.substr(i + 2, tag.length).toUpperCase() === tag
233
- ) {
234
- continue main;
235
- }
236
-
237
- i += 1;
238
- }
239
- }
240
-
241
- let href = '';
242
-
243
- while (i < html.length) {
244
- const start = i;
245
-
246
- const char = html[start];
247
- if (char === '>') break;
248
-
249
- if (ATTRIBUTE_NAME.test(char)) {
250
- i += 1;
251
-
252
- while (i < html.length) {
253
- if (!ATTRIBUTE_NAME.test(html[i])) {
254
- break;
255
- }
256
-
257
- i += 1;
258
- }
259
-
260
- const name = html.slice(start, i).toLowerCase();
261
-
262
- while (WHITESPACE.test(html[i])) i += 1;
263
-
264
- if (html[i] === '=') {
265
- i += 1;
266
- while (WHITESPACE.test(html[i])) i += 1;
267
-
268
- let value;
269
-
270
- if (html[i] === "'" || html[i] === '"') {
271
- const quote = html[i++];
272
-
273
- const start = i;
274
- let escaped = false;
275
-
276
- while (i < html.length) {
277
- if (!escaped) {
278
- const char = html[i];
279
-
280
- if (html[i] === quote) {
281
- break;
282
- }
283
-
284
- if (char === '\\') {
285
- escaped = true;
286
- }
287
- }
288
-
289
- i += 1;
290
- }
291
-
292
- value = html.slice(start, i);
293
- } else {
294
- const start = i;
295
- while (html[i] !== '>' && !WHITESPACE.test(html[i])) i += 1;
296
- value = html.slice(start, i);
297
-
298
- i -= 1;
299
- }
300
-
301
- if (name === 'href') {
302
- href = value;
303
- } else if (name === 'src') {
304
- hrefs.push(value);
305
- } else if (name === 'srcset') {
306
- const candidates = [];
307
- let insideURL = true;
308
- value = value.trim();
309
- for (let i = 0; i < value.length; i++) {
310
- if (value[i] === ',' && (!insideURL || (insideURL && value[i + 1] === ' '))) {
311
- candidates.push(value.slice(0, i));
312
- value = value.substring(i + 1).trim();
313
- i = 0;
314
- insideURL = true;
315
- } else if (value[i] === ' ') {
316
- insideURL = false;
317
- }
318
- }
319
- candidates.push(value);
320
- for (const candidate of candidates) {
321
- const src = candidate.split(WHITESPACE)[0];
322
- hrefs.push(src);
323
- }
324
- }
325
- } else {
326
- i -= 1;
327
- }
328
- }
329
-
330
- i += 1;
331
- }
332
-
333
- if (href) {
334
- hrefs.push(href);
335
- }
336
- }
337
- }
338
-
339
- i += 1;
340
- }
341
-
342
- return hrefs;
343
- }
344
-
345
- // dict from https://github.com/yahoo/serialize-javascript/blob/183c18a776e4635a379fdc620f81771f219832bb/index.js#L25
346
- /** @type {Record<string, string>} */
347
- const escape_json_in_html_dict = {
348
- '<': '\\u003C',
349
- '>': '\\u003E',
350
- '/': '\\u002F',
351
- '\u2028': '\\u2028',
352
- '\u2029': '\\u2029'
353
- };
354
-
355
- new RegExp(
356
- `[${Object.keys(escape_json_in_html_dict).join('')}]`,
357
- 'g'
358
- );
359
-
360
- /**
361
- * When inside a double-quoted attribute value, only `&` and `"` hold special meaning.
362
- * @see https://html.spec.whatwg.org/multipage/parsing.html#attribute-value-(double-quoted)-state
363
- * @type {Record<string, string>}
364
- */
365
- const escape_html_attr_dict = {
366
- '&': '&amp;',
367
- '"': '&quot;'
368
- };
369
-
370
- const escape_html_attr_regex = new RegExp(
371
- // special characters
372
- `[${Object.keys(escape_html_attr_dict).join('')}]|` +
373
- // high surrogate without paired low surrogate
374
- '[\\ud800-\\udbff](?![\\udc00-\\udfff])|' +
375
- // a valid surrogate pair, the only match with 2 code units
376
- // we match it so that we can match unpaired low surrogates in the same pass
377
- // TODO: use lookbehind assertions once they are widely supported: (?<![\ud800-udbff])[\udc00-\udfff]
378
- '[\\ud800-\\udbff][\\udc00-\\udfff]|' +
379
- // unpaired low surrogate (see previous match)
380
- '[\\udc00-\\udfff]',
381
- 'g'
382
- );
383
-
384
- /**
385
- * Formats a string to be used as an attribute's value in raw HTML.
386
- *
387
- * It escapes unpaired surrogates (which are allowed in js strings but invalid in HTML), escapes
388
- * characters that are special in attributes, and surrounds the whole string in double-quotes.
389
- *
390
- * @param {string} str
391
- * @returns {string} Escaped string surrounded by double-quotes.
392
- * @example const html = `<tag data-value=${escape_html_attr('value')}>...</tag>`;
393
- */
394
- function escape_html_attr(str) {
395
- const escaped_str = str.replace(escape_html_attr_regex, (match) => {
396
- if (match.length === 2) {
397
- // valid surrogate pair
398
- return match;
399
- }
18
+ import 'net';
19
+ import 'sade';
20
+ import 'child_process';
21
+ import 'os';
400
22
 
401
- return escape_html_attr_dict[match] ?? `&#${match.charCodeAt(0)};`;
23
+ /** @param {string} dir */
24
+ const mutable = (dir) =>
25
+ sirv(dir, {
26
+ etag: true,
27
+ maxAge: 0
402
28
  });
403
29
 
404
- return `"${escaped_str}"`;
405
- }
406
-
407
- /**
408
- * @typedef {import('types').PrerenderErrorHandler} PrerenderErrorHandler
409
- * @typedef {import('types').PrerenderOnErrorValue} OnError
410
- * @typedef {import('types').Logger} Logger
411
- */
412
-
413
- /** @type {(details: Parameters<PrerenderErrorHandler>[0] ) => string} */
414
- function format_error({ status, path, referrer, referenceType }) {
415
- return `${status} ${path}${referrer ? ` (${referenceType} from ${referrer})` : ''}`;
416
- }
417
-
418
- /** @type {(log: Logger, onError: OnError) => PrerenderErrorHandler} */
419
- function normalise_error_handler(log, onError) {
420
- switch (onError) {
421
- case 'continue':
422
- return (details) => {
423
- log.error(format_error(details));
424
- };
425
- case 'fail':
426
- return (details) => {
427
- throw new Error(format_error(details));
428
- };
429
- default:
430
- return onError;
431
- }
432
- }
433
-
434
- const OK = 2;
435
- const REDIRECT = 3;
436
-
437
30
  /**
438
31
  * @param {{
439
- * cwd: string;
440
- * out: string;
441
- * log: Logger;
32
+ * port: number;
33
+ * host?: string;
442
34
  * config: import('types').ValidatedConfig;
443
- * build_data: import('types').BuildData;
444
- * fallback?: string;
445
- * all: boolean; // disregard `export const prerender = true`
35
+ * https?: boolean;
36
+ * cwd?: string;
446
37
  * }} opts
447
38
  */
448
- async function prerender({ cwd, out, log, config, build_data, fallback, all }) {
449
- /** @type {import('types').Prerendered} */
450
- const prerendered = {
451
- pages: new Map(),
452
- assets: new Map(),
453
- redirects: new Map(),
454
- paths: []
455
- };
456
-
457
- if (!config.kit.prerender.enabled && !fallback) {
458
- return prerendered;
459
- }
460
-
461
- __fetch_polyfill();
462
-
463
- const server_root = resolve$1(cwd, `${SVELTE_KIT}/output`);
39
+ async function preview({
40
+ port,
41
+ host,
42
+ config,
43
+ https: use_https = false,
44
+ cwd = process.cwd()
45
+ }) {
46
+ installFetch();
47
+
48
+ const index_file = resolve(cwd, `${SVELTE_KIT}/output/server/index.js`);
49
+ const manifest_file = resolve(cwd, `${SVELTE_KIT}/output/server/manifest.js`);
464
50
 
465
51
  /** @type {import('types').ServerModule} */
466
- const { Server, override } = await import(pathToFileURL(`${server_root}/server/index.js`).href);
467
- const { manifest } = await import(pathToFileURL(`${server_root}/server/manifest.js`).href);
468
-
469
- override({
470
- paths: config.kit.paths,
471
- prerendering: true,
472
- read: (file) => readFileSync(join(config.kit.files.assets, file))
473
- });
474
-
475
- const server = new Server(manifest);
52
+ const { Server, override } = await import(pathToFileURL(index_file).href);
476
53
 
477
- const error = normalise_error_handler(log, config.kit.prerender.onError);
54
+ const { manifest } = await import(pathToFileURL(manifest_file).href);
478
55
 
479
- const files = new Set([
480
- ...build_data.static,
481
- ...build_data.client.chunks.map((chunk) => `${config.kit.appDir}/${chunk.fileName}`),
482
- ...build_data.client.assets.map((chunk) => `${config.kit.appDir}/${chunk.fileName}`)
483
- ]);
56
+ /** @type {import('sirv').RequestHandler} */
57
+ const static_handler = fs__default.existsSync(config.kit.files.assets)
58
+ ? mutable(config.kit.files.assets)
59
+ : (_req, _res, next) => {
60
+ if (!next) throw new Error('No next() handler is available');
61
+ return next();
62
+ };
484
63
 
485
- build_data.static.forEach((file) => {
486
- if (file.endsWith('/index.html')) {
487
- files.add(file.slice(0, -11));
488
- }
64
+ const assets_handler = sirv(resolve(cwd, `${SVELTE_KIT}/output/client`), {
65
+ maxAge: 31536000,
66
+ immutable: true
489
67
  });
490
68
 
491
- const q = queue(config.kit.prerender.concurrency);
492
-
493
- /**
494
- * @param {string} path
495
- * @param {boolean} is_html
496
- */
497
- function output_filename(path, is_html) {
498
- const file = path.slice(config.kit.paths.base.length + 1);
499
-
500
- if (file === '') {
501
- return 'index.html';
502
- }
503
-
504
- if (is_html && !file.endsWith('.html')) {
505
- return file + (config.kit.trailingSlash === 'always' ? 'index.html' : '.html');
506
- }
507
-
508
- return file;
509
- }
510
-
511
- const seen = new Set();
512
- const written = new Set();
513
-
514
- /**
515
- * @param {string | null} referrer
516
- * @param {string} decoded
517
- * @param {string} [encoded]
518
- */
519
- function enqueue(referrer, decoded, encoded) {
520
- if (seen.has(decoded)) return;
521
- seen.add(decoded);
522
-
523
- const file = decoded.slice(config.kit.paths.base.length + 1);
524
- if (files.has(file)) return;
525
-
526
- return q.add(() => visit(decoded, encoded || encodeURI(decoded), referrer));
527
- }
528
-
529
- /**
530
- * @param {string} decoded
531
- * @param {string} encoded
532
- * @param {string?} referrer
533
- */
534
- async function visit(decoded, encoded, referrer) {
535
- if (!decoded.startsWith(config.kit.paths.base)) {
536
- error({ status: 404, path: decoded, referrer, referenceType: 'linked' });
537
- return;
538
- }
539
-
540
- /** @type {Map<string, import('types').PrerenderDependency>} */
541
- const dependencies = new Map();
542
-
543
- const response = await server.respond(new Request(`http://sveltekit-prerender${encoded}`), {
544
- prerender: {
545
- all,
546
- dependencies
547
- }
548
- });
549
-
550
- const text = await response.text();
551
-
552
- save(response, text, decoded, encoded, referrer, 'linked');
553
-
554
- for (const [dependency_path, result] of dependencies) {
555
- // this seems circuitous, but using new URL allows us to not care
556
- // whether dependency_path is encoded or not
557
- const encoded_dependency_path = new URL(dependency_path, 'http://localhost').pathname;
558
- const decoded_dependency_path = decodeURI(encoded_dependency_path);
69
+ const has_asset_path = !!config.kit.paths.assets;
559
70
 
560
- const body = result.body ?? new Uint8Array(await result.response.arrayBuffer());
561
- save(
562
- result.response,
563
- body,
564
- decoded_dependency_path,
565
- encoded_dependency_path,
566
- decoded,
567
- 'fetched'
568
- );
569
- }
570
-
571
- if (config.kit.prerender.crawl && response.headers.get('content-type') === 'text/html') {
572
- for (const href of crawl(text)) {
573
- if (href.startsWith('data:') || href.startsWith('#')) continue;
574
-
575
- const resolved = resolve(encoded, href);
576
- if (!is_root_relative(resolved)) continue;
71
+ override({
72
+ paths: {
73
+ base: config.kit.paths.base,
74
+ assets: has_asset_path ? SVELTE_KIT_ASSETS : config.kit.paths.base
75
+ },
76
+ prerendering: false,
77
+ protocol: use_https ? 'https' : 'http',
78
+ read: (file) => fs__default.readFileSync(join(config.kit.files.assets, file))
79
+ });
577
80
 
578
- const parsed = new URL(resolved, 'http://localhost');
81
+ const server = new Server(manifest);
579
82
 
580
- if (parsed.search) ;
83
+ /** @type {import('vite').UserConfig} */
84
+ const vite_config = (config.kit.vite && (await config.kit.vite())) || {};
581
85
 
582
- const pathname = normalize_path(parsed.pathname, config.kit.trailingSlash);
583
- enqueue(decoded, decodeURI(pathname), pathname);
584
- }
86
+ const http_server = await get_server(use_https, vite_config, (req, res) => {
87
+ if (req.url == null) {
88
+ throw new Error('Invalid request url');
585
89
  }
586
- }
587
-
588
- /**
589
- * @param {Response} response
590
- * @param {string | Uint8Array} body
591
- * @param {string} decoded
592
- * @param {string} encoded
593
- * @param {string | null} referrer
594
- * @param {'linked' | 'fetched'} referenceType
595
- */
596
- function save(response, body, decoded, encoded, referrer, referenceType) {
597
- const response_type = Math.floor(response.status / 100);
598
- const type = /** @type {string} */ (response.headers.get('content-type'));
599
- const is_html = response_type === REDIRECT || type === 'text/html';
600
-
601
- const file = output_filename(decoded, is_html);
602
- const dest = `${out}/${file}`;
603
-
604
- if (written.has(file)) return;
605
- written.add(file);
606
90
 
607
- if (response_type === REDIRECT) {
608
- const location = response.headers.get('location');
91
+ const initial_url = req.url;
609
92
 
610
- if (location) {
611
- mkdirp(dirname(dest));
93
+ const render_handler = async () => {
94
+ if (initial_url.startsWith(config.kit.paths.base)) {
95
+ const protocol = use_https ? 'https' : 'http';
96
+ const host = req.headers['host'];
612
97
 
613
- log.warn(`${response.status} ${decoded} -> ${location}`);
98
+ let request;
614
99
 
615
- writeFileSync(
616
- dest,
617
- `<meta http-equiv="refresh" content=${escape_html_attr(`0;url=${location}`)}>`
618
- );
619
-
620
- let resolved = resolve(encoded, location);
621
- if (is_root_relative(resolved)) {
622
- resolved = normalize_path(resolved, config.kit.trailingSlash);
623
- enqueue(decoded, decodeURI(resolved), resolved);
100
+ try {
101
+ req.url = initial_url;
102
+ request = await getRequest(`${protocol}://${host}`, req);
103
+ } catch (/** @type {any} */ err) {
104
+ res.statusCode = err.status || 400;
105
+ return res.end(err.reason || 'Invalid request body');
624
106
  }
625
107
 
626
- if (!prerendered.redirects.has(decoded)) {
627
- prerendered.redirects.set(decoded, {
628
- status: response.status,
629
- location: resolved
630
- });
631
-
632
- prerendered.paths.push(normalize_path(decoded, 'never'));
633
- }
108
+ setResponse(res, await server.respond(request));
634
109
  } else {
635
- log.warn(`location header missing on redirect received from ${decoded}`);
110
+ res.statusCode = 404;
111
+ res.end('Not found');
636
112
  }
637
-
638
- return;
639
- }
640
-
641
- if (response.status === 200) {
642
- mkdirp(dirname(dest));
643
-
644
- log.info(`${response.status} ${decoded}`);
645
- writeFileSync(dest, body);
646
-
647
- if (is_html) {
648
- prerendered.pages.set(decoded, {
649
- file
113
+ };
114
+
115
+ if (has_asset_path) {
116
+ if (initial_url.startsWith(SVELTE_KIT_ASSETS)) {
117
+ // custom assets path
118
+ req.url = initial_url.slice(SVELTE_KIT_ASSETS.length);
119
+ assets_handler(req, res, () => {
120
+ static_handler(req, res, render_handler);
650
121
  });
651
122
  } else {
652
- prerendered.assets.set(decoded, {
653
- type
654
- });
123
+ render_handler();
655
124
  }
656
-
657
- prerendered.paths.push(normalize_path(decoded, 'never'));
658
- } else if (response_type !== OK) {
659
- error({ status: response.status, path: decoded, referrer, referenceType });
660
- }
661
- }
662
-
663
- if (config.kit.prerender.enabled) {
664
- for (const entry of config.kit.prerender.entries) {
665
- if (entry === '*') {
666
- for (const entry of build_data.entries) {
667
- enqueue(null, normalize_path(config.kit.paths.base + entry, config.kit.trailingSlash)); // TODO can we pre-normalize these?
668
- }
669
- } else {
670
- enqueue(null, normalize_path(config.kit.paths.base + entry, config.kit.trailingSlash));
125
+ } else {
126
+ if (initial_url.startsWith(config.kit.paths.base)) {
127
+ req.url = initial_url.slice(config.kit.paths.base.length);
671
128
  }
129
+ assets_handler(req, res, () => {
130
+ static_handler(req, res, render_handler);
131
+ });
672
132
  }
133
+ });
673
134
 
674
- await q.done();
675
- }
676
-
677
- if (fallback) {
678
- const rendered = await server.respond(new Request('http://sveltekit-prerender/[fallback]'), {
679
- prerender: {
680
- fallback,
681
- all: false,
682
- dependencies: new Map()
683
- }
684
- });
685
-
686
- const file = join(out, fallback);
687
- mkdirp(dirname(file));
688
- writeFileSync(file, await rendered.text());
689
- }
135
+ await http_server.listen(port, host || '0.0.0.0');
690
136
 
691
- return prerendered;
137
+ return Promise.resolve(http_server);
692
138
  }
693
139
 
694
140
  /**
695
- * @param {{
696
- * cwd: string;
697
- * config: import('types').ValidatedConfig;
698
- * build_data: import('types').BuildData;
699
- * log: import('types').Logger;
700
- * }} opts
701
- * @returns {import('types').Builder}
141
+ * @param {boolean} use_https
142
+ * @param {import('vite').UserConfig} user_config
143
+ * @param {(req: http.IncomingMessage, res: http.ServerResponse) => void} handler
144
+ * @returns {Promise<import('net').Server>}
702
145
  */
703
- function create_builder({ cwd, config, build_data, log }) {
704
- /** @type {Set<string>} */
705
- let prerendered_paths;
706
-
707
- let generated_manifest = false;
708
-
709
- /** @param {import('types').RouteData} route */
710
- function not_prerendered(route) {
711
- if (!prerendered_paths) return true;
712
-
713
- if (route.type === 'page' && route.path) {
714
- return !prerendered_paths.has(route.path);
146
+ async function get_server(use_https, user_config, handler) {
147
+ /** @type {https.ServerOptions} */
148
+ const https_options = {};
149
+
150
+ if (use_https) {
151
+ const secure_opts = user_config.server
152
+ ? /** @type {import('tls').SecureContextOptions} */ (user_config.server.https)
153
+ : {};
154
+
155
+ if (secure_opts.key && secure_opts.cert) {
156
+ https_options.key = secure_opts.key.toString();
157
+ https_options.cert = secure_opts.cert.toString();
158
+ } else {
159
+ https_options.key = https_options.cert = (await import('./cert.js')).createCertificate();
715
160
  }
716
-
717
- return true;
718
161
  }
719
162
 
720
- return {
721
- log,
722
- rimraf,
723
- mkdirp,
724
- copy,
725
-
726
- appDir: config.kit.appDir,
727
- trailingSlash: config.kit.trailingSlash,
728
-
729
- createEntries(fn) {
730
- generated_manifest = true;
731
-
732
- const { routes } = build_data.manifest_data;
733
-
734
- /** @type {import('types').RouteDefinition[]} */
735
- const facades = routes.map((route) => ({
736
- type: route.type,
737
- segments: route.segments,
738
- pattern: route.pattern,
739
- methods: route.type === 'page' ? ['get'] : build_data.server.methods[route.file]
740
- }));
741
-
742
- const seen = new Set();
743
-
744
- for (let i = 0; i < routes.length; i += 1) {
745
- const route = routes[i];
746
- const { id, filter, complete } = fn(facades[i]);
747
-
748
- if (seen.has(id)) continue;
749
- seen.add(id);
750
-
751
- const group = [route];
752
-
753
- // figure out which lower priority routes should be considered fallbacks
754
- for (let j = i + 1; j < routes.length; j += 1) {
755
- if (filter(facades[j])) {
756
- group.push(routes[j]);
757
- }
758
- }
759
-
760
- const filtered = new Set(group.filter(not_prerendered));
761
-
762
- // heuristic: if /foo/[bar] is included, /foo/[bar].json should
763
- // also be included, since the page likely needs the endpoint
764
- filtered.forEach((route) => {
765
- if (route.type === 'page') {
766
- const length = route.segments.length;
767
-
768
- const endpoint = routes.find((candidate) => {
769
- if (candidate.segments.length !== length) return false;
770
-
771
- for (let i = 0; i < length; i += 1) {
772
- const a = route.segments[i];
773
- const b = candidate.segments[i];
774
-
775
- if (i === length - 1) {
776
- return b.content === `${a.content}.json`;
777
- }
778
-
779
- if (a.content !== b.content) return false;
780
- }
781
- });
782
-
783
- if (endpoint) {
784
- filtered.add(endpoint);
785
- }
786
- }
787
- });
788
-
789
- if (filtered.size > 0) {
790
- complete({
791
- generateManifest: ({ relativePath, format }) =>
792
- generate_manifest(build_data, relativePath, Array.from(filtered), format)
793
- });
794
- }
795
- }
796
- },
797
-
798
- generateManifest: ({ relativePath, format }) => {
799
- generated_manifest = true;
800
- return generate_manifest(
801
- build_data,
802
- relativePath,
803
- build_data.manifest_data.routes.filter(not_prerendered),
804
- format
805
- );
806
- },
807
-
808
- getBuildDirectory(name) {
809
- return `${cwd}/${SVELTE_KIT}/${name}`;
810
- },
811
-
812
- getClientDirectory() {
813
- return `${cwd}/${SVELTE_KIT}/output/client`;
814
- },
815
-
816
- getServerDirectory() {
817
- return `${cwd}/${SVELTE_KIT}/output/server`;
818
- },
819
-
820
- getStaticDirectory() {
821
- return config.kit.files.assets;
822
- },
823
-
824
- writeClient(dest) {
825
- return copy(`${cwd}/${SVELTE_KIT}/output/client`, dest, {
826
- filter: (file) => file[0] !== '.'
827
- });
828
- },
829
-
830
- writeServer(dest) {
831
- return copy(`${cwd}/${SVELTE_KIT}/output/server`, dest, {
832
- filter: (file) => file[0] !== '.'
833
- });
834
- },
835
-
836
- writeStatic(dest) {
837
- return copy(config.kit.files.assets, dest);
838
- },
839
-
840
- async prerender({ all = false, dest, fallback }) {
841
- if (generated_manifest) {
842
- throw new Error(
843
- 'Adapters must call prerender(...) before createEntries(...) or generateManifest(...)'
844
- );
845
- }
846
-
847
- const prerendered = await prerender({
848
- out: dest,
849
- all,
850
- cwd,
851
- config,
852
- build_data,
853
- fallback,
854
- log
855
- });
856
-
857
- prerendered_paths = new Set(prerendered.paths);
858
-
859
- return prerendered;
860
- }
861
- };
862
- }
863
-
864
- /**
865
- * @param {import('types').ValidatedConfig} config
866
- * @param {import('types').BuildData} build_data
867
- * @param {{ cwd?: string, verbose: boolean }} opts
868
- */
869
- async function adapt(config, build_data, { cwd = process.cwd(), verbose }) {
870
- const { name, adapt } = config.kit.adapter;
871
-
872
- console.log($.bold().cyan(`\n> Using ${name}`));
873
-
874
- const log = logger({ verbose });
875
- const builder = create_builder({ cwd, config, build_data, log });
876
- await adapt(builder);
877
-
878
- log.success('done');
163
+ return Promise.resolve(
164
+ use_https
165
+ ? https.createServer(/** @type {https.ServerOptions} */ (https_options), handler)
166
+ : http.createServer(handler)
167
+ );
879
168
  }
880
169
 
881
- export { adapt };
170
+ export { preview };