@sveltejs/kit 1.0.0-next.206 → 1.0.0-next.208

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,526 +1,136 @@
1
- import fs__default from 'fs';
1
+ import fs__default, { writeFileSync } from 'fs';
2
2
  import path__default from 'path';
3
- import { svelte } from '@sveltejs/vite-plugin-svelte';
4
- import require$$0 from 'os';
5
- import vite from 'vite';
6
- import { r as rimraf, a as resolve_entry, b as posixify, c as copy_assets, p as print_config_conflicts } from '../cli.js';
7
- import { c as create_manifest_data, a as create_app, d as deep_merge } from './index2.js';
3
+ import { p as print_config_conflicts, c as copy_assets, b as posixify, a as resolve_entry, r as rimraf, m as mkdirp } from '../cli.js';
4
+ import { d as deep_merge, a as create_app, c as create_manifest_data } from './index2.js';
8
5
  import { S as SVELTE_KIT } from './constants.js';
6
+ import { g as generate_manifest } from './index4.js';
7
+ import { s } from './misc.js';
8
+ import vite from 'vite';
9
+ import { svelte } from '@sveltejs/vite-plugin-svelte';
9
10
  import 'sade';
10
11
  import 'child_process';
11
12
  import 'net';
12
13
  import 'url';
14
+ import 'os';
13
15
  import './error.js';
14
16
 
15
- const isWin$1 = process.platform === 'win32';
16
- const SEP = isWin$1 ? `\\\\+` : `\\/`;
17
- const SEP_ESC = isWin$1 ? `\\\\` : `/`;
18
- const GLOBSTAR = `((?:[^/]*(?:/|$))*)`;
19
- const WILDCARD = `([^/]*)`;
20
- const GLOBSTAR_SEGMENT = `((?:[^${SEP_ESC}]*(?:${SEP_ESC}|$))*)`;
21
- const WILDCARD_SEGMENT = `([^${SEP_ESC}]*)`;
22
-
23
- /**
24
- * Convert any glob pattern to a JavaScript Regexp object
25
- * @param {String} glob Glob pattern to convert
26
- * @param {Object} opts Configuration object
27
- * @param {Boolean} [opts.extended=false] Support advanced ext globbing
28
- * @param {Boolean} [opts.globstar=false] Support globstar
29
- * @param {Boolean} [opts.strict=true] be laissez faire about mutiple slashes
30
- * @param {Boolean} [opts.filepath=''] Parse as filepath for extra path related features
31
- * @param {String} [opts.flags=''] RegExp globs
32
- * @returns {Object} converted object with string, segments and RegExp object
33
- */
34
- function globrex$1(glob, {extended = false, globstar = false, strict = false, filepath = false, flags = ''} = {}) {
35
- let regex = '';
36
- let segment = '';
37
- let path = { regex: '', segments: [] };
38
-
39
- // If we are doing extended matching, this boolean is true when we are inside
40
- // a group (eg {*.html,*.js}), and false otherwise.
41
- let inGroup = false;
42
- let inRange = false;
43
-
44
- // extglob stack. Keep track of scope
45
- const ext = [];
46
-
47
- // Helper function to build string and segments
48
- function add(str, {split, last, only}={}) {
49
- if (only !== 'path') regex += str;
50
- if (filepath && only !== 'regex') {
51
- path.regex += (str === '\\/' ? SEP : str);
52
- if (split) {
53
- if (last) segment += str;
54
- if (segment !== '') {
55
- if (!flags.includes('g')) segment = `^${segment}$`; // change it 'includes'
56
- path.segments.push(new RegExp(segment, flags));
57
- }
58
- segment = '';
59
- } else {
60
- segment += str;
61
- }
62
- }
63
- }
64
-
65
- let c, n;
66
- for (let i = 0; i < glob.length; i++) {
67
- c = glob[i];
68
- n = glob[i + 1];
69
-
70
- if (['\\', '$', '^', '.', '='].includes(c)) {
71
- add(`\\${c}`);
72
- continue;
73
- }
74
-
75
- if (c === '/') {
76
- add(`\\${c}`, {split: true});
77
- if (n === '/' && !strict) regex += '?';
78
- continue;
79
- }
80
-
81
- if (c === '(') {
82
- if (ext.length) {
83
- add(c);
84
- continue;
85
- }
86
- add(`\\${c}`);
87
- continue;
88
- }
89
-
90
- if (c === ')') {
91
- if (ext.length) {
92
- add(c);
93
- let type = ext.pop();
94
- if (type === '@') {
95
- add('{1}');
96
- } else if (type === '!') {
97
- add('([^\/]*)');
98
- } else {
99
- add(type);
100
- }
101
- continue;
102
- }
103
- add(`\\${c}`);
104
- continue;
105
- }
106
-
107
- if (c === '|') {
108
- if (ext.length) {
109
- add(c);
110
- continue;
111
- }
112
- add(`\\${c}`);
113
- continue;
114
- }
115
-
116
- if (c === '+') {
117
- if (n === '(' && extended) {
118
- ext.push(c);
119
- continue;
120
- }
121
- add(`\\${c}`);
122
- continue;
123
- }
124
-
125
- if (c === '@' && extended) {
126
- if (n === '(') {
127
- ext.push(c);
128
- continue;
129
- }
130
- }
131
-
132
- if (c === '!') {
133
- if (extended) {
134
- if (inRange) {
135
- add('^');
136
- continue
137
- }
138
- if (n === '(') {
139
- ext.push(c);
140
- add('(?!');
141
- i++;
142
- continue;
143
- }
144
- add(`\\${c}`);
145
- continue;
146
- }
147
- add(`\\${c}`);
148
- continue;
149
- }
150
-
151
- if (c === '?') {
152
- if (extended) {
153
- if (n === '(') {
154
- ext.push(c);
155
- } else {
156
- add('.');
157
- }
158
- continue;
159
- }
160
- add(`\\${c}`);
161
- continue;
162
- }
163
-
164
- if (c === '[') {
165
- if (inRange && n === ':') {
166
- i++; // skip [
167
- let value = '';
168
- while(glob[++i] !== ':') value += glob[i];
169
- if (value === 'alnum') add('(\\w|\\d)');
170
- else if (value === 'space') add('\\s');
171
- else if (value === 'digit') add('\\d');
172
- i++; // skip last ]
173
- continue;
174
- }
175
- if (extended) {
176
- inRange = true;
177
- add(c);
178
- continue;
179
- }
180
- add(`\\${c}`);
181
- continue;
182
- }
183
-
184
- if (c === ']') {
185
- if (extended) {
186
- inRange = false;
187
- add(c);
188
- continue;
189
- }
190
- add(`\\${c}`);
191
- continue;
192
- }
193
-
194
- if (c === '{') {
195
- if (extended) {
196
- inGroup = true;
197
- add('(');
198
- continue;
199
- }
200
- add(`\\${c}`);
201
- continue;
202
- }
203
-
204
- if (c === '}') {
205
- if (extended) {
206
- inGroup = false;
207
- add(')');
208
- continue;
209
- }
210
- add(`\\${c}`);
211
- continue;
212
- }
213
-
214
- if (c === ',') {
215
- if (inGroup) {
216
- add('|');
217
- continue;
218
- }
219
- add(`\\${c}`);
220
- continue;
221
- }
222
-
223
- if (c === '*') {
224
- if (n === '(' && extended) {
225
- ext.push(c);
226
- continue;
227
- }
228
- // Move over all consecutive "*"'s.
229
- // Also store the previous and next characters
230
- let prevChar = glob[i - 1];
231
- let starCount = 1;
232
- while (glob[i + 1] === '*') {
233
- starCount++;
234
- i++;
235
- }
236
- let nextChar = glob[i + 1];
237
- if (!globstar) {
238
- // globstar is disabled, so treat any number of "*" as one
239
- add('.*');
240
- } else {
241
- // globstar is enabled, so determine if this is a globstar segment
242
- let isGlobstar =
243
- starCount > 1 && // multiple "*"'s
244
- (prevChar === '/' || prevChar === undefined) && // from the start of the segment
245
- (nextChar === '/' || nextChar === undefined); // to the end of the segment
246
- if (isGlobstar) {
247
- // it's a globstar, so match zero or more path segments
248
- add(GLOBSTAR, {only:'regex'});
249
- add(GLOBSTAR_SEGMENT, {only:'path', last:true, split:true});
250
- i++; // move over the "/"
251
- } else {
252
- // it's not a globstar, so only match one path segment
253
- add(WILDCARD, {only:'regex'});
254
- add(WILDCARD_SEGMENT, {only:'path'});
255
- }
256
- }
257
- continue;
258
- }
259
-
260
- add(c);
261
- }
262
-
263
-
264
- // When regexp 'g' flag is specified don't
265
- // constrain the regular expression with ^ & $
266
- if (!flags.includes('g')) {
267
- regex = `^${regex}$`;
268
- segment = `^${segment}$`;
269
- if (filepath) path.regex = `^${path.regex}$`;
270
- }
271
-
272
- const result = {regex: new RegExp(regex, flags)};
273
-
274
- // Push the last segment
275
- if (filepath) {
276
- path.segments.push(new RegExp(segment, flags));
277
- path.regex = new RegExp(path.regex, flags);
278
- path.globstar = new RegExp(!flags.includes('g') ? `^${GLOBSTAR_SEGMENT}$` : GLOBSTAR_SEGMENT, flags);
279
- result.path = path;
280
- }
281
-
282
- return result;
283
- }
284
-
285
- var globrex_1 = globrex$1;
286
-
287
- const os = require$$0;
288
- const path = path__default;
289
- const isWin = os.platform() === 'win32';
290
-
291
- const CHARS = { '{': '}', '(': ')', '[': ']'};
292
- const STRICT = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\)|(\\).|([@?!+*]\(.*\)))/;
293
- const RELAXED = /\\(.)|(^!|[*?{}()[\]]|\(\?)/;
294
-
295
17
  /**
296
- * Detect if a string cointains glob
297
- * @param {String} str Input string
298
- * @param {Object} [options] Configuration object
299
- * @param {Boolean} [options.strict=true] Use relaxed regex if true
300
- * @returns {Boolean} true if string contains glob
18
+ * @param {{
19
+ * cwd: string;
20
+ * assets_base: string;
21
+ * config: import('types/config').ValidatedConfig
22
+ * manifest_data: import('types/internal').ManifestData
23
+ * build_dir: string;
24
+ * output_dir: string;
25
+ * client_entry_file: string;
26
+ * service_worker_entry_file: string | null;
27
+ * }} options
28
+ * @param {import('vite').Manifest} client_manifest
301
29
  */
302
- function isglob(str, { strict = true } = {}) {
303
- if (str === '') return false;
304
- let match, rgx = strict ? STRICT : RELAXED;
305
-
306
- while ((match = rgx.exec(str))) {
307
- if (match[2]) return true;
308
- let idx = match.index + match[0].length;
309
-
310
- // if an open bracket/brace/paren is escaped,
311
- // set the index to the next closing character
312
- let open = match[1];
313
- let close = open ? CHARS[open] : null;
314
- if (open && close) {
315
- let n = str.indexOf(close, idx);
316
- if (n !== -1) idx = n + 1;
317
- }
318
-
319
- str = str.slice(idx);
320
- }
321
- return false;
322
- }
323
-
30
+ async function build_service_worker(
31
+ { cwd, assets_base, config, manifest_data, build_dir, output_dir, service_worker_entry_file },
32
+ client_manifest
33
+ ) {
34
+ // TODO add any assets referenced in template .html file, e.g. favicon?
35
+ const app_files = new Set();
36
+ for (const key in client_manifest) {
37
+ const { file, css } = client_manifest[key];
38
+ app_files.add(file);
39
+ if (css) {
40
+ css.forEach((file) => {
41
+ app_files.add(file);
42
+ });
43
+ }
44
+ }
324
45
 
325
- /**
326
- * Find the static part of a glob-path,
327
- * split path and return path part
328
- * @param {String} str Path/glob string
329
- * @returns {String} static path section of glob
330
- */
331
- function parent(str, { strict = false } = {}) {
332
- if (isWin && str.includes('/'))
333
- str = str.split('\\').join('/');
46
+ fs__default.writeFileSync(
47
+ `${build_dir}/runtime/service-worker.js`,
48
+ `
49
+ export const timestamp = ${Date.now()};
334
50
 
335
- // special case for strings ending in enclosure containing path separator
336
- if (/[\{\[].*[\/]*.*[\}\]]$/.test(str)) str += '/';
51
+ export const build = [
52
+ ${Array.from(app_files)
53
+ .map((file) => `${s(`${config.kit.paths.base}/${config.kit.appDir}/${file}`)}`)
54
+ .join(',\n\t\t\t\t')}
55
+ ];
337
56
 
338
- // preserves full path in case of trailing path separator
339
- str += 'a';
57
+ export const files = [
58
+ ${manifest_data.assets
59
+ .map((asset) => `${s(`${config.kit.paths.base}/${asset.file}`)}`)
60
+ .join(',\n\t\t\t\t')}
61
+ ];
62
+ `
63
+ .replace(/^\t{3}/gm, '')
64
+ .trim()
65
+ );
340
66
 
341
- do {str = path.dirname(str);}
342
- while (isglob(str, {strict}) || /(^|[^\\])([\{\[]|\([^\)]+$)/.test(str));
67
+ /** @type {[any, string[]]} */
68
+ const [merged_config, conflicts] = deep_merge(config.kit.vite(), {
69
+ configFile: false,
70
+ root: cwd,
71
+ base: assets_base,
72
+ build: {
73
+ lib: {
74
+ entry: service_worker_entry_file,
75
+ name: 'app',
76
+ formats: ['es']
77
+ },
78
+ rollupOptions: {
79
+ output: {
80
+ entryFileNames: 'service-worker.js'
81
+ }
82
+ },
83
+ outDir: `${output_dir}/client`,
84
+ emptyOutDir: false
85
+ },
86
+ resolve: {
87
+ alias: {
88
+ '$service-worker': path__default.resolve(`${build_dir}/runtime/service-worker`),
89
+ $lib: config.kit.files.lib
90
+ }
91
+ }
92
+ });
343
93
 
344
- // remove escape chars and return result
345
- return str.replace(/\\([\*\?\|\[\]\(\)\{\}])/g, '$1');
346
- }
94
+ print_config_conflicts(conflicts, 'kit.vite.', 'build_service_worker');
347
95
 
348
- /**
349
- * Parse a glob path, and split it by static/glob part
350
- * @param {String} pattern String path
351
- * @param {Object} [opts] Options
352
- * @param {Object} [opts.strict=false] Use strict parsing
353
- * @returns {Object} object with parsed path
354
- */
355
- function globalyzer$1(pattern, opts = {}) {
356
- let base = parent(pattern, opts);
357
- let isGlob = isglob(pattern, opts);
358
- let glob;
359
-
360
- if (base != '.') {
361
- glob = pattern.substr(base.length);
362
- if (glob.startsWith('/')) glob = glob.substr(1);
363
- } else {
364
- glob = pattern;
365
- }
366
-
367
- if (!isGlob) {
368
- base = path.dirname(pattern);
369
- glob = base !== '.' ? pattern.substr(base.length) : pattern;
370
- }
371
-
372
- if (glob.startsWith('./')) glob = glob.substr(2);
373
- if (glob.startsWith('/')) glob = glob.substr(1);
374
-
375
- return { base, glob, isGlob };
96
+ await vite.build(merged_config);
376
97
  }
377
98
 
99
+ /** @param {import('vite').UserConfig} config */
100
+ async function create_build(config) {
101
+ const { output } = /** @type {import('rollup').RollupOutput} */ (await vite.build(config));
378
102
 
379
- var src = globalyzer$1;
380
-
381
- const fs = fs__default;
382
- const globrex = globrex_1;
383
- const globalyzer = src;
384
- const { join, resolve, relative } = path__default;
385
- const isHidden = /(^|[\\\/])\.[^\\\/\.]/g;
386
-
387
- let CACHE = {};
388
-
389
- function walk(output, prefix, lexer, opts, dirname='', level=0) {
390
- const rgx = lexer.segments[level];
391
- const dir = resolve(opts.cwd, prefix, dirname);
392
- const files = fs.readdirSync(dir);
393
- const { dot, filesOnly } = opts;
394
-
395
- let i=0, len=files.length, file;
396
- let fullpath, relpath, stats, isMatch;
397
-
398
- for (; i < len; i++) {
399
- fullpath = join(dir, file=files[i]);
400
- relpath = dirname ? join(dirname, file) : file;
401
- if (!dot && isHidden.test(relpath)) continue;
402
- isMatch = lexer.regex.test(relpath);
403
-
404
- if ((stats=CACHE[relpath]) === void 0) {
405
- CACHE[relpath] = stats = fs.lstatSync(fullpath);
406
- }
407
-
408
- if (!stats.isDirectory()) {
409
- isMatch && output.push(relative(opts.cwd, fullpath));
410
- continue;
411
- }
103
+ const chunks = /** @type {import('rollup').OutputChunk[]} */ (
104
+ output.filter((output) => output.type === 'chunk')
105
+ );
412
106
 
413
- if (rgx && !rgx.test(file)) continue;
414
- !filesOnly && isMatch && output.push(join(prefix, relpath));
107
+ const assets = /** @type {import('rollup').OutputAsset[]} */ (
108
+ output.filter((output) => output.type === 'asset')
109
+ );
415
110
 
416
- walk(output, prefix, lexer, opts, relpath, rgx && rgx.toString() !== lexer.globstar && level + 1);
417
- }
111
+ return { chunks, assets };
418
112
  }
419
113
 
420
114
  /**
421
- * Find files using bash-like globbing.
422
- * All paths are normalized compared to node-glob.
423
- * @param {String} str Glob string
424
- * @param {String} [options.cwd='.'] Current working directory
425
- * @param {Boolean} [options.dot=false] Include dotfile matches
426
- * @param {Boolean} [options.absolute=false] Return absolute paths
427
- * @param {Boolean} [options.filesOnly=false] Do not include folders if true
428
- * @param {Boolean} [options.flush=false] Reset cache object
429
- * @returns {Array} array containing matching files
430
- */
431
- var sync = function (str, opts={}) {
432
- if (!str) return [];
433
-
434
- let glob = globalyzer(str);
435
-
436
- opts.cwd = opts.cwd || '.';
437
-
438
- if (!glob.isGlob) {
439
- try {
440
- let resolved = resolve(opts.cwd, str);
441
- let dirent = fs.statSync(resolved);
442
- if (opts.filesOnly && !dirent.isFile()) return [];
443
-
444
- return opts.absolute ? [resolved] : [str];
445
- } catch (err) {
446
- if (err.code != 'ENOENT') throw err;
447
-
448
- return [];
449
- }
450
- }
451
-
452
- if (opts.flush) CACHE = {};
453
-
454
- let matches = [];
455
- const { path } = globrex(glob.glob, { filepath:true, globstar:true, extended:true });
456
-
457
- path.globstar = path.globstar.toString();
458
- walk(matches, glob.base, path, opts, '.', 0);
459
-
460
- return opts.absolute ? matches.map(x => resolve(opts.cwd, x)) : matches;
461
- };
462
-
463
- var glob = sync;
464
-
465
- /** @param {any} value */
466
- const s = (value) => JSON.stringify(value);
467
-
468
- /**
469
- * @param {import('types/config').ValidatedConfig} config
470
- * @param {{
471
- * cwd?: string;
472
- * runtime?: string;
473
- * }} [opts]
474
- * @returns {Promise<import('types/internal').BuildData>}
115
+ * @param {string} file
116
+ * @param {import('vite').Manifest} manifest
117
+ * @param {Set<string>} css
118
+ * @param {Set<string>} js
119
+ * @returns
475
120
  */
476
- async function build(config, { cwd = process.cwd(), runtime = '@sveltejs/kit/ssr' } = {}) {
477
- const build_dir = path__default.resolve(cwd, `${SVELTE_KIT}/build`);
478
-
479
- rimraf(build_dir);
480
-
481
- const output_dir = path__default.resolve(cwd, `${SVELTE_KIT}/output`);
482
-
483
- const options = {
484
- cwd,
485
- config,
486
- build_dir,
487
- // TODO this is so that Vite's preloading works. Unfortunately, it fails
488
- // during `svelte-kit preview`, because we use a local asset path. If Vite
489
- // used relative paths, I _think_ this could get fixed. Issue here:
490
- // https://github.com/vitejs/vite/issues/2009
491
- assets_base: `${config.kit.paths.assets || config.kit.paths.base}/${config.kit.appDir}/`,
492
- manifest: create_manifest_data({
493
- config,
494
- output: build_dir,
495
- cwd
496
- }),
497
- output_dir,
498
- client_entry_file: `${SVELTE_KIT}/build/runtime/internal/start.js`,
499
- service_worker_entry_file: resolve_entry(config.kit.files.serviceWorker)
500
- };
121
+ function find_deps(file, manifest, js, css) {
122
+ const chunk = manifest[file];
501
123
 
502
- const client_manifest = await build_client(options);
503
- await build_server(options, client_manifest, runtime);
124
+ if (js.has(chunk.file)) return;
125
+ js.add(chunk.file);
504
126
 
505
- if (options.service_worker_entry_file) {
506
- if (config.kit.paths.assets) {
507
- throw new Error('Cannot use service worker alongside config.kit.paths.assets');
508
- }
509
-
510
- await build_service_worker(options, client_manifest);
127
+ if (chunk.css) {
128
+ chunk.css.forEach((file) => css.add(file));
511
129
  }
512
130
 
513
- const client = glob('**', { cwd: `${output_dir}/client`, filesOnly: true }).map(posixify);
514
- const server = glob('**', { cwd: `${output_dir}/server`, filesOnly: true }).map(posixify);
515
-
516
- return {
517
- client,
518
- server,
519
- static: options.manifest.assets.map((asset) => posixify(asset.file)),
520
- entries: options.manifest.routes
521
- .map((route) => (route.type === 'page' ? route.path : ''))
522
- .filter(Boolean)
523
- };
131
+ if (chunk.imports) {
132
+ chunk.imports.forEach((file) => find_deps(file, manifest, js, css));
133
+ }
524
134
  }
525
135
 
526
136
  /**
@@ -528,24 +138,25 @@ async function build(config, { cwd = process.cwd(), runtime = '@sveltejs/kit/ssr
528
138
  * cwd: string;
529
139
  * assets_base: string;
530
140
  * config: import('types/config').ValidatedConfig
531
- * manifest: import('types/internal').ManifestData
141
+ * manifest_data: import('types/internal').ManifestData
532
142
  * build_dir: string;
533
143
  * output_dir: string;
534
144
  * client_entry_file: string;
535
145
  * service_worker_entry_file: string | null;
146
+ * service_worker_register: boolean;
536
147
  * }} options
537
148
  */
538
149
  async function build_client({
539
150
  cwd,
540
151
  assets_base,
541
152
  config,
542
- manifest,
153
+ manifest_data,
543
154
  build_dir,
544
155
  output_dir,
545
156
  client_entry_file
546
157
  }) {
547
158
  create_app({
548
- manifest_data: manifest,
159
+ manifest_data,
549
160
  output: build_dir,
550
161
  cwd
551
162
  });
@@ -564,7 +175,7 @@ async function build_client({
564
175
  // This step is optional — Vite/Rollup will create the necessary chunks
565
176
  // for everything regardless — but it means that entry chunks reflect
566
177
  // their location in the source code, which is helpful for debugging
567
- manifest.components.forEach((file) => {
178
+ manifest_data.components.forEach((file) => {
568
179
  const resolved = path__default.resolve(cwd, file);
569
180
  const relative = path__default.relative(config.kit.files.routes, resolved);
570
181
 
@@ -574,16 +185,8 @@ async function build_client({
574
185
  input[name] = resolved;
575
186
  });
576
187
 
577
- /** @type {import('vite').UserConfig} */
578
- const vite_config = config.kit.vite();
579
-
580
- const default_config = {};
581
-
582
- // don't warn on overriding defaults
583
- const [modified_vite_config] = deep_merge(default_config, vite_config);
584
-
585
188
  /** @type {[any, string[]]} */
586
- const [merged_config, conflicts] = deep_merge(modified_vite_config, {
189
+ const [merged_config, conflicts] = deep_merge(config.kit.vite(), {
587
190
  configFile: false,
588
191
  root: cwd,
589
192
  base: assets_base,
@@ -621,42 +224,143 @@ async function build_client({
621
224
 
622
225
  print_config_conflicts(conflicts, 'kit.vite.', 'build_client');
623
226
 
624
- await vite.build(merged_config);
227
+ const { chunks, assets } = await create_build(merged_config);
625
228
 
626
- const client_manifest_file = `${client_out_dir}/manifest.json`;
627
229
  /** @type {import('vite').Manifest} */
628
- const client_manifest = JSON.parse(fs__default.readFileSync(client_manifest_file, 'utf-8'));
629
- fs__default.renameSync(client_manifest_file, `${output_dir}/manifest.json`); // inspectable but not shipped
230
+ const vite_manifest = JSON.parse(fs__default.readFileSync(`${client_out_dir}/manifest.json`, 'utf-8'));
231
+
232
+ const entry_js = new Set();
233
+ const entry_css = new Set();
234
+ find_deps(client_entry_file, vite_manifest, entry_js, entry_css);
235
+
236
+ return {
237
+ assets,
238
+ chunks,
239
+ entry: {
240
+ file: vite_manifest[client_entry_file].file,
241
+ js: Array.from(entry_js),
242
+ css: Array.from(entry_css)
243
+ },
244
+ vite_manifest
245
+ };
246
+ }
247
+
248
+ /**
249
+ * @param {{
250
+ * runtime: string,
251
+ * hooks: string,
252
+ * config: import('types/config').ValidatedConfig
253
+ * }} opts
254
+ * @returns
255
+ */
256
+ const template = ({ config, hooks, runtime }) => `
257
+ import { respond } from '${runtime}';
258
+ import root from './generated/root.svelte';
259
+ import { set_paths, assets, base } from './runtime/paths.js';
260
+ import { set_prerendering } from './runtime/env.js';
261
+ import * as user_hooks from ${s(hooks)};
262
+
263
+ const template = ({ head, body }) => ${s(fs__default.readFileSync(config.kit.files.template, 'utf-8'))
264
+ .replace('%svelte.head%', '" + head + "')
265
+ .replace('%svelte.body%', '" + body + "')};
266
+
267
+ let read = null;
268
+
269
+ set_paths(${s(config.kit.paths)});
270
+
271
+ // this looks redundant, but the indirection allows us to access
272
+ // named imports without triggering Rollup's missing import detection
273
+ const get_hooks = hooks => ({
274
+ getSession: hooks.getSession || (() => ({})),
275
+ handle: hooks.handle || (({ request, resolve }) => resolve(request)),
276
+ handleError: hooks.handleError || (({ error }) => console.error(error.stack)),
277
+ externalFetch: hooks.externalFetch || fetch
278
+ });
279
+
280
+ let default_protocol = 'https';
281
+
282
+ // allow paths to be globally overridden
283
+ // in svelte-kit preview and in prerendering
284
+ export function override(settings) {
285
+ default_protocol = settings.protocol || default_protocol;
286
+ set_paths(settings.paths);
287
+ set_prerendering(settings.prerendering);
288
+ read = settings.read;
289
+ }
290
+
291
+ export class App {
292
+ constructor(manifest) {
293
+ const hooks = get_hooks(user_hooks);
294
+
295
+ this.options = {
296
+ amp: ${config.kit.amp},
297
+ dev: false,
298
+ floc: ${config.kit.floc},
299
+ get_stack: error => String(error), // for security
300
+ handle_error: (error, request) => {
301
+ hooks.handleError({ error, request });
302
+ error.stack = this.options.get_stack(error);
303
+ },
304
+ hooks,
305
+ hydrate: ${s(config.kit.hydrate)},
306
+ manifest,
307
+ paths: { base, assets },
308
+ prefix: assets + '/${config.kit.appDir}/',
309
+ prerender: ${config.kit.prerender.enabled},
310
+ read,
311
+ root,
312
+ service_worker: ${
313
+ config.kit.files.serviceWorker && config.kit.serviceWorker.register
314
+ ? "'/service-worker.js'"
315
+ : 'null'
316
+ },
317
+ router: ${s(config.kit.router)},
318
+ ssr: ${s(config.kit.ssr)},
319
+ target: ${s(config.kit.target)},
320
+ template,
321
+ trailing_slash: ${s(config.kit.trailingSlash)}
322
+ };
323
+ }
324
+
325
+ render(request, {
326
+ prerender
327
+ } = {}) {
328
+ // TODO remove this for 1.0
329
+ if (Object.keys(request).sort().join() !== 'headers,method,rawBody,url') {
330
+ throw new Error('Adapters should call app.render({ url, method, headers, rawBody })');
331
+ }
332
+
333
+ const host = ${
334
+ config.kit.host
335
+ ? s(config.kit.host)
336
+ : `request.headers[${s(config.kit.headers.host || 'host')}]`
337
+ };
338
+ const protocol = ${
339
+ config.kit.protocol
340
+ ? s(config.kit.protocol)
341
+ : config.kit.headers.protocol
342
+ ? `request.headers[${s(config.kit.headers.protocol)}] || default_protocol`
343
+ : 'default_protocol'
344
+ };
630
345
 
631
- return client_manifest;
346
+ return respond({ ...request, url: new URL(request.url, protocol + '://' + host) }, this.options, { prerender });
347
+ }
632
348
  }
349
+ `;
633
350
 
634
351
  /**
635
352
  * @param {{
636
353
  * cwd: string;
637
354
  * assets_base: string;
638
355
  * config: import('types/config').ValidatedConfig
639
- * manifest: import('types/internal').ManifestData
356
+ * manifest_data: import('types/internal').ManifestData
640
357
  * build_dir: string;
641
358
  * output_dir: string;
642
- * client_entry_file: string;
643
- * service_worker_entry_file: string | null;
644
359
  * }} options
645
- * @param {import('vite').Manifest} client_manifest
646
360
  * @param {string} runtime
647
361
  */
648
362
  async function build_server(
649
- {
650
- cwd,
651
- assets_base,
652
- config,
653
- manifest,
654
- build_dir,
655
- output_dir,
656
- client_entry_file,
657
- service_worker_entry_file
658
- },
659
- client_manifest,
363
+ { cwd, assets_base, config, manifest_data, build_dir, output_dir },
660
364
  runtime
661
365
  ) {
662
366
  let hooks_file = resolve_entry(config.kit.files.hooks);
@@ -665,215 +369,46 @@ async function build_server(
665
369
  fs__default.writeFileSync(hooks_file, '');
666
370
  }
667
371
 
668
- const app_file = `${build_dir}/app.js`;
669
-
670
- /** @type {(file: string) => string} */
671
- const app_relative = (file) => {
672
- const relative_file = path__default.relative(build_dir, path__default.resolve(cwd, file));
673
- return relative_file[0] === '.' ? relative_file : `./${relative_file}`;
372
+ /** @type {Record<string, string>} */
373
+ const input = {
374
+ app: `${build_dir}/app.js`
674
375
  };
675
376
 
676
- const prefix = `/${config.kit.appDir}/`;
677
-
678
- /**
679
- * @param {string} file
680
- * @param {Set<string>} js_deps
681
- * @param {Set<string>} css_deps
682
- */
683
- function find_deps(file, js_deps, css_deps) {
684
- const chunk = client_manifest[file];
685
-
686
- if (js_deps.has(chunk.file)) return;
687
- js_deps.add(chunk.file);
688
-
689
- if (chunk.css) {
690
- chunk.css.forEach((file) => css_deps.add(file));
377
+ // add entry points for every endpoint...
378
+ manifest_data.routes.forEach((route) => {
379
+ if (route.type === 'endpoint') {
380
+ const resolved = path__default.resolve(cwd, route.file);
381
+ const relative = path__default.relative(config.kit.files.routes, resolved);
382
+ const name = posixify(path__default.join('entries/endpoints', relative.replace(/\.js$/, '')));
383
+ input[name] = resolved;
691
384
  }
385
+ });
692
386
 
693
- if (chunk.imports) {
694
- chunk.imports.forEach((file) => find_deps(file, js_deps, css_deps));
695
- }
696
- }
697
-
698
- /** @type {Record<string, { entry: string, css: string[], js: string[], styles: string[] }>} */
699
- const metadata_lookup = {};
700
-
701
- manifest.components.forEach((file) => {
702
- const js_deps = new Set();
703
- const css_deps = new Set();
704
-
705
- find_deps(file, js_deps, css_deps);
706
-
707
- const js = Array.from(js_deps);
708
- const css = Array.from(css_deps);
709
-
710
- const styles = config.kit.amp
711
- ? Array.from(css_deps).map((url) => {
712
- const resolved = `${output_dir}/client/${config.kit.appDir}/${url}`;
713
- return fs__default.readFileSync(resolved, 'utf-8');
714
- })
715
- : [];
387
+ // ...and every component used by pages
388
+ manifest_data.components.forEach((file) => {
389
+ const resolved = path__default.resolve(cwd, file);
390
+ const relative = path__default.relative(config.kit.files.routes, resolved);
716
391
 
717
- metadata_lookup[file] = {
718
- entry: client_manifest[file].file,
719
- css,
720
- js,
721
- styles
722
- };
392
+ const name = relative.startsWith('..')
393
+ ? posixify(path__default.join('entries/pages', path__default.basename(file)))
394
+ : posixify(path__default.join('entries/pages', relative));
395
+ input[name] = resolved;
723
396
  });
724
397
 
725
- /** @type {Set<string>} */
726
- const entry_js = new Set();
727
- /** @type {Set<string>} */
728
- const entry_css = new Set();
729
-
730
- find_deps(client_entry_file, entry_js, entry_css);
398
+ /** @type {(file: string) => string} */
399
+ const app_relative = (file) => {
400
+ const relative_file = path__default.relative(build_dir, path__default.resolve(cwd, file));
401
+ return relative_file[0] === '.' ? relative_file : `./${relative_file}`;
402
+ };
731
403
 
732
404
  // prettier-ignore
733
405
  fs__default.writeFileSync(
734
- app_file,
735
- `
736
- import { respond } from '${runtime}';
737
- import root from './generated/root.svelte';
738
- import { set_paths, assets } from './runtime/paths.js';
739
- import { set_prerendering } from './runtime/env.js';
740
- import * as user_hooks from ${s(app_relative(hooks_file))};
741
-
742
- const template = ({ head, body }) => ${s(fs__default.readFileSync(config.kit.files.template, 'utf-8'))
743
- .replace('%svelte.head%', '" + head + "')
744
- .replace('%svelte.body%', '" + body + "')};
745
-
746
- let options = null;
747
-
748
- const default_settings = { paths: ${s(config.kit.paths)} };
749
-
750
- // allow paths to be overridden in svelte-kit preview
751
- // and in prerendering
752
- export function init(settings = default_settings) {
753
- set_paths(settings.paths);
754
- set_prerendering(settings.prerendering || false);
755
-
756
- const hooks = get_hooks(user_hooks);
757
-
758
- options = {
759
- amp: ${config.kit.amp},
760
- dev: false,
761
- entry: {
762
- file: assets + ${s(prefix + client_manifest[client_entry_file].file)},
763
- css: [${Array.from(entry_css).map(dep => 'assets + ' + s(prefix + dep))}],
764
- js: [${Array.from(entry_js).map(dep => 'assets + ' + s(prefix + dep))}]
765
- },
766
- fetched: undefined,
767
- floc: ${config.kit.floc},
768
- get_component_path: id => assets + ${s(prefix)} + entry_lookup[id],
769
- get_stack: error => String(error), // for security
770
- handle_error: (error, request) => {
771
- hooks.handleError({ error, request });
772
- error.stack = options.get_stack(error);
773
- },
774
- hooks,
775
- hydrate: ${s(config.kit.hydrate)},
776
- initiator: undefined,
777
- load_component,
778
- manifest,
779
- paths: settings.paths,
780
- prerender: ${config.kit.prerender.enabled},
781
- read: settings.read,
782
- root,
783
- service_worker: ${service_worker_entry_file ? "'/service-worker.js'" : 'null'},
784
- router: ${s(config.kit.router)},
785
- ssr: ${s(config.kit.ssr)},
786
- target: ${s(config.kit.target)},
787
- template,
788
- trailing_slash: ${s(config.kit.trailingSlash)}
789
- };
790
- }
791
-
792
- // input has already been decoded by decodeURI
793
- // now handle the rest that decodeURIComponent would do
794
- const d = s => s
795
- .replace(/%23/g, '#')
796
- .replace(/%3[Bb]/g, ';')
797
- .replace(/%2[Cc]/g, ',')
798
- .replace(/%2[Ff]/g, '/')
799
- .replace(/%3[Ff]/g, '?')
800
- .replace(/%3[Aa]/g, ':')
801
- .replace(/%40/g, '@')
802
- .replace(/%26/g, '&')
803
- .replace(/%3[Dd]/g, '=')
804
- .replace(/%2[Bb]/g, '+')
805
- .replace(/%24/g, '$');
806
-
807
- const empty = () => ({});
808
-
809
- const manifest = {
810
- assets: ${s(manifest.assets)},
811
- layout: ${s(manifest.layout)},
812
- error: ${s(manifest.error)},
813
- routes: [
814
- ${manifest.routes
815
- .map((route) => {
816
- if (route.type === 'page') {
817
- const params = get_params(route.params);
818
-
819
- return `{
820
- type: 'page',
821
- pattern: ${route.pattern},
822
- params: ${params},
823
- a: [${route.a.map(file => file && s(file)).join(', ')}],
824
- b: [${route.b.map(file => file && s(file)).join(', ')}]
825
- }`;
826
- } else {
827
- const params = get_params(route.params);
828
- const load = `() => import(${s(app_relative(route.file))})`;
829
-
830
- return `{
831
- type: 'endpoint',
832
- pattern: ${route.pattern},
833
- params: ${params},
834
- load: ${load}
835
- }`;
836
- }
837
- })
838
- .join(',\n\t\t\t\t\t')}
839
- ]
840
- };
841
-
842
- // this looks redundant, but the indirection allows us to access
843
- // named imports without triggering Rollup's missing import detection
844
- const get_hooks = hooks => ({
845
- getSession: hooks.getSession || (() => ({})),
846
- handle: hooks.handle || (({ request, resolve }) => resolve(request)),
847
- handleError: hooks.handleError || (({ error }) => console.error(error.stack)),
848
- externalFetch: hooks.externalFetch || fetch
849
- });
850
-
851
- const module_lookup = {
852
- ${manifest.components.map(file => `${s(file)}: () => import(${s(app_relative(file))})`)}
853
- };
854
-
855
- const metadata_lookup = ${s(metadata_lookup)};
856
-
857
- async function load_component(file) {
858
- const { entry, css, js, styles } = metadata_lookup[file];
859
- return {
860
- module: await module_lookup[file](),
861
- entry: assets + ${s(prefix)} + entry,
862
- css: css.map(dep => assets + ${s(prefix)} + dep),
863
- js: js.map(dep => assets + ${s(prefix)} + dep),
864
- styles
865
- };
866
- }
867
-
868
- export function render(request, {
869
- prerender
870
- } = {}) {
871
- const host = ${config.kit.host ? s(config.kit.host) : `request.headers[${s(config.kit.hostHeader || 'host')}]`};
872
- return respond({ ...request, host }, options, { prerender });
873
- }
874
- `
875
- .replace(/^\t{3}/gm, '')
876
- .trim()
406
+ input.app,
407
+ template({
408
+ config,
409
+ hooks: app_relative(hooks_file),
410
+ runtime
411
+ })
877
412
  );
878
413
 
879
414
  /** @type {import('vite').UserConfig} */
@@ -896,11 +431,10 @@ async function build_server(
896
431
  build: {
897
432
  ssr: true,
898
433
  outDir: `${output_dir}/server`,
434
+ manifest: true,
899
435
  polyfillDynamicImport: false,
900
436
  rollupOptions: {
901
- input: {
902
- app: app_file
903
- },
437
+ input,
904
438
  output: {
905
439
  format: 'esm',
906
440
  entryFileNames: '[name].js',
@@ -928,115 +462,163 @@ async function build_server(
928
462
 
929
463
  print_config_conflicts(conflicts, 'kit.vite.', 'build_server');
930
464
 
931
- await vite.build(merged_config);
465
+ const { chunks } = await create_build(merged_config);
466
+
467
+ /** @type {Record<string, string[]>} */
468
+ const lookup = {};
469
+ chunks.forEach((chunk) => {
470
+ if (!chunk.facadeModuleId) return;
471
+ const id = chunk.facadeModuleId.slice(cwd.length + 1);
472
+ lookup[id] = chunk.exports;
473
+ });
474
+
475
+ /** @type {Record<string, import('types/internal').HttpMethod[]>} */
476
+ const methods = {};
477
+ manifest_data.routes.forEach((route) => {
478
+ if (route.type === 'endpoint' && lookup[route.file]) {
479
+ methods[route.file] = lookup[route.file]
480
+ .map((x) => /** @type {import('types/internal').HttpMethod} */ (method_names[x]))
481
+ .filter(Boolean);
482
+ }
483
+ });
484
+
485
+ return {
486
+ chunks,
487
+ /** @type {import('vite').Manifest} */
488
+ vite_manifest: JSON.parse(fs__default.readFileSync(`${output_dir}/server/manifest.json`, 'utf-8')),
489
+ methods: get_methods(cwd, chunks, manifest_data)
490
+ };
932
491
  }
933
492
 
493
+ /** @type {Record<string, string>} */
494
+ const method_names = {
495
+ get: 'get',
496
+ head: 'head',
497
+ post: 'post',
498
+ put: 'put',
499
+ del: 'delete',
500
+ patch: 'patch'
501
+ };
502
+
934
503
  /**
935
- * @param {{
936
- * cwd: string;
937
- * assets_base: string;
938
- * config: import('types/config').ValidatedConfig
939
- * manifest: import('types/internal').ManifestData
940
- * build_dir: string;
941
- * output_dir: string;
942
- * client_entry_file: string;
943
- * service_worker_entry_file: string | null;
944
- * }} options
945
- * @param {import('vite').Manifest} client_manifest
504
+ *
505
+ * @param {string} cwd
506
+ * @param {import('rollup').OutputChunk[]} output
507
+ * @param {import('types/internal').ManifestData} manifest_data
946
508
  */
947
- async function build_service_worker(
948
- { cwd, assets_base, config, manifest, build_dir, output_dir, service_worker_entry_file },
949
- client_manifest
950
- ) {
951
- // TODO add any assets referenced in template .html file, e.g. favicon?
952
- const app_files = new Set();
953
- for (const key in client_manifest) {
954
- const { file, css } = client_manifest[key];
955
- app_files.add(file);
956
- if (css) {
957
- css.forEach((file) => {
958
- app_files.add(file);
959
- });
509
+ function get_methods(cwd, output, manifest_data) {
510
+ /** @type {Record<string, string[]>} */
511
+ const lookup = {};
512
+ output.forEach((chunk) => {
513
+ if (!chunk.facadeModuleId) return;
514
+ const id = chunk.facadeModuleId.slice(cwd.length + 1);
515
+ lookup[id] = chunk.exports;
516
+ });
517
+
518
+ /** @type {Record<string, import('types/internal').HttpMethod[]>} */
519
+ const methods = {};
520
+ manifest_data.routes.forEach((route) => {
521
+ if (route.type === 'endpoint' && lookup[route.file]) {
522
+ methods[route.file] = lookup[route.file]
523
+ .map((x) => /** @type {import('types/internal').HttpMethod} */ (method_names[x]))
524
+ .filter(Boolean);
960
525
  }
961
- }
526
+ });
962
527
 
963
- fs__default.writeFileSync(
964
- `${build_dir}/runtime/service-worker.js`,
965
- `
966
- export const timestamp = ${Date.now()};
528
+ return methods;
529
+ }
967
530
 
968
- export const build = [
969
- ${Array.from(app_files)
970
- .map((file) => `${s(`${config.kit.paths.base}/${config.kit.appDir}/${file}`)}`)
971
- .join(',\n\t\t\t\t')}
972
- ];
531
+ /**
532
+ * @param {import('types/config').ValidatedConfig} config
533
+ * @param {{
534
+ * cwd?: string;
535
+ * runtime?: string;
536
+ * }} [opts]
537
+ * @returns {Promise<import('types/internal').BuildData>}
538
+ */
539
+ async function build(config, { cwd = process.cwd(), runtime = '@sveltejs/kit/ssr' } = {}) {
540
+ const build_dir = path__default.resolve(cwd, `${SVELTE_KIT}/build`);
973
541
 
974
- export const files = [
975
- ${manifest.assets
976
- .map((asset) => `${s(`${config.kit.paths.base}/${asset.file}`)}`)
977
- .join(',\n\t\t\t\t')}
978
- ];
979
- `
980
- .replace(/^\t{3}/gm, '')
981
- .trim()
982
- );
542
+ rimraf(build_dir);
983
543
 
984
- /** @type {import('vite').UserConfig} */
985
- const vite_config = config.kit.vite();
544
+ const output_dir = path__default.resolve(cwd, `${SVELTE_KIT}/output`);
986
545
 
987
- const default_config = {};
546
+ const options = {
547
+ cwd,
548
+ config,
549
+ build_dir,
550
+ // TODO this is so that Vite's preloading works. Unfortunately, it fails
551
+ // during `svelte-kit preview`, because we use a local asset path. If Vite
552
+ // used relative paths, I _think_ this could get fixed. Issue here:
553
+ // https://github.com/vitejs/vite/issues/2009
554
+ assets_base: `${config.kit.paths.assets || config.kit.paths.base}/${config.kit.appDir}/`,
555
+ manifest_data: create_manifest_data({
556
+ config,
557
+ output: build_dir,
558
+ cwd
559
+ }),
560
+ output_dir,
561
+ client_entry_file: `${SVELTE_KIT}/build/runtime/internal/start.js`,
562
+ service_worker_entry_file: resolve_entry(config.kit.files.serviceWorker),
563
+ service_worker_register: config.kit.serviceWorker.register
564
+ };
988
565
 
989
- // don't warn on overriding defaults
990
- const [modified_vite_config] = deep_merge(default_config, vite_config);
566
+ const client = await build_client(options);
567
+ const server = await build_server(options, runtime);
991
568
 
992
- /** @type {[any, string[]]} */
993
- const [merged_config, conflicts] = deep_merge(modified_vite_config, {
994
- configFile: false,
995
- root: cwd,
996
- base: assets_base,
997
- build: {
998
- lib: {
999
- entry: service_worker_entry_file,
1000
- name: 'app',
1001
- formats: ['es']
1002
- },
1003
- rollupOptions: {
1004
- output: {
1005
- entryFileNames: 'service-worker.js'
1006
- }
1007
- },
1008
- outDir: `${output_dir}/client`,
1009
- emptyOutDir: false
1010
- },
1011
- resolve: {
1012
- alias: {
1013
- '$service-worker': path__default.resolve(`${build_dir}/runtime/service-worker`),
1014
- $lib: config.kit.files.lib
569
+ const styles_lookup = new Map();
570
+ if (options.config.kit.amp) {
571
+ client.assets.forEach((asset) => {
572
+ if (asset.fileName.endsWith('.css')) {
573
+ styles_lookup.set(asset.fileName, asset.source);
1015
574
  }
1016
- }
575
+ });
576
+ }
577
+
578
+ mkdirp(`${output_dir}/server/nodes`);
579
+ options.manifest_data.components.forEach((component, i) => {
580
+ const file = `${output_dir}/server/nodes/${i}.js`;
581
+
582
+ const js = new Set();
583
+ const css = new Set();
584
+ find_deps(component, client.vite_manifest, js, css);
585
+
586
+ const styles = config.kit.amp && Array.from(css).map((file) => styles_lookup.get(file));
587
+
588
+ const node = `import * as module from '../${server.vite_manifest[component].file}';
589
+ export { module };
590
+ export const entry = '${client.vite_manifest[component].file}';
591
+ export const js = ${JSON.stringify(Array.from(js))};
592
+ export const css = ${JSON.stringify(Array.from(css))};
593
+ ${styles ? `export const styles = ${s(styles)}` : ''}
594
+ `.replace(/^\t\t\t/gm, '');
595
+
596
+ writeFileSync(file, node);
1017
597
  });
1018
598
 
1019
- print_config_conflicts(conflicts, 'kit.vite.', 'build_service_worker');
599
+ if (options.service_worker_entry_file) {
600
+ if (config.kit.paths.assets) {
601
+ throw new Error('Cannot use service worker alongside config.kit.paths.assets');
602
+ }
1020
603
 
1021
- await vite.build(merged_config);
1022
- }
604
+ await build_service_worker(options, client.vite_manifest);
605
+ }
606
+
607
+ const build_data = {
608
+ app_dir: config.kit.appDir,
609
+ manifest_data: options.manifest_data,
610
+ client,
611
+ server,
612
+ static: options.manifest_data.assets.map((asset) => posixify(asset.file)),
613
+ entries: options.manifest_data.routes
614
+ .map((route) => (route.type === 'page' ? route.path : ''))
615
+ .filter(Boolean)
616
+ };
617
+
618
+ const manifest = `export const manifest = ${generate_manifest(build_data, '.')};\n`;
619
+ fs__default.writeFileSync(`${output_dir}/server/manifest.js`, manifest);
1023
620
 
1024
- /** @param {string[]} array */
1025
- function get_params(array) {
1026
- // given an array of params like `['x', 'y', 'z']` for
1027
- // src/routes/[x]/[y]/[z]/svelte, create a function
1028
- // that turns a RexExpMatchArray into ({ x, y, z })
1029
- return array.length
1030
- ? '(m) => ({ ' +
1031
- array
1032
- .map((param, i) => {
1033
- return param.startsWith('...')
1034
- ? `${param.slice(3)}: d(m[${i + 1}] || '')`
1035
- : `${param}: d(m[${i + 1}])`;
1036
- })
1037
- .join(', ') +
1038
- '})'
1039
- : 'empty';
621
+ return build_data;
1040
622
  }
1041
623
 
1042
624
  export { build };