@sveltejs/kit 1.0.0-next.350 → 1.0.0-next.353

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,120 +1,196 @@
1
- import { s, p as parse_route_id } from './misc.js';
2
- import { b as get_mime_lookup } from '../cli.js';
1
+ import { $ } from './error.js';
2
+ import { r as rimraf, m as mkdirp, c as copy } from './write_tsconfig.js';
3
+ import { g as generate_manifest } from '../vite.js';
4
+ import 'fs';
5
+ import 'path';
6
+ import 'url';
7
+ import '@sveltejs/vite-plugin-svelte';
8
+ import 'vite';
9
+ import './sync.js';
10
+ import '../node/polyfills.js';
11
+ import 'node:http';
12
+ import 'node:https';
13
+ import 'node:zlib';
14
+ import 'node:stream';
15
+ import 'node:buffer';
16
+ import 'node:util';
17
+ import 'node:url';
18
+ import 'node:net';
19
+ import 'node:fs';
20
+ import 'node:path';
21
+ import 'crypto';
22
+ import 'querystring';
23
+ import '../node.js';
24
+ import 'stream';
3
25
 
4
26
  /**
5
- * Generates the data used to write the server-side manifest.js file. This data is used in the Vite
6
- * build process, to power routing, etc.
27
+ * Creates the Builder which is passed to adapters for building the application.
7
28
  * @param {{
29
+ * config: import('types').ValidatedConfig;
8
30
  * build_data: import('types').BuildData;
9
- * relative_path: string;
10
- * routes: import('types').RouteData[];
11
- * format?: 'esm' | 'cjs'
31
+ * prerendered: import('types').Prerendered;
32
+ * log: import('types').Logger;
12
33
  * }} opts
34
+ * @returns {import('types').Builder}
13
35
  */
14
- function generate_manifest({ build_data, relative_path, routes, format = 'esm' }) {
15
- /** @typedef {{ index: number, path: string }} LookupEntry */
16
- /** @type {Map<string, LookupEntry>} */
17
- const bundled_nodes = new Map();
18
-
19
- // 0 and 1 are special, they correspond to the root layout and root error nodes
20
- bundled_nodes.set(build_data.manifest_data.components[0], {
21
- path: `${relative_path}/nodes/0.js`,
22
- index: 0
23
- });
24
-
25
- bundled_nodes.set(build_data.manifest_data.components[1], {
26
- path: `${relative_path}/nodes/1.js`,
27
- index: 1
28
- });
29
-
30
- routes.forEach((route) => {
31
- if (route.type === 'page') {
32
- [...route.a, ...route.b].forEach((component) => {
33
- if (component && !bundled_nodes.has(component)) {
34
- const i = build_data.manifest_data.components.indexOf(component);
35
-
36
- bundled_nodes.set(component, {
37
- path: `${relative_path}/nodes/${i}.js`,
38
- index: bundled_nodes.size
39
- });
40
- }
41
- });
36
+ function create_builder({ config, build_data, prerendered, log }) {
37
+ /** @type {Set<string>} */
38
+ const prerendered_paths = new Set(prerendered.paths);
39
+
40
+ /** @param {import('types').RouteData} route */
41
+ // TODO routes should come pre-filtered
42
+ function not_prerendered(route) {
43
+ if (route.type === 'page' && route.path) {
44
+ return !prerendered_paths.has(route.path);
42
45
  }
43
- });
44
46
 
45
- /** @type {(path: string) => string} */
46
- const load =
47
- format === 'esm'
48
- ? (path) => `import('${path}')`
49
- : (path) => `Promise.resolve().then(() => require('${path}'))`;
47
+ return true;
48
+ }
50
49
 
51
- /** @type {(path: string) => string} */
52
- const loader = (path) => `() => ${load(path)}`;
50
+ return {
51
+ log,
52
+ rimraf,
53
+ mkdirp,
54
+ copy,
53
55
 
54
- const assets = build_data.manifest_data.assets.map((asset) => asset.file);
55
- if (build_data.service_worker) {
56
- assets.push(build_data.service_worker);
57
- }
56
+ config,
57
+ prerendered,
58
58
 
59
- /** @param {string | undefined} id */
60
- const get_index = (id) => id && /** @type {LookupEntry} */ (bundled_nodes.get(id)).index;
61
-
62
- const matchers = new Set();
63
-
64
- // prettier-ignore
65
- return `{
66
- appDir: ${s(build_data.app_dir)},
67
- assets: new Set(${s(assets)}),
68
- mimeTypes: ${s(get_mime_lookup(build_data.manifest_data))},
69
- _: {
70
- entry: ${s(build_data.client.entry)},
71
- nodes: [
72
- ${Array.from(bundled_nodes.values()).map(node => loader(node.path)).join(',\n\t\t\t\t')}
73
- ],
74
- routes: [
75
- ${routes.map(route => {
76
- const { pattern, names, types } = parse_route_id(route.id);
77
-
78
- types.forEach(type => {
79
- if (type) matchers.add(type);
80
- });
59
+ async createEntries(fn) {
60
+ const { routes } = build_data.manifest_data;
61
+
62
+ /** @type {import('types').RouteDefinition[]} */
63
+ const facades = routes.map((route) => ({
64
+ id: route.id,
65
+ type: route.type,
66
+ segments: route.id.split('/').map((segment) => ({
67
+ dynamic: segment.includes('['),
68
+ rest: segment.includes('[...'),
69
+ content: segment
70
+ })),
71
+ pattern: route.pattern,
72
+ methods: route.type === 'page' ? ['get'] : build_data.server.methods[route.file]
73
+ }));
74
+
75
+ const seen = new Set();
76
+
77
+ for (let i = 0; i < routes.length; i += 1) {
78
+ const route = routes[i];
79
+ const { id, filter, complete } = fn(facades[i]);
80
+
81
+ if (seen.has(id)) continue;
82
+ seen.add(id);
81
83
 
84
+ const group = [route];
85
+
86
+ // figure out which lower priority routes should be considered fallbacks
87
+ for (let j = i + 1; j < routes.length; j += 1) {
88
+ if (filter(facades[j])) {
89
+ group.push(routes[j]);
90
+ }
91
+ }
92
+
93
+ const filtered = new Set(group.filter(not_prerendered));
94
+
95
+ // heuristic: if /foo/[bar] is included, /foo/[bar].json should
96
+ // also be included, since the page likely needs the endpoint
97
+ filtered.forEach((route) => {
82
98
  if (route.type === 'page') {
83
- return `{
84
- type: 'page',
85
- id: ${s(route.id)},
86
- pattern: ${pattern},
87
- names: ${s(names)},
88
- types: ${s(types)},
89
- path: ${route.path ? s(route.path) : null},
90
- shadow: ${route.shadow ? loader(`${relative_path}/${build_data.server.vite_manifest[route.shadow].file}`) : null},
91
- a: ${s(route.a.map(get_index))},
92
- b: ${s(route.b.map(get_index))}
93
- }`.replace(/^\t\t/gm, '');
94
- } else {
95
- if (!build_data.server.vite_manifest[route.file]) {
96
- // this is necessary in cases where a .css file snuck in —
97
- // perhaps it would be better to disallow these (and others?)
98
- return null;
99
- }
99
+ const endpoint = routes.find((candidate) => candidate.id === route.id + '.json');
100
100
 
101
- return `{
102
- type: 'endpoint',
103
- id: ${s(route.id)},
104
- pattern: ${pattern},
105
- names: ${s(names)},
106
- types: ${s(types)},
107
- load: ${loader(`${relative_path}/${build_data.server.vite_manifest[route.file].file}`)}
108
- }`.replace(/^\t\t/gm, '');
101
+ if (endpoint) {
102
+ filtered.add(endpoint);
103
+ }
109
104
  }
110
- }).filter(Boolean).join(',\n\t\t\t\t')}
111
- ],
112
- matchers: async () => {
113
- ${Array.from(matchers).map(type => `const { match: ${type} } = await ${load(`${relative_path}/entries/matchers/${type}.js`)}`).join('\n\t\t\t\t')}
114
- return { ${Array.from(matchers).join(', ')} };
105
+ });
106
+
107
+ if (filtered.size > 0) {
108
+ await complete({
109
+ generateManifest: ({ relativePath, format }) =>
110
+ generate_manifest({
111
+ build_data,
112
+ relative_path: relativePath,
113
+ routes: Array.from(filtered),
114
+ format
115
+ })
116
+ });
117
+ }
115
118
  }
119
+ },
120
+
121
+ generateManifest: ({ relativePath, format }) => {
122
+ return generate_manifest({
123
+ build_data,
124
+ relative_path: relativePath,
125
+ routes: build_data.manifest_data.routes.filter(not_prerendered),
126
+ format
127
+ });
128
+ },
129
+
130
+ getBuildDirectory(name) {
131
+ return `${config.kit.outDir}/${name}`;
132
+ },
133
+
134
+ getClientDirectory() {
135
+ return `${config.kit.outDir}/output/client`;
136
+ },
137
+
138
+ getServerDirectory() {
139
+ return `${config.kit.outDir}/output/server`;
140
+ },
141
+
142
+ getStaticDirectory() {
143
+ return config.kit.files.assets;
144
+ },
145
+
146
+ writeClient(dest) {
147
+ return copy(`${config.kit.outDir}/output/client`, dest);
148
+ },
149
+
150
+ writePrerendered(dest, { fallback } = {}) {
151
+ const source = `${config.kit.outDir}/output/prerendered`;
152
+ const files = [...copy(`${source}/pages`, dest), ...copy(`${source}/dependencies`, dest)];
153
+
154
+ if (fallback) {
155
+ files.push(fallback);
156
+ copy(`${source}/fallback.html`, `${dest}/${fallback}`);
157
+ }
158
+
159
+ return files;
160
+ },
161
+
162
+ writeServer(dest) {
163
+ return copy(`${config.kit.outDir}/output/server`, dest);
164
+ },
165
+
166
+ writeStatic(dest) {
167
+ return copy(config.kit.files.assets, dest);
168
+ },
169
+
170
+ // @ts-expect-error
171
+ async prerender() {
172
+ throw new Error(
173
+ 'builder.prerender() has been removed. Prerendering now takes place in the build phase — see builder.prerender and builder.writePrerendered'
174
+ );
116
175
  }
117
- }`.replace(/^\t/gm, '');
176
+ };
177
+ }
178
+
179
+ /**
180
+ * @param {import('types').ValidatedConfig} config
181
+ * @param {import('types').BuildData} build_data
182
+ * @param {import('types').Prerendered} prerendered
183
+ * @param {{ log: import('types').Logger }} opts
184
+ */
185
+ async function adapt(config, build_data, prerendered, { log }) {
186
+ const { name, adapt } = config.kit.adapter;
187
+
188
+ console.log($.bold().cyan(`\n> Using ${name}`));
189
+
190
+ const builder = create_builder({ config, build_data, prerendered, log });
191
+ await adapt(builder);
192
+
193
+ log.success('done');
118
194
  }
119
195
 
120
- export { generate_manifest as g };
196
+ export { adapt };
@@ -1,14 +1,8 @@
1
1
  import path__default from 'path';
2
2
  import fs__default from 'fs';
3
- import { a as get_runtime_path } from '../cli.js';
4
- import { p as posixify, c as copy, r as rimraf } from './filesystem.js';
5
- import { p as parse_route_id, s } from './misc.js';
3
+ import { $ } from './error.js';
6
4
  import { fileURLToPath } from 'url';
7
- import { w as write_if_changed, t as trim, a as write, b as write_tsconfig } from './write_tsconfig.js';
8
- import 'chokidar';
9
- import 'sade';
10
- import 'vite';
11
- import 'os';
5
+ import { p as posixify, c as copy, w as write_if_changed, t as trim, r as rimraf, a as write, b as write_tsconfig } from './write_tsconfig.js';
12
6
 
13
7
  /**
14
8
  * @param typeMap [Object] Map of MIME type -> Array[extensions]
@@ -113,6 +107,174 @@ var other = {"application/prs.cww":["cww"],"application/vnd.1000minds.decision-m
113
107
  let Mime = Mime_1;
114
108
  var mime = new Mime(standard, other);
115
109
 
110
+ const get_runtime_path = /** @param {import('types').ValidatedKitConfig} config */ (config) =>
111
+ posixify_path(path__default.join(config.outDir, 'runtime'))
112
+ ;
113
+
114
+ /** @param {string} str */
115
+ function posixify_path(str) {
116
+ const parsed = path__default.parse(str);
117
+ return `/${parsed.dir.slice(parsed.root.length).split(path__default.sep).join('/')}/${parsed.base}`;
118
+ }
119
+
120
+ function noop() {}
121
+
122
+ /** @param {{ verbose: boolean }} opts */
123
+ function logger({ verbose }) {
124
+ /** @type {import('types').Logger} */
125
+ const log = (msg) => console.log(msg.replace(/^/gm, ' '));
126
+
127
+ /** @param {string} msg */
128
+ const err = (msg) => console.error(msg.replace(/^/gm, ' '));
129
+
130
+ log.success = (msg) => log($.green(`✔ ${msg}`));
131
+ log.error = (msg) => err($.bold().red(msg));
132
+ log.warn = (msg) => log($.bold().yellow(msg));
133
+
134
+ log.minor = verbose ? (msg) => log($.grey(msg)) : noop;
135
+ log.info = verbose ? log : noop;
136
+
137
+ return log;
138
+ }
139
+
140
+ /**
141
+ * Given an entry point like [cwd]/src/hooks, returns a filename like [cwd]/src/hooks.js or [cwd]/src/hooks/index.js
142
+ * @param {string} entry
143
+ * @returns {string|null}
144
+ */
145
+ function resolve_entry(entry) {
146
+ if (fs__default.existsSync(entry)) {
147
+ const stats = fs__default.statSync(entry);
148
+ if (stats.isDirectory()) {
149
+ return resolve_entry(path__default.join(entry, 'index'));
150
+ }
151
+
152
+ return entry;
153
+ } else {
154
+ const dir = path__default.dirname(entry);
155
+
156
+ if (fs__default.existsSync(dir)) {
157
+ const base = path__default.basename(entry);
158
+ const files = fs__default.readdirSync(dir);
159
+
160
+ const found = files.find((file) => file.replace(/\.[^.]+$/, '') === base);
161
+
162
+ if (found) return path__default.join(dir, found);
163
+ }
164
+ }
165
+
166
+ return null;
167
+ }
168
+
169
+ /** @param {import('types').ManifestData} manifest_data */
170
+ function get_mime_lookup(manifest_data) {
171
+ /** @type {Record<string, string>} */
172
+ const mime = {};
173
+
174
+ manifest_data.assets.forEach((asset) => {
175
+ if (asset.type) {
176
+ const ext = path__default.extname(asset.file);
177
+ mime[ext] = asset.type;
178
+ }
179
+ });
180
+
181
+ return mime;
182
+ }
183
+
184
+ /** @param {import('types').ValidatedKitConfig} config */
185
+ function get_aliases(config) {
186
+ /** @type {Record<string, string>} */
187
+ const alias = {
188
+ __GENERATED__: path__default.posix.join(config.outDir, 'generated'),
189
+ $app: `${get_runtime_path(config)}/app`,
190
+
191
+ // For now, we handle `$lib` specially here rather than make it a default value for
192
+ // `config.kit.alias` since it has special meaning for packaging, etc.
193
+ $lib: config.files.lib
194
+ };
195
+
196
+ for (const [key, value] of Object.entries(config.alias)) {
197
+ alias[key] = path__default.resolve(value);
198
+ }
199
+
200
+ return alias;
201
+ }
202
+
203
+ const param_pattern = /^(\.\.\.)?(\w+)(?:=(\w+))?$/;
204
+
205
+ /** @param {string} id */
206
+ function parse_route_id(id) {
207
+ /** @type {string[]} */
208
+ const names = [];
209
+
210
+ /** @type {string[]} */
211
+ const types = [];
212
+
213
+ // `/foo` should get an optional trailing slash, `/foo.json` should not
214
+ // const add_trailing_slash = !/\.[a-z]+$/.test(key);
215
+ let add_trailing_slash = true;
216
+
217
+ const pattern =
218
+ id === ''
219
+ ? /^\/$/
220
+ : new RegExp(
221
+ `^${decodeURIComponent(id)
222
+ .split(/(?:@[a-zA-Z0-9_-]+)?(?:\/|$)/)
223
+ .map((segment, i, segments) => {
224
+ // special case — /[...rest]/ could contain zero segments
225
+ const match = /^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(segment);
226
+ if (match) {
227
+ names.push(match[1]);
228
+ types.push(match[2]);
229
+ return '(?:/(.*))?';
230
+ }
231
+
232
+ const is_last = i === segments.length - 1;
233
+
234
+ return (
235
+ segment &&
236
+ '/' +
237
+ segment
238
+ .split(/\[(.+?)\]/)
239
+ .map((content, i) => {
240
+ if (i % 2) {
241
+ const [, rest, name, type] = /** @type {RegExpMatchArray} */ (
242
+ param_pattern.exec(content)
243
+ );
244
+ names.push(name);
245
+ types.push(type);
246
+ return rest ? '(.*?)' : '([^/]+?)';
247
+ }
248
+
249
+ if (is_last && content.includes('.')) add_trailing_slash = false;
250
+
251
+ return (
252
+ content // allow users to specify characters on the file system in an encoded manner
253
+ .normalize()
254
+ // We use [ and ] to denote parameters, so users must encode these on the file
255
+ // system to match against them. We don't decode all characters since others
256
+ // can already be epressed and so that '%' can be easily used directly in filenames
257
+ .replace(/%5[Bb]/g, '[')
258
+ .replace(/%5[Dd]/g, ']')
259
+ // '#', '/', and '?' can only appear in URL path segments in an encoded manner.
260
+ // They will not be touched by decodeURI so need to be encoded here, so
261
+ // that we can match against them.
262
+ // We skip '/' since you can't create a file with it on any OS
263
+ .replace(/#/g, '%23')
264
+ .replace(/\?/g, '%3F')
265
+ // escape characters that have special meaning in regex
266
+ .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
267
+ ); // TODO handle encoding
268
+ })
269
+ .join('')
270
+ );
271
+ })
272
+ .join('')}${add_trailing_slash ? '/?' : ''}$`
273
+ );
274
+
275
+ return { pattern, names, types };
276
+ }
277
+
116
278
  /**
117
279
  * A portion of a file or directory name where the name has been split into
118
280
  * static and dynamic parts
@@ -586,6 +748,8 @@ function copy_assets(dest) {
586
748
  } while (true); // eslint-disable-line
587
749
  }
588
750
 
751
+ const s = JSON.stringify;
752
+
589
753
  /**
590
754
  * Writes the client manifest to disk. The manifest is used to power the router. It contains the
591
755
  * list of routes and corresponding Svelte components (i.e. pages and layouts).
@@ -853,4 +1017,11 @@ function all(config) {
853
1017
  return update(config);
854
1018
  }
855
1019
 
856
- export { all, init, update };
1020
+ var sync = /*#__PURE__*/Object.freeze({
1021
+ __proto__: null,
1022
+ init: init,
1023
+ update: update,
1024
+ all: all
1025
+ });
1026
+
1027
+ export { get_runtime_path as a, get_mime_lookup as b, all as c, sync as d, get_aliases as g, init as i, logger as l, parse_route_id as p, resolve_entry as r, s, update as u };
@@ -1,7 +1,112 @@
1
1
  import fs__default from 'fs';
2
2
  import path__default from 'path';
3
- import { $ } from '../cli.js';
4
- import { m as mkdirp, p as posixify } from './filesystem.js';
3
+ import { $ } from './error.js';
4
+
5
+ /** @param {string} dir */
6
+ function mkdirp(dir) {
7
+ try {
8
+ fs__default.mkdirSync(dir, { recursive: true });
9
+ } catch (/** @type {any} */ e) {
10
+ if (e.code === 'EEXIST') return;
11
+ throw e;
12
+ }
13
+ }
14
+
15
+ /** @param {string} path */
16
+ function rimraf(path) {
17
+ fs__default.rmSync(path, { force: true, recursive: true });
18
+ }
19
+
20
+ /**
21
+ * @param {string} source
22
+ * @param {string} target
23
+ * @param {{
24
+ * filter?: (basename: string) => boolean;
25
+ * replace?: Record<string, string>;
26
+ * }} opts
27
+ */
28
+ function copy(source, target, opts = {}) {
29
+ if (!fs__default.existsSync(source)) return [];
30
+
31
+ /** @type {string[]} */
32
+ const files = [];
33
+
34
+ const prefix = posixify(target) + '/';
35
+
36
+ const regex = opts.replace
37
+ ? new RegExp(`\\b(${Object.keys(opts.replace).join('|')})\\b`, 'g')
38
+ : null;
39
+
40
+ /**
41
+ * @param {string} from
42
+ * @param {string} to
43
+ */
44
+ function go(from, to) {
45
+ if (opts.filter && !opts.filter(path__default.basename(from))) return;
46
+
47
+ const stats = fs__default.statSync(from);
48
+
49
+ if (stats.isDirectory()) {
50
+ fs__default.readdirSync(from).forEach((file) => {
51
+ go(path__default.join(from, file), path__default.join(to, file));
52
+ });
53
+ } else {
54
+ mkdirp(path__default.dirname(to));
55
+
56
+ if (opts.replace) {
57
+ const data = fs__default.readFileSync(from, 'utf-8');
58
+ fs__default.writeFileSync(
59
+ to,
60
+ data.replace(
61
+ /** @type {RegExp} */ (regex),
62
+ (match, key) => /** @type {Record<string, string>} */ (opts.replace)[key]
63
+ )
64
+ );
65
+ } else {
66
+ fs__default.copyFileSync(from, to);
67
+ }
68
+
69
+ files.push(to === target ? posixify(path__default.basename(to)) : posixify(to).replace(prefix, ''));
70
+ }
71
+ }
72
+
73
+ go(source, target);
74
+
75
+ return files;
76
+ }
77
+
78
+ /**
79
+ * Get a list of all files in a directory
80
+ * @param {string} cwd - the directory to walk
81
+ * @param {boolean} [dirs] - whether to include directories in the result
82
+ */
83
+ function walk(cwd, dirs = false) {
84
+ /** @type {string[]} */
85
+ const all_files = [];
86
+
87
+ /** @param {string} dir */
88
+ function walk_dir(dir) {
89
+ const files = fs__default.readdirSync(path__default.join(cwd, dir));
90
+
91
+ for (const file of files) {
92
+ const joined = path__default.join(dir, file);
93
+ const stats = fs__default.statSync(path__default.join(cwd, joined));
94
+ if (stats.isDirectory()) {
95
+ if (dirs) all_files.push(joined);
96
+ walk_dir(joined);
97
+ } else {
98
+ all_files.push(joined);
99
+ }
100
+ }
101
+ }
102
+
103
+ return walk_dir(''), all_files;
104
+ }
105
+
106
+ /** @param {string} str */
107
+ function posixify(str) {
108
+ return str.replace(/\\/g, '/');
109
+ }
5
110
 
6
111
  /** @type {Map<string, string>} */
7
112
  const previous_contents = new Map();
@@ -166,4 +271,4 @@ function validate(config, cwd, out, user_file) {
166
271
  }
167
272
  }
168
273
 
169
- export { write as a, write_tsconfig as b, trim as t, write_if_changed as w };
274
+ export { write as a, write_tsconfig as b, copy as c, walk as d, mkdirp as m, posixify as p, rimraf as r, trim as t, write_if_changed as w };