@sveltejs/kit 1.0.0-next.98 → 1.0.0
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.
- package/README.md +5 -1
- package/package.json +91 -77
- package/postinstall.js +47 -0
- package/src/cli.js +44 -0
- package/src/constants.js +5 -0
- package/src/core/adapt/builder.js +221 -0
- package/src/core/adapt/index.js +31 -0
- package/src/core/config/default-error.html +56 -0
- package/src/core/config/index.js +100 -0
- package/src/core/config/options.js +387 -0
- package/src/core/config/types.d.ts +1 -0
- package/src/core/env.js +138 -0
- package/src/core/generate_manifest/index.js +116 -0
- package/src/core/prerender/crawl.js +207 -0
- package/src/core/prerender/entities.js +2252 -0
- package/src/core/prerender/fallback.js +43 -0
- package/src/core/prerender/prerender.js +459 -0
- package/src/core/prerender/queue.js +80 -0
- package/src/core/sync/create_manifest_data/conflict.js +0 -0
- package/src/core/sync/create_manifest_data/index.js +523 -0
- package/src/core/sync/create_manifest_data/sort.js +161 -0
- package/src/core/sync/create_manifest_data/types.d.ts +37 -0
- package/src/core/sync/sync.js +59 -0
- package/src/core/sync/utils.js +33 -0
- package/src/core/sync/write_ambient.js +58 -0
- package/src/core/sync/write_client_manifest.js +107 -0
- package/src/core/sync/write_matchers.js +25 -0
- package/src/core/sync/write_root.js +91 -0
- package/src/core/sync/write_tsconfig.js +195 -0
- package/src/core/sync/write_types/index.js +809 -0
- package/src/core/utils.js +67 -0
- package/src/exports/hooks/index.js +1 -0
- package/src/exports/hooks/sequence.js +44 -0
- package/src/exports/index.js +55 -0
- package/src/exports/node/index.js +172 -0
- package/src/exports/node/polyfills.js +28 -0
- package/src/exports/vite/build/build_server.js +359 -0
- package/src/exports/vite/build/build_service_worker.js +85 -0
- package/src/exports/vite/build/utils.js +230 -0
- package/src/exports/vite/dev/index.js +597 -0
- package/src/exports/vite/graph_analysis/index.js +99 -0
- package/src/exports/vite/graph_analysis/types.d.ts +5 -0
- package/src/exports/vite/graph_analysis/utils.js +6 -0
- package/src/exports/vite/index.js +708 -0
- package/src/exports/vite/preview/index.js +194 -0
- package/src/exports/vite/types.d.ts +3 -0
- package/src/exports/vite/utils.js +184 -0
- package/src/runtime/app/env.js +1 -0
- package/src/runtime/app/environment.js +13 -0
- package/src/runtime/app/forms.js +135 -0
- package/src/runtime/app/navigation.js +22 -0
- package/src/runtime/app/paths.js +1 -0
- package/src/runtime/app/stores.js +57 -0
- package/src/runtime/client/ambient.d.ts +30 -0
- package/src/runtime/client/client.js +1725 -0
- package/src/runtime/client/constants.js +10 -0
- package/src/runtime/client/fetcher.js +127 -0
- package/src/runtime/client/parse.js +60 -0
- package/src/runtime/client/singletons.js +21 -0
- package/src/runtime/client/start.js +45 -0
- package/src/runtime/client/types.d.ts +86 -0
- package/src/runtime/client/utils.js +257 -0
- package/src/runtime/components/error.svelte +6 -0
- package/{assets → src/runtime}/components/layout.svelte +0 -0
- package/src/runtime/control.js +45 -0
- package/src/runtime/env/dynamic/private.js +1 -0
- package/src/runtime/env/dynamic/public.js +1 -0
- package/src/runtime/env-private.js +6 -0
- package/src/runtime/env-public.js +6 -0
- package/src/runtime/env.js +12 -0
- package/src/runtime/hash.js +20 -0
- package/src/runtime/paths.js +11 -0
- package/src/runtime/server/cookie.js +228 -0
- package/src/runtime/server/data/index.js +158 -0
- package/src/runtime/server/endpoint.js +86 -0
- package/src/runtime/server/fetch.js +175 -0
- package/src/runtime/server/index.js +405 -0
- package/src/runtime/server/page/actions.js +267 -0
- package/src/runtime/server/page/crypto.js +239 -0
- package/src/runtime/server/page/csp.js +250 -0
- package/src/runtime/server/page/index.js +326 -0
- package/src/runtime/server/page/load_data.js +270 -0
- package/src/runtime/server/page/render.js +393 -0
- package/src/runtime/server/page/respond_with_error.js +103 -0
- package/src/runtime/server/page/serialize_data.js +87 -0
- package/src/runtime/server/page/types.d.ts +35 -0
- package/src/runtime/server/utils.js +179 -0
- package/src/utils/array.js +9 -0
- package/src/utils/error.js +22 -0
- package/src/utils/escape.js +46 -0
- package/src/utils/exports.js +54 -0
- package/src/utils/filesystem.js +178 -0
- package/src/utils/functions.js +16 -0
- package/src/utils/http.js +72 -0
- package/src/utils/misc.js +1 -0
- package/src/utils/promises.js +17 -0
- package/src/utils/routing.js +201 -0
- package/src/utils/unit_test.js +11 -0
- package/src/utils/url.js +161 -0
- package/svelte-kit.js +1 -1
- package/types/ambient.d.ts +451 -0
- package/types/index.d.ts +1168 -5
- package/types/internal.d.ts +348 -160
- package/types/private.d.ts +237 -0
- package/types/synthetic/$env+dynamic+private.md +10 -0
- package/types/synthetic/$env+dynamic+public.md +8 -0
- package/types/synthetic/$env+static+private.md +19 -0
- package/types/synthetic/$env+static+public.md +7 -0
- package/types/synthetic/$lib.md +5 -0
- package/CHANGELOG.md +0 -819
- package/assets/components/error.svelte +0 -21
- package/assets/runtime/app/env.js +0 -16
- package/assets/runtime/app/navigation.js +0 -53
- package/assets/runtime/app/paths.js +0 -1
- package/assets/runtime/app/stores.js +0 -87
- package/assets/runtime/chunks/utils.js +0 -13
- package/assets/runtime/env.js +0 -8
- package/assets/runtime/internal/singletons.js +0 -20
- package/assets/runtime/internal/start.js +0 -1061
- package/assets/runtime/paths.js +0 -12
- package/dist/chunks/_commonjsHelpers.js +0 -8
- package/dist/chunks/cert.js +0 -29079
- package/dist/chunks/constants.js +0 -3
- package/dist/chunks/index.js +0 -3526
- package/dist/chunks/index2.js +0 -583
- package/dist/chunks/index3.js +0 -31
- package/dist/chunks/index4.js +0 -1005
- package/dist/chunks/index5.js +0 -327
- package/dist/chunks/index6.js +0 -325
- package/dist/chunks/standard.js +0 -99
- package/dist/chunks/utils.js +0 -149
- package/dist/cli.js +0 -711
- package/dist/http.js +0 -66
- package/dist/install-fetch.js +0 -1699
- package/dist/ssr.js +0 -1529
- package/types/ambient-modules.d.ts +0 -115
- package/types/config.d.ts +0 -101
- package/types/endpoint.d.ts +0 -23
- package/types/helper.d.ts +0 -19
- package/types/hooks.d.ts +0 -23
- package/types/page.d.ts +0 -30
|
@@ -0,0 +1,597 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import colors from 'kleur';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import sirv from 'sirv';
|
|
5
|
+
import { URL } from 'url';
|
|
6
|
+
import { isCSSRequest } from 'vite';
|
|
7
|
+
import { getRequest, setResponse } from '../../../exports/node/index.js';
|
|
8
|
+
import { installPolyfills } from '../../../exports/node/polyfills.js';
|
|
9
|
+
import { coalesce_to_error } from '../../../utils/error.js';
|
|
10
|
+
import { posixify, resolve_entry, to_fs } from '../../../utils/filesystem.js';
|
|
11
|
+
import { load_error_page, load_template } from '../../../core/config/index.js';
|
|
12
|
+
import { SVELTE_KIT_ASSETS } from '../../../constants.js';
|
|
13
|
+
import * as sync from '../../../core/sync/sync.js';
|
|
14
|
+
import { get_mime_lookup, runtime_prefix } from '../../../core/utils.js';
|
|
15
|
+
import { compact } from '../../../utils/array.js';
|
|
16
|
+
import { not_found } from '../utils.js';
|
|
17
|
+
|
|
18
|
+
const cwd = process.cwd();
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {import('vite').ViteDevServer} vite
|
|
22
|
+
* @param {import('vite').ResolvedConfig} vite_config
|
|
23
|
+
* @param {import('types').ValidatedConfig} svelte_config
|
|
24
|
+
* @return {Promise<Promise<() => void>>}
|
|
25
|
+
*/
|
|
26
|
+
export async function dev(vite, vite_config, svelte_config) {
|
|
27
|
+
installPolyfills();
|
|
28
|
+
|
|
29
|
+
sync.init(svelte_config, vite_config.mode);
|
|
30
|
+
|
|
31
|
+
/** @type {import('types').Respond} */
|
|
32
|
+
const respond = (await import(`${runtime_prefix}/server/index.js`)).respond;
|
|
33
|
+
|
|
34
|
+
/** @type {import('types').ManifestData} */
|
|
35
|
+
let manifest_data;
|
|
36
|
+
/** @type {import('types').SSRManifest} */
|
|
37
|
+
let manifest;
|
|
38
|
+
|
|
39
|
+
/** @type {Error | null} */
|
|
40
|
+
let manifest_error = null;
|
|
41
|
+
|
|
42
|
+
/** @param {string} id */
|
|
43
|
+
async function resolve(id) {
|
|
44
|
+
const url = id.startsWith('..') ? `/@fs${path.posix.resolve(id)}` : `/${id}`;
|
|
45
|
+
|
|
46
|
+
const module = await vite.ssrLoadModule(url);
|
|
47
|
+
|
|
48
|
+
const module_node = await vite.moduleGraph.getModuleByUrl(url);
|
|
49
|
+
if (!module_node) throw new Error(`Could not find node for ${url}`);
|
|
50
|
+
|
|
51
|
+
return { module, module_node, url };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function update_manifest() {
|
|
55
|
+
try {
|
|
56
|
+
({ manifest_data } = await sync.create(svelte_config));
|
|
57
|
+
|
|
58
|
+
if (manifest_error) {
|
|
59
|
+
manifest_error = null;
|
|
60
|
+
vite.ws.send({ type: 'full-reload' });
|
|
61
|
+
}
|
|
62
|
+
} catch (error) {
|
|
63
|
+
manifest_error = /** @type {Error} */ (error);
|
|
64
|
+
|
|
65
|
+
console.error(colors.bold().red('Invalid routes'));
|
|
66
|
+
console.error(error);
|
|
67
|
+
vite.ws.send({
|
|
68
|
+
type: 'error',
|
|
69
|
+
err: {
|
|
70
|
+
message: manifest_error.message ?? 'Invalid routes',
|
|
71
|
+
stack: ''
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
manifest = {
|
|
79
|
+
appDir: svelte_config.kit.appDir,
|
|
80
|
+
appPath: svelte_config.kit.appDir,
|
|
81
|
+
assets: new Set(manifest_data.assets.map((asset) => asset.file)),
|
|
82
|
+
mimeTypes: get_mime_lookup(manifest_data),
|
|
83
|
+
_: {
|
|
84
|
+
entry: {
|
|
85
|
+
file: `/@fs${runtime_prefix}/client/start.js`,
|
|
86
|
+
imports: [],
|
|
87
|
+
stylesheets: [],
|
|
88
|
+
fonts: []
|
|
89
|
+
},
|
|
90
|
+
nodes: manifest_data.nodes.map((node, index) => {
|
|
91
|
+
return async () => {
|
|
92
|
+
/** @type {import('types').SSRNode} */
|
|
93
|
+
const result = {};
|
|
94
|
+
|
|
95
|
+
/** @type {import('vite').ModuleNode[]} */
|
|
96
|
+
const module_nodes = [];
|
|
97
|
+
|
|
98
|
+
result.index = index;
|
|
99
|
+
|
|
100
|
+
// these are unused in dev, it's easier to include them
|
|
101
|
+
result.imports = [];
|
|
102
|
+
result.stylesheets = [];
|
|
103
|
+
result.fonts = [];
|
|
104
|
+
|
|
105
|
+
if (node.component) {
|
|
106
|
+
result.component = async () => {
|
|
107
|
+
const { module_node, module, url } = await resolve(
|
|
108
|
+
/** @type {string} */ (node.component)
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
module_nodes.push(module_node);
|
|
112
|
+
result.file = url.endsWith('.svelte') ? url : url + '?import'; // TODO what is this for?
|
|
113
|
+
|
|
114
|
+
return module.default;
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (node.universal) {
|
|
119
|
+
const { module, module_node } = await resolve(node.universal);
|
|
120
|
+
|
|
121
|
+
module_nodes.push(module_node);
|
|
122
|
+
|
|
123
|
+
result.universal = module;
|
|
124
|
+
result.universal_id = node.universal;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (node.server) {
|
|
128
|
+
const { module } = await resolve(node.server);
|
|
129
|
+
result.server = module;
|
|
130
|
+
result.server_id = node.server;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// in dev we inline all styles to avoid FOUC. this gets populated lazily so that
|
|
134
|
+
// components/stylesheets loaded via import() during `load` are included
|
|
135
|
+
result.inline_styles = async () => {
|
|
136
|
+
const deps = new Set();
|
|
137
|
+
|
|
138
|
+
for (const module_node of module_nodes) {
|
|
139
|
+
await find_deps(vite, module_node, deps);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** @type {Record<string, string>} */
|
|
143
|
+
const styles = {};
|
|
144
|
+
|
|
145
|
+
for (const dep of deps) {
|
|
146
|
+
const parsed = new URL(dep.url, 'http://localhost/');
|
|
147
|
+
const query = parsed.searchParams;
|
|
148
|
+
|
|
149
|
+
if (
|
|
150
|
+
isCSSRequest(dep.file) ||
|
|
151
|
+
(query.has('svelte') && query.get('type') === 'style')
|
|
152
|
+
) {
|
|
153
|
+
try {
|
|
154
|
+
const mod = await vite.ssrLoadModule(dep.url);
|
|
155
|
+
styles[dep.url] = mod.default;
|
|
156
|
+
} catch {
|
|
157
|
+
// this can happen with dynamically imported modules, I think
|
|
158
|
+
// because the Vite module graph doesn't distinguish between
|
|
159
|
+
// static and dynamic imports? TODO investigate, submit fix
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return styles;
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
return result;
|
|
168
|
+
};
|
|
169
|
+
}),
|
|
170
|
+
routes: compact(
|
|
171
|
+
manifest_data.routes.map((route) => {
|
|
172
|
+
if (!route.page && !route.endpoint) return null;
|
|
173
|
+
|
|
174
|
+
const endpoint = route.endpoint;
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
id: route.id,
|
|
178
|
+
pattern: route.pattern,
|
|
179
|
+
params: route.params,
|
|
180
|
+
page: route.page,
|
|
181
|
+
endpoint: endpoint
|
|
182
|
+
? async () => {
|
|
183
|
+
const url = path.resolve(cwd, endpoint.file);
|
|
184
|
+
return await vite.ssrLoadModule(url);
|
|
185
|
+
}
|
|
186
|
+
: null,
|
|
187
|
+
endpoint_id: endpoint?.file
|
|
188
|
+
};
|
|
189
|
+
})
|
|
190
|
+
),
|
|
191
|
+
matchers: async () => {
|
|
192
|
+
/** @type {Record<string, import('types').ParamMatcher>} */
|
|
193
|
+
const matchers = {};
|
|
194
|
+
|
|
195
|
+
for (const key in manifest_data.matchers) {
|
|
196
|
+
const file = manifest_data.matchers[key];
|
|
197
|
+
const url = path.resolve(cwd, file);
|
|
198
|
+
const module = await vite.ssrLoadModule(url);
|
|
199
|
+
|
|
200
|
+
if (module.match) {
|
|
201
|
+
matchers[key] = module.match;
|
|
202
|
+
} else {
|
|
203
|
+
throw new Error(`${file} does not export a \`match\` function`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return matchers;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/** @param {Error} error */
|
|
214
|
+
function fix_stack_trace(error) {
|
|
215
|
+
return error.stack ? vite.ssrRewriteStacktrace(error.stack) : error.stack;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
await update_manifest();
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* @param {string} event
|
|
222
|
+
* @param {(file: string) => void} cb
|
|
223
|
+
*/
|
|
224
|
+
const watch = (event, cb) => {
|
|
225
|
+
vite.watcher.on(event, (file) => {
|
|
226
|
+
if (
|
|
227
|
+
file.startsWith(svelte_config.kit.files.routes + path.sep) ||
|
|
228
|
+
file.startsWith(svelte_config.kit.files.params + path.sep) ||
|
|
229
|
+
// in contrast to server hooks, client hooks are written to the client manifest
|
|
230
|
+
// and therefore need rebuilding when they are added/removed
|
|
231
|
+
file.startsWith(svelte_config.kit.files.hooks.client)
|
|
232
|
+
) {
|
|
233
|
+
cb(file);
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
};
|
|
237
|
+
/** @type {NodeJS.Timeout | null } */
|
|
238
|
+
let timeout = null;
|
|
239
|
+
/** @param {() => void} to_run */
|
|
240
|
+
const debounce = (to_run) => {
|
|
241
|
+
timeout && clearTimeout(timeout);
|
|
242
|
+
timeout = setTimeout(() => {
|
|
243
|
+
timeout = null;
|
|
244
|
+
to_run();
|
|
245
|
+
}, 100);
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
// flag to skip watchers if server is already restarting
|
|
249
|
+
let restarting = false;
|
|
250
|
+
|
|
251
|
+
// Debounce add/unlink events because in case of folder deletion or moves
|
|
252
|
+
// they fire in rapid succession, causing needless invocations.
|
|
253
|
+
watch('add', () => debounce(update_manifest));
|
|
254
|
+
watch('unlink', () => debounce(update_manifest));
|
|
255
|
+
watch('change', (file) => {
|
|
256
|
+
// Don't run for a single file if the whole manifest is about to get updated
|
|
257
|
+
if (timeout || restarting) return;
|
|
258
|
+
|
|
259
|
+
sync.update(svelte_config, manifest_data, file);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
const { appTemplate } = svelte_config.kit.files;
|
|
263
|
+
// vite client only executes a full reload if the triggering html file path is index.html
|
|
264
|
+
// kit defaults to src/app.html, so unless user changed that to index.html
|
|
265
|
+
// send the vite client a full-reload event without path being set
|
|
266
|
+
if (appTemplate !== 'index.html') {
|
|
267
|
+
vite.watcher.on('change', (file) => {
|
|
268
|
+
if (file === appTemplate && !restarting) {
|
|
269
|
+
vite.ws.send({ type: 'full-reload' });
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// changing the svelte config requires restarting the dev server
|
|
275
|
+
// the config is only read on start and passed on to vite-plugin-svelte
|
|
276
|
+
// which needs up-to-date values to operate correctly
|
|
277
|
+
vite.watcher.on('change', (file) => {
|
|
278
|
+
if (path.basename(file) === 'svelte.config.js') {
|
|
279
|
+
console.log(`svelte config changed, restarting vite dev-server. changed file: ${file}`);
|
|
280
|
+
restarting = true;
|
|
281
|
+
vite.restart();
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
const assets = svelte_config.kit.paths.assets ? SVELTE_KIT_ASSETS : svelte_config.kit.paths.base;
|
|
286
|
+
const asset_server = sirv(svelte_config.kit.files.assets, {
|
|
287
|
+
dev: true,
|
|
288
|
+
etag: true,
|
|
289
|
+
maxAge: 0,
|
|
290
|
+
extensions: [],
|
|
291
|
+
setHeaders: (res) => {
|
|
292
|
+
res.setHeader('access-control-allow-origin', '*');
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
vite.middlewares.use(async (req, res, next) => {
|
|
297
|
+
try {
|
|
298
|
+
const base = `${vite.config.server.https ? 'https' : 'http'}://${
|
|
299
|
+
req.headers[':authority'] || req.headers.host
|
|
300
|
+
}`;
|
|
301
|
+
|
|
302
|
+
const decoded = decodeURI(new URL(base + req.url).pathname);
|
|
303
|
+
|
|
304
|
+
if (decoded.startsWith(assets)) {
|
|
305
|
+
const pathname = decoded.slice(assets.length);
|
|
306
|
+
const file = svelte_config.kit.files.assets + pathname;
|
|
307
|
+
|
|
308
|
+
if (fs.existsSync(file) && !fs.statSync(file).isDirectory()) {
|
|
309
|
+
if (has_correct_case(file, svelte_config.kit.files.assets)) {
|
|
310
|
+
req.url = encodeURI(pathname); // don't need query/hash
|
|
311
|
+
asset_server(req, res);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
next();
|
|
318
|
+
} catch (e) {
|
|
319
|
+
const error = coalesce_to_error(e);
|
|
320
|
+
res.statusCode = 500;
|
|
321
|
+
res.end(fix_stack_trace(error));
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
return () => {
|
|
326
|
+
const serve_static_middleware = vite.middlewares.stack.find(
|
|
327
|
+
(middleware) =>
|
|
328
|
+
/** @type {function} */ (middleware.handle).name === 'viteServeStaticMiddleware'
|
|
329
|
+
);
|
|
330
|
+
|
|
331
|
+
remove_static_middlewares(vite.middlewares);
|
|
332
|
+
|
|
333
|
+
vite.middlewares.use(async (req, res) => {
|
|
334
|
+
// Vite's base middleware strips out the base path. Restore it
|
|
335
|
+
req.url = req.originalUrl;
|
|
336
|
+
try {
|
|
337
|
+
const base = `${vite.config.server.https ? 'https' : 'http'}://${
|
|
338
|
+
req.headers[':authority'] || req.headers.host
|
|
339
|
+
}`;
|
|
340
|
+
|
|
341
|
+
const decoded = decodeURI(new URL(base + req.url).pathname);
|
|
342
|
+
const file = posixify(path.resolve(decoded.slice(1)));
|
|
343
|
+
const is_file = fs.existsSync(file) && !fs.statSync(file).isDirectory();
|
|
344
|
+
const allowed =
|
|
345
|
+
!vite_config.server.fs.strict ||
|
|
346
|
+
vite_config.server.fs.allow.some((dir) => file.startsWith(dir));
|
|
347
|
+
|
|
348
|
+
if (is_file && allowed) {
|
|
349
|
+
// @ts-expect-error
|
|
350
|
+
serve_static_middleware.handle(req, res);
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (!decoded.startsWith(svelte_config.kit.paths.base)) {
|
|
355
|
+
return not_found(req, res, svelte_config.kit.paths.base);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (decoded === svelte_config.kit.paths.base + '/service-worker.js') {
|
|
359
|
+
const resolved = resolve_entry(svelte_config.kit.files.serviceWorker);
|
|
360
|
+
|
|
361
|
+
if (resolved) {
|
|
362
|
+
res.writeHead(200, {
|
|
363
|
+
'content-type': 'application/javascript'
|
|
364
|
+
});
|
|
365
|
+
res.end(`import '${to_fs(resolved)}';`);
|
|
366
|
+
} else {
|
|
367
|
+
res.writeHead(404);
|
|
368
|
+
res.end('not found');
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const hooks_file = svelte_config.kit.files.hooks.server;
|
|
375
|
+
/** @type {Partial<import('types').ServerHooks>} */
|
|
376
|
+
const user_hooks = resolve_entry(hooks_file)
|
|
377
|
+
? await vite.ssrLoadModule(`/${hooks_file}`)
|
|
378
|
+
: {};
|
|
379
|
+
|
|
380
|
+
const handle = user_hooks.handle || (({ event, resolve }) => resolve(event));
|
|
381
|
+
|
|
382
|
+
/** @type {import('types').ServerHooks} */
|
|
383
|
+
const hooks = {
|
|
384
|
+
handle,
|
|
385
|
+
handleError:
|
|
386
|
+
user_hooks.handleError ||
|
|
387
|
+
(({ error: e }) => {
|
|
388
|
+
const error = /** @type {Error & { frame?: string }} */ (e);
|
|
389
|
+
console.error(colors.bold().red(error.message ?? error)); // Could be anything
|
|
390
|
+
if (error.frame) {
|
|
391
|
+
console.error(colors.gray(error.frame));
|
|
392
|
+
}
|
|
393
|
+
if (error.stack) {
|
|
394
|
+
console.error(colors.gray(error.stack));
|
|
395
|
+
}
|
|
396
|
+
}),
|
|
397
|
+
handleFetch: user_hooks.handleFetch || (({ request, fetch }) => fetch(request))
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
// TODO the / prefix will probably fail if outDir is outside the cwd (which
|
|
401
|
+
// could be the case in a monorepo setup), but without it these modules
|
|
402
|
+
// can get loaded twice via different URLs, which causes failures. Might
|
|
403
|
+
// require changes to Vite to fix
|
|
404
|
+
const { default: root } = await vite.ssrLoadModule(
|
|
405
|
+
`/${posixify(path.relative(cwd, `${svelte_config.kit.outDir}/generated/root.svelte`))}`
|
|
406
|
+
);
|
|
407
|
+
|
|
408
|
+
let request;
|
|
409
|
+
|
|
410
|
+
try {
|
|
411
|
+
request = await getRequest({
|
|
412
|
+
base,
|
|
413
|
+
request: req
|
|
414
|
+
});
|
|
415
|
+
} catch (/** @type {any} */ err) {
|
|
416
|
+
res.statusCode = err.status || 400;
|
|
417
|
+
return res.end('Invalid request body');
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const template = load_template(cwd, svelte_config);
|
|
421
|
+
const error_page = load_error_page(svelte_config);
|
|
422
|
+
|
|
423
|
+
/** @param {{ status: number; message: string }} opts */
|
|
424
|
+
const error_template = ({ status, message }) => {
|
|
425
|
+
return error_page
|
|
426
|
+
.replace(/%sveltekit\.status%/g, String(status))
|
|
427
|
+
.replace(/%sveltekit\.error\.message%/g, message);
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
if (manifest_error) {
|
|
431
|
+
console.error(colors.bold().red('Invalid routes'));
|
|
432
|
+
console.error(manifest_error);
|
|
433
|
+
|
|
434
|
+
res.writeHead(500, {
|
|
435
|
+
'Content-Type': 'text/html; charset=utf-8'
|
|
436
|
+
});
|
|
437
|
+
res.end(
|
|
438
|
+
error_template({ status: 500, message: manifest_error.message ?? 'Invalid routes' })
|
|
439
|
+
);
|
|
440
|
+
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
const rendered = await respond(
|
|
445
|
+
request,
|
|
446
|
+
{
|
|
447
|
+
csp: svelte_config.kit.csp,
|
|
448
|
+
csrf: {
|
|
449
|
+
check_origin: svelte_config.kit.csrf.checkOrigin
|
|
450
|
+
},
|
|
451
|
+
dev: true,
|
|
452
|
+
embedded: svelte_config.kit.embedded,
|
|
453
|
+
handle_error: async (error, event) => {
|
|
454
|
+
const error_object = await hooks.handleError({
|
|
455
|
+
error: new Proxy(error, {
|
|
456
|
+
get: (target, property) => {
|
|
457
|
+
if (property === 'stack') {
|
|
458
|
+
return fix_stack_trace(error);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
return Reflect.get(target, property, target);
|
|
462
|
+
}
|
|
463
|
+
}),
|
|
464
|
+
event
|
|
465
|
+
});
|
|
466
|
+
return (
|
|
467
|
+
error_object ?? { message: event.route.id != null ? 'Internal Error' : 'Not Found' }
|
|
468
|
+
);
|
|
469
|
+
},
|
|
470
|
+
hooks,
|
|
471
|
+
manifest,
|
|
472
|
+
paths: {
|
|
473
|
+
base: svelte_config.kit.paths.base,
|
|
474
|
+
assets
|
|
475
|
+
},
|
|
476
|
+
public_env: {},
|
|
477
|
+
read: (file) => fs.readFileSync(path.join(svelte_config.kit.files.assets, file)),
|
|
478
|
+
root,
|
|
479
|
+
app_template: ({ head, body, assets, nonce }) => {
|
|
480
|
+
return (
|
|
481
|
+
template
|
|
482
|
+
.replace(/%sveltekit\.assets%/g, assets)
|
|
483
|
+
.replace(/%sveltekit\.nonce%/g, nonce)
|
|
484
|
+
// head and body must be replaced last, in case someone tries to sneak in %sveltekit.assets% etc
|
|
485
|
+
.replace('%sveltekit.head%', () => head)
|
|
486
|
+
.replace('%sveltekit.body%', () => body)
|
|
487
|
+
);
|
|
488
|
+
},
|
|
489
|
+
app_template_contains_nonce: template.includes('%sveltekit.nonce%'),
|
|
490
|
+
error_template,
|
|
491
|
+
service_worker:
|
|
492
|
+
svelte_config.kit.serviceWorker.register &&
|
|
493
|
+
!!resolve_entry(svelte_config.kit.files.serviceWorker),
|
|
494
|
+
version: svelte_config.kit.version.name
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
getClientAddress: () => {
|
|
498
|
+
const { remoteAddress } = req.socket;
|
|
499
|
+
if (remoteAddress) return remoteAddress;
|
|
500
|
+
throw new Error('Could not determine clientAddress');
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
);
|
|
504
|
+
|
|
505
|
+
if (rendered.status === 404) {
|
|
506
|
+
// @ts-expect-error
|
|
507
|
+
serve_static_middleware.handle(req, res, () => {
|
|
508
|
+
setResponse(res, rendered);
|
|
509
|
+
});
|
|
510
|
+
} else {
|
|
511
|
+
setResponse(res, rendered);
|
|
512
|
+
}
|
|
513
|
+
} catch (e) {
|
|
514
|
+
const error = coalesce_to_error(e);
|
|
515
|
+
res.statusCode = 500;
|
|
516
|
+
res.end(fix_stack_trace(error));
|
|
517
|
+
}
|
|
518
|
+
});
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* @param {import('connect').Server} server
|
|
524
|
+
*/
|
|
525
|
+
function remove_static_middlewares(server) {
|
|
526
|
+
const static_middlewares = ['viteServeStaticMiddleware'];
|
|
527
|
+
for (let i = server.stack.length - 1; i > 0; i--) {
|
|
528
|
+
// @ts-expect-error using internals
|
|
529
|
+
if (static_middlewares.includes(server.stack[i].handle.name)) {
|
|
530
|
+
server.stack.splice(i, 1);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* @param {import('vite').ViteDevServer} vite
|
|
537
|
+
* @param {import('vite').ModuleNode} node
|
|
538
|
+
* @param {Set<import('vite').ModuleNode>} deps
|
|
539
|
+
*/
|
|
540
|
+
async function find_deps(vite, node, deps) {
|
|
541
|
+
// since `ssrTransformResult.deps` contains URLs instead of `ModuleNode`s, this process is asynchronous.
|
|
542
|
+
// instead of using `await`, we resolve all branches in parallel.
|
|
543
|
+
/** @type {Promise<void>[]} */
|
|
544
|
+
const branches = [];
|
|
545
|
+
|
|
546
|
+
/** @param {import('vite').ModuleNode} node */
|
|
547
|
+
async function add(node) {
|
|
548
|
+
if (!deps.has(node)) {
|
|
549
|
+
deps.add(node);
|
|
550
|
+
await find_deps(vite, node, deps);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/** @param {string} url */
|
|
555
|
+
async function add_by_url(url) {
|
|
556
|
+
const node = await vite.moduleGraph.getModuleByUrl(url);
|
|
557
|
+
|
|
558
|
+
if (node) {
|
|
559
|
+
await add(node);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
if (node.ssrTransformResult) {
|
|
564
|
+
if (node.ssrTransformResult.deps) {
|
|
565
|
+
node.ssrTransformResult.deps.forEach((url) => branches.push(add_by_url(url)));
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
if (node.ssrTransformResult.dynamicDeps) {
|
|
569
|
+
node.ssrTransformResult.dynamicDeps.forEach((url) => branches.push(add_by_url(url)));
|
|
570
|
+
}
|
|
571
|
+
} else {
|
|
572
|
+
node.importedModules.forEach((node) => branches.push(add(node)));
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
await Promise.all(branches);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Determine if a file is being requested with the correct case,
|
|
580
|
+
* to ensure consistent behaviour between dev and prod and across
|
|
581
|
+
* operating systems. Note that we can't use realpath here,
|
|
582
|
+
* because we don't want to follow symlinks
|
|
583
|
+
* @param {string} file
|
|
584
|
+
* @param {string} assets
|
|
585
|
+
* @returns {boolean}
|
|
586
|
+
*/
|
|
587
|
+
function has_correct_case(file, assets) {
|
|
588
|
+
if (file === assets) return true;
|
|
589
|
+
|
|
590
|
+
const parent = path.dirname(file);
|
|
591
|
+
|
|
592
|
+
if (fs.readdirSync(parent).includes(path.basename(file))) {
|
|
593
|
+
return has_correct_case(parent, assets);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
return false;
|
|
597
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { posixify } from '../../../utils/filesystem.js';
|
|
3
|
+
|
|
4
|
+
const ILLEGAL_IMPORTS = new Set(['\0$env/dynamic/private', '\0$env/static/private']);
|
|
5
|
+
const ILLEGAL_MODULE_NAME_PATTERN = /.*\.server\..+/;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Checks if given id imports a module that is not allowed to be imported into client-side code.
|
|
9
|
+
* @param {string} id
|
|
10
|
+
* @param {{
|
|
11
|
+
* cwd: string;
|
|
12
|
+
* node_modules: string;
|
|
13
|
+
* server: string;
|
|
14
|
+
* }} dirs
|
|
15
|
+
*/
|
|
16
|
+
export function is_illegal(id, dirs) {
|
|
17
|
+
if (ILLEGAL_IMPORTS.has(id)) return true;
|
|
18
|
+
if (!id.startsWith(dirs.cwd) || id.startsWith(dirs.node_modules)) return false;
|
|
19
|
+
return ILLEGAL_MODULE_NAME_PATTERN.test(path.basename(id)) || id.startsWith(dirs.server);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Creates a guard that checks that no id imports a module that is not allowed to be imported into client-side code.
|
|
24
|
+
* @param {import('rollup').PluginContext} context
|
|
25
|
+
* @param {{ cwd: string; lib: string }} paths
|
|
26
|
+
*/
|
|
27
|
+
export function module_guard(context, { cwd, lib }) {
|
|
28
|
+
/** @type {Set<string>} */
|
|
29
|
+
const seen = new Set();
|
|
30
|
+
|
|
31
|
+
const dirs = {
|
|
32
|
+
// ids will be posixified, so we need to posixify these, too
|
|
33
|
+
cwd: posixify(cwd),
|
|
34
|
+
node_modules: posixify(path.join(cwd, 'node_modules')),
|
|
35
|
+
server: posixify(path.join(lib, 'server'))
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {string} id
|
|
40
|
+
* @param {Array<{ id: string; dynamic: boolean }>} chain
|
|
41
|
+
*/
|
|
42
|
+
function follow(id, chain) {
|
|
43
|
+
if (seen.has(id)) return;
|
|
44
|
+
seen.add(id);
|
|
45
|
+
|
|
46
|
+
if (is_illegal(id, dirs)) {
|
|
47
|
+
chain.shift(); // discard the entry point
|
|
48
|
+
id = normalize_id(id, lib, cwd);
|
|
49
|
+
|
|
50
|
+
const pyramid =
|
|
51
|
+
chain.map(({ id, dynamic }, i) => {
|
|
52
|
+
id = normalize_id(id, lib, cwd);
|
|
53
|
+
|
|
54
|
+
return `${' '.repeat(i * 2)}- ${id} ${dynamic ? 'dynamically imports' : 'imports'}\n`;
|
|
55
|
+
}) + `${' '.repeat(chain.length)}- ${id}`;
|
|
56
|
+
|
|
57
|
+
const message = `Cannot import ${id} into client-side code:\n${pyramid}`;
|
|
58
|
+
|
|
59
|
+
throw new Error(message);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const module = context.getModuleInfo(id);
|
|
63
|
+
|
|
64
|
+
if (module) {
|
|
65
|
+
for (const child of module.importedIds) {
|
|
66
|
+
follow(child, [...chain, { id, dynamic: false }]);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
for (const child of module.dynamicallyImportedIds) {
|
|
70
|
+
follow(child, [...chain, { id, dynamic: true }]);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
/** @param {string} id should be posixified */
|
|
77
|
+
check: (id) => {
|
|
78
|
+
follow(id, []);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Removes cwd/lib path from the start of the id
|
|
85
|
+
* @param {string} id
|
|
86
|
+
* @param {string} lib
|
|
87
|
+
* @param {string} cwd
|
|
88
|
+
*/
|
|
89
|
+
export function normalize_id(id, lib, cwd) {
|
|
90
|
+
if (id.startsWith(lib)) {
|
|
91
|
+
id = id.replace(lib, '$lib');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (id.startsWith(cwd)) {
|
|
95
|
+
id = path.relative(cwd, id);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return posixify(id);
|
|
99
|
+
}
|