@sveltejs/kit 1.0.0-next.539 → 1.0.0-next.540
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/package.json +1 -1
- package/scripts/special-types/$env+dynamic+private.md +1 -1
- package/scripts/special-types/$env+static+private.md +1 -1
- package/scripts/special-types/$lib.md +1 -1
- package/src/exports/node/index.js +9 -0
- package/src/exports/vite/dev/index.js +0 -16
- package/src/exports/vite/graph_analysis/index.js +75 -245
- package/src/exports/vite/graph_analysis/utils.js +0 -24
- package/src/exports/vite/index.js +23 -11
- package/src/exports/vite/preview/index.js +21 -19
- package/src/runtime/client/client.js +16 -13
- package/src/runtime/client/fetcher.js +31 -17
- package/src/runtime/client/utils.js +8 -1
- package/src/utils/routing.js +0 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
This module provides access to runtime environment variables, as defined by the platform you're running on. For example if you're using [`adapter-node`](https://github.com/sveltejs/kit/tree/master/packages/adapter-node) (or running [`vite preview`](https://kit.svelte.dev/docs/cli)), this is equivalent to `process.env`. This module only includes variables that _do not_ begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#env).
|
|
2
2
|
|
|
3
|
-
This module cannot be imported into
|
|
3
|
+
This module cannot be imported into client-side code.
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
6
|
import { env } from '$env/dynamic/private';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Environment variables [loaded by Vite](https://vitejs.dev/guide/env-and-mode.html#env-files) from `.env` files and `process.env`. Like [`$env/dynamic/private`](https://kit.svelte.dev/docs/modules#$env-dynamic-private), this module cannot be imported into
|
|
1
|
+
Environment variables [loaded by Vite](https://vitejs.dev/guide/env-and-mode.html#env-files) from `.env` files and `process.env`. Like [`$env/dynamic/private`](https://kit.svelte.dev/docs/modules#$env-dynamic-private), this module cannot be imported into client-side code. This module only includes variables that _do not_ begin with [`config.kit.env.publicPrefix`](https://kit.svelte.dev/docs/configuration#env).
|
|
2
2
|
|
|
3
3
|
_Unlike_ [`$env/dynamic/private`](https://kit.svelte.dev/docs/modules#$env-dynamic-private), the values exported from this module are statically injected into your bundle at build time, enabling optimisations like dead code elimination.
|
|
4
4
|
|
|
@@ -2,4 +2,4 @@ This is a simple alias to `src/lib`, or whatever directory is specified as [`con
|
|
|
2
2
|
|
|
3
3
|
#### `$lib/server`
|
|
4
4
|
|
|
5
|
-
A subdirectory of `$lib`. SvelteKit will prevent you from importing any modules in `$lib/server` into
|
|
5
|
+
A subdirectory of `$lib`. SvelteKit will prevent you from importing any modules in `$lib/server` into client-side code. See [server-only modules](/docs/server-only-modules).
|
|
@@ -122,6 +122,15 @@ export async function setResponse(res, response) {
|
|
|
122
122
|
return;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
if (response.body.locked) {
|
|
126
|
+
res.write(
|
|
127
|
+
'Fatal error: Response body is locked. ' +
|
|
128
|
+
`This can happen when the response was already read (for example through 'response.json()' or 'response.text()').`
|
|
129
|
+
);
|
|
130
|
+
res.end();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
125
134
|
const reader = response.body.getReader();
|
|
126
135
|
|
|
127
136
|
if (res.destroyed) {
|
|
@@ -11,9 +11,7 @@ import { load_error_page, load_template } from '../../../core/config/index.js';
|
|
|
11
11
|
import { SVELTE_KIT_ASSETS } from '../../../constants.js';
|
|
12
12
|
import * as sync from '../../../core/sync/sync.js';
|
|
13
13
|
import { get_mime_lookup, runtime_base, runtime_prefix } from '../../../core/utils.js';
|
|
14
|
-
import { prevent_illegal_vite_imports } from '../graph_analysis/index.js';
|
|
15
14
|
import { compact } from '../../../utils/array.js';
|
|
16
|
-
import { normalizePath } from 'vite';
|
|
17
15
|
|
|
18
16
|
// Vite doesn't expose this so we just copy the list for now
|
|
19
17
|
// https://github.com/vitejs/vite/blob/3edd1af56e980aef56641a5a51cf2932bb580d41/packages/vite/src/node/plugins/css.ts#L96
|
|
@@ -43,8 +41,6 @@ export async function dev(vite, vite_config, svelte_config) {
|
|
|
43
41
|
/** @type {import('types').SSRManifest} */
|
|
44
42
|
let manifest;
|
|
45
43
|
|
|
46
|
-
const extensions = [...svelte_config.extensions, ...svelte_config.kit.moduleExtensions];
|
|
47
|
-
|
|
48
44
|
/** @param {string} id */
|
|
49
45
|
async function resolve(id) {
|
|
50
46
|
const url = id.startsWith('..') ? `/@fs${path.posix.resolve(id)}` : `/${id}`;
|
|
@@ -94,12 +90,6 @@ export async function dev(vite, vite_config, svelte_config) {
|
|
|
94
90
|
module_nodes.push(module_node);
|
|
95
91
|
result.file = url.endsWith('.svelte') ? url : url + '?import'; // TODO what is this for?
|
|
96
92
|
|
|
97
|
-
prevent_illegal_vite_imports(
|
|
98
|
-
module_node,
|
|
99
|
-
normalizePath(svelte_config.kit.files.lib),
|
|
100
|
-
extensions
|
|
101
|
-
);
|
|
102
|
-
|
|
103
93
|
return module.default;
|
|
104
94
|
};
|
|
105
95
|
}
|
|
@@ -110,12 +100,6 @@ export async function dev(vite, vite_config, svelte_config) {
|
|
|
110
100
|
module_nodes.push(module_node);
|
|
111
101
|
|
|
112
102
|
result.shared = module;
|
|
113
|
-
|
|
114
|
-
prevent_illegal_vite_imports(
|
|
115
|
-
module_node,
|
|
116
|
-
normalizePath(svelte_config.kit.files.lib),
|
|
117
|
-
extensions
|
|
118
|
-
);
|
|
119
103
|
}
|
|
120
104
|
|
|
121
105
|
if (node.server) {
|
|
@@ -1,277 +1,107 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
|
-
import {
|
|
3
|
-
import { remove_query_from_id, get_module_types } from './utils.js';
|
|
2
|
+
import { posixify } from '../../../utils/filesystem.js';
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const CWD_ID = normalizePath(process.cwd());
|
|
8
|
-
const NODE_MODULES_ID = normalizePath(path.resolve(process.cwd(), 'node_modules'));
|
|
9
|
-
const ILLEGAL_IMPORTS = new Set([
|
|
10
|
-
'/@id/__x00__$env/dynamic/private', //dev
|
|
11
|
-
'\0$env/dynamic/private', // prod
|
|
12
|
-
'/@id/__x00__$env/static/private', // dev
|
|
13
|
-
'\0$env/static/private' // prod
|
|
14
|
-
]);
|
|
4
|
+
const ILLEGAL_IMPORTS = new Set(['\0$env/dynamic/private', '\0$env/static/private']);
|
|
15
5
|
const ILLEGAL_MODULE_NAME_PATTERN = /.*\.server\..+/;
|
|
16
6
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
this.#lib_dir = normalizePath(lib_dir);
|
|
32
|
-
this.#server_dir = normalizePath(path.resolve(lib_dir, 'server'));
|
|
33
|
-
}
|
|
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
|
+
}
|
|
34
21
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (this.#is_illegal(child.id)) {
|
|
44
|
-
this.#chain.push(child);
|
|
45
|
-
const error = this.#format_illegal_import_chain(this.#chain);
|
|
46
|
-
this.#chain = []; // Reset the chain in case we want to reuse this guard
|
|
47
|
-
throw new Error(error);
|
|
48
|
-
}
|
|
49
|
-
this.assert_legal(child);
|
|
50
|
-
}
|
|
51
|
-
this.#chain.pop();
|
|
52
|
-
}
|
|
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();
|
|
53
30
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (this.#is_kit_illegal(module_id) || this.#is_user_illegal(module_id)) return true;
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
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
|
+
};
|
|
63
37
|
|
|
64
38
|
/**
|
|
65
|
-
*
|
|
66
|
-
* @param {string}
|
|
67
|
-
* @returns {boolean}
|
|
39
|
+
* @param {string} id
|
|
40
|
+
* @param {Array<{ id: string, dynamic: boolean }>} chain
|
|
68
41
|
*/
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
42
|
+
function follow(id, chain) {
|
|
43
|
+
if (seen.has(id)) return;
|
|
44
|
+
seen.add(id);
|
|
72
45
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
* @returns {boolean}
|
|
77
|
-
*/
|
|
78
|
-
#is_user_illegal(module_id) {
|
|
79
|
-
if (module_id.startsWith(this.#server_dir)) return true;
|
|
46
|
+
if (is_illegal(id, dirs)) {
|
|
47
|
+
chain.shift(); // discard the entry point
|
|
48
|
+
id = normalize_id(id, lib, cwd);
|
|
80
49
|
|
|
81
|
-
|
|
82
|
-
|
|
50
|
+
const pyramid =
|
|
51
|
+
chain.map(({ id, dynamic }, i) => {
|
|
52
|
+
id = normalize_id(id, lib, cwd);
|
|
83
53
|
|
|
84
|
-
|
|
85
|
-
|
|
54
|
+
return `${repeat(' ', i * 2)}- ${id} ${dynamic ? 'dynamically imports' : 'imports'}\n`;
|
|
55
|
+
}) + `${repeat(' ', chain.length)}- ${id}`;
|
|
86
56
|
|
|
87
|
-
|
|
88
|
-
}
|
|
57
|
+
const message = `Cannot import ${id} into client-side code:\n${pyramid}`;
|
|
89
58
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
* @param {number} times
|
|
93
|
-
*/
|
|
94
|
-
#repeat(str, times) {
|
|
95
|
-
return new Array(times + 1).join(str);
|
|
96
|
-
}
|
|
59
|
+
throw new Error(message);
|
|
60
|
+
}
|
|
97
61
|
|
|
98
|
-
|
|
99
|
-
* Create a formatted error for an illegal import.
|
|
100
|
-
* @param {Array<ImportGraph>} stack
|
|
101
|
-
*/
|
|
102
|
-
#format_illegal_import_chain(stack) {
|
|
103
|
-
const dev_virtual_prefix = '/@id/__x00__';
|
|
104
|
-
const prod_virtual_prefix = '\0';
|
|
62
|
+
const module = context.getModuleInfo(id);
|
|
105
63
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
if (graph.id.startsWith(prod_virtual_prefix)) {
|
|
111
|
-
return { ...graph, id: graph.id.replace(prod_virtual_prefix, '') };
|
|
112
|
-
}
|
|
113
|
-
if (graph.id.startsWith(this.#lib_dir)) {
|
|
114
|
-
return { ...graph, id: graph.id.replace(this.#lib_dir, '$lib') };
|
|
64
|
+
if (module) {
|
|
65
|
+
for (const child of module.importedIds) {
|
|
66
|
+
follow(child, [...chain, { id, dynamic: false }]);
|
|
115
67
|
}
|
|
116
68
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
.map(
|
|
122
|
-
(file, i) =>
|
|
123
|
-
`${this.#repeat(' ', i * 2)}- ${file.id} ${
|
|
124
|
-
file.dynamic ? '(imported by parent dynamically)' : ''
|
|
125
|
-
}`
|
|
126
|
-
)
|
|
127
|
-
.join('\n');
|
|
128
|
-
|
|
129
|
-
return `Cannot import ${stack.at(-1)?.id} into public-facing code:\n${pyramid}`;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/** @implements {ImportGraph} */
|
|
134
|
-
export class RollupImportGraph {
|
|
135
|
-
/** @type {(id: string) => import('rollup').ModuleInfo | null} */
|
|
136
|
-
#node_getter;
|
|
137
|
-
|
|
138
|
-
/** @type {import('rollup').ModuleInfo} */
|
|
139
|
-
#module_info;
|
|
140
|
-
|
|
141
|
-
/** @type {string} */
|
|
142
|
-
id;
|
|
143
|
-
|
|
144
|
-
/** @type {boolean} */
|
|
145
|
-
dynamic;
|
|
146
|
-
|
|
147
|
-
/** @type {Set<string>} */
|
|
148
|
-
#seen;
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* @param {(id: string) => import('rollup').ModuleInfo | null} node_getter
|
|
152
|
-
* @param {import('rollup').ModuleInfo} node
|
|
153
|
-
*/
|
|
154
|
-
constructor(node_getter, node) {
|
|
155
|
-
this.#node_getter = node_getter;
|
|
156
|
-
this.#module_info = node;
|
|
157
|
-
this.id = remove_query_from_id(normalizePath(node.id));
|
|
158
|
-
this.dynamic = false;
|
|
159
|
-
this.#seen = new Set();
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* @param {(id: string) => import('rollup').ModuleInfo | null} node_getter
|
|
164
|
-
* @param {import('rollup').ModuleInfo} node
|
|
165
|
-
* @param {boolean} dynamic
|
|
166
|
-
* @param {Set<string>} seen;
|
|
167
|
-
* @returns {RollupImportGraph}
|
|
168
|
-
*/
|
|
169
|
-
static #new_internal(node_getter, node, dynamic, seen) {
|
|
170
|
-
const instance = new RollupImportGraph(node_getter, node);
|
|
171
|
-
instance.dynamic = dynamic;
|
|
172
|
-
instance.#seen = seen;
|
|
173
|
-
return instance;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
get children() {
|
|
177
|
-
return this.#children();
|
|
69
|
+
for (const child of module.dynamicallyImportedIds) {
|
|
70
|
+
follow(child, [...chain, { id, dynamic: true }]);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
178
73
|
}
|
|
179
74
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
const child = this.#node_getter(id);
|
|
185
|
-
if (child === null) return;
|
|
186
|
-
yield RollupImportGraph.#new_internal(this.#node_getter, child, false, this.#seen);
|
|
187
|
-
}
|
|
188
|
-
for (const id of this.#module_info.dynamicallyImportedIds) {
|
|
189
|
-
const child = this.#node_getter(id);
|
|
190
|
-
if (child === null) return;
|
|
191
|
-
yield RollupImportGraph.#new_internal(this.#node_getter, child, true, this.#seen);
|
|
75
|
+
return {
|
|
76
|
+
/** @param {string} id should be posixified */
|
|
77
|
+
check: (id) => {
|
|
78
|
+
follow(id, []);
|
|
192
79
|
}
|
|
193
|
-
}
|
|
80
|
+
};
|
|
194
81
|
}
|
|
195
82
|
|
|
196
|
-
/**
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
id;
|
|
206
|
-
|
|
207
|
-
/** @type {Set<string>} */
|
|
208
|
-
#seen;
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* @param {Set<string>} module_types Module types to analyze, eg '.js', '.ts', etc.
|
|
212
|
-
* @param {import('vite').ModuleNode} node
|
|
213
|
-
*/
|
|
214
|
-
constructor(module_types, node) {
|
|
215
|
-
this.#module_types = module_types;
|
|
216
|
-
this.#module_info = node;
|
|
217
|
-
this.id = remove_query_from_id(normalizePath(node.id ?? ''));
|
|
218
|
-
this.#seen = new Set();
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* @param {Set<string>} module_types Module types to analyze, eg '.js', '.ts', etc.
|
|
223
|
-
* @param {import('vite').ModuleNode} node
|
|
224
|
-
* @param {Set<string>} seen
|
|
225
|
-
* @returns {ViteImportGraph}
|
|
226
|
-
*/
|
|
227
|
-
static #new_internal(module_types, node, seen) {
|
|
228
|
-
const instance = new ViteImportGraph(module_types, node);
|
|
229
|
-
instance.#seen = seen;
|
|
230
|
-
return instance;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
get dynamic() {
|
|
234
|
-
return false;
|
|
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');
|
|
235
92
|
}
|
|
236
93
|
|
|
237
|
-
|
|
238
|
-
|
|
94
|
+
if (id.startsWith(cwd)) {
|
|
95
|
+
id = path.relative(cwd, id);
|
|
239
96
|
}
|
|
240
97
|
|
|
241
|
-
|
|
242
|
-
if (this.#seen.has(this.id)) return;
|
|
243
|
-
this.#seen.add(this.id);
|
|
244
|
-
for (const child of this.#module_info.importedModules) {
|
|
245
|
-
if (!this.#module_types.has(path.extname(this.id))) {
|
|
246
|
-
continue;
|
|
247
|
-
}
|
|
248
|
-
yield ViteImportGraph.#new_internal(this.#module_types, child, this.#seen);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* Throw an error if a private module is imported from a client-side node.
|
|
255
|
-
* @param {(id: string) => import('rollup').ModuleInfo | null} node_getter
|
|
256
|
-
* @param {import('rollup').ModuleInfo} node
|
|
257
|
-
* @param {string} lib_dir
|
|
258
|
-
* @returns {void}
|
|
259
|
-
*/
|
|
260
|
-
export function prevent_illegal_rollup_imports(node_getter, node, lib_dir) {
|
|
261
|
-
const graph = new RollupImportGraph(node_getter, node);
|
|
262
|
-
const guard = new IllegalModuleGuard(lib_dir);
|
|
263
|
-
guard.assert_legal(graph);
|
|
98
|
+
return posixify(id);
|
|
264
99
|
}
|
|
265
100
|
|
|
266
101
|
/**
|
|
267
|
-
*
|
|
268
|
-
* @param {
|
|
269
|
-
* @param {string} lib_dir
|
|
270
|
-
* @param {Iterable<string>} module_types File extensions to analyze in addition to the defaults: `.ts`, `.js`, etc.
|
|
271
|
-
* @returns {void}
|
|
102
|
+
* @param {string} str
|
|
103
|
+
* @param {number} times
|
|
272
104
|
*/
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
const guard = new IllegalModuleGuard(lib_dir);
|
|
276
|
-
guard.assert_legal(graph);
|
|
105
|
+
function repeat(str, times) {
|
|
106
|
+
return new Array(times + 1).join(str);
|
|
277
107
|
}
|
|
@@ -4,27 +4,3 @@ const query_pattern = /\?.*$/s;
|
|
|
4
4
|
export function remove_query_from_id(path) {
|
|
5
5
|
return path.replace(query_pattern, '');
|
|
6
6
|
}
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Vite does some weird things with import trees in dev
|
|
10
|
-
* for example, a Tailwind app.css will appear to import
|
|
11
|
-
* every file in the project. This isn't a problem for
|
|
12
|
-
* Rollup during build.
|
|
13
|
-
* @param {Iterable<string>} config_module_types
|
|
14
|
-
*/
|
|
15
|
-
export const get_module_types = (config_module_types) => {
|
|
16
|
-
return new Set([
|
|
17
|
-
'',
|
|
18
|
-
'.ts',
|
|
19
|
-
'.js',
|
|
20
|
-
'.svelte',
|
|
21
|
-
'.mts',
|
|
22
|
-
'.mjs',
|
|
23
|
-
'.cts',
|
|
24
|
-
'.cjs',
|
|
25
|
-
'.svelte.md',
|
|
26
|
-
'.svx',
|
|
27
|
-
'.md',
|
|
28
|
-
...config_module_types
|
|
29
|
-
]);
|
|
30
|
-
};
|
|
@@ -15,9 +15,9 @@ import { runtime_directory, logger } from '../../core/utils.js';
|
|
|
15
15
|
import { find_deps, get_default_build_config } from './build/utils.js';
|
|
16
16
|
import { preview } from './preview/index.js';
|
|
17
17
|
import { get_config_aliases, get_app_aliases, get_env } from './utils.js';
|
|
18
|
-
import { prevent_illegal_rollup_imports } from './graph_analysis/index.js';
|
|
19
18
|
import { fileURLToPath } from 'node:url';
|
|
20
19
|
import { create_static_module, create_dynamic_module } from '../../core/env.js';
|
|
20
|
+
import { is_illegal, module_guard, normalize_id } from './graph_analysis/index.js';
|
|
21
21
|
|
|
22
22
|
const cwd = process.cwd();
|
|
23
23
|
|
|
@@ -292,7 +292,22 @@ function kit() {
|
|
|
292
292
|
if (id.startsWith('$env/')) return `\0${id}`;
|
|
293
293
|
},
|
|
294
294
|
|
|
295
|
-
async load(id) {
|
|
295
|
+
async load(id, options) {
|
|
296
|
+
if (options?.ssr === false) {
|
|
297
|
+
const normalized_cwd = vite.normalizePath(cwd);
|
|
298
|
+
const normalized_lib = vite.normalizePath(svelte_config.kit.files.lib);
|
|
299
|
+
if (
|
|
300
|
+
is_illegal(id, {
|
|
301
|
+
cwd: normalized_cwd,
|
|
302
|
+
node_modules: vite.normalizePath(path.join(cwd, 'node_modules')),
|
|
303
|
+
server: vite.normalizePath(path.join(normalized_lib, 'server'))
|
|
304
|
+
})
|
|
305
|
+
) {
|
|
306
|
+
const relative = normalize_id(id, normalized_lib, normalized_cwd);
|
|
307
|
+
throw new Error(`Cannot import ${relative} into client-side code`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
296
311
|
switch (id) {
|
|
297
312
|
case '\0$env/static/private':
|
|
298
313
|
return create_static_module('$env/static/private', env.private);
|
|
@@ -350,20 +365,17 @@ function kit() {
|
|
|
350
365
|
return;
|
|
351
366
|
}
|
|
352
367
|
|
|
368
|
+
const guard = module_guard(this, {
|
|
369
|
+
cwd: vite.normalizePath(process.cwd()),
|
|
370
|
+
lib: vite.normalizePath(svelte_config.kit.files.lib)
|
|
371
|
+
});
|
|
372
|
+
|
|
353
373
|
manifest_data.nodes.forEach((_node, i) => {
|
|
354
374
|
const id = vite.normalizePath(
|
|
355
375
|
path.resolve(svelte_config.kit.outDir, `generated/nodes/${i}.js`)
|
|
356
376
|
);
|
|
357
377
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
if (module_node) {
|
|
361
|
-
prevent_illegal_rollup_imports(
|
|
362
|
-
this.getModuleInfo.bind(this),
|
|
363
|
-
module_node,
|
|
364
|
-
vite.normalizePath(svelte_config.kit.files.lib)
|
|
365
|
-
);
|
|
366
|
-
}
|
|
378
|
+
guard.check(id);
|
|
367
379
|
});
|
|
368
380
|
|
|
369
381
|
const verbose = vite_config.logLevel === 'info';
|
|
@@ -100,27 +100,24 @@ export async function preview(vite, vite_config, svelte_config) {
|
|
|
100
100
|
|
|
101
101
|
const { pathname } = new URL(/** @type {string} */ (req.url), 'http://dummy');
|
|
102
102
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
(pathname.endsWith('/') ? 'index.html' : '.html')
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
if (fs.existsSync(file)) {
|
|
113
|
-
res.writeHead(200, {
|
|
114
|
-
'content-type': 'text/html',
|
|
115
|
-
etag
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
fs.createReadStream(file).pipe(res);
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
103
|
+
let filename = join(svelte_config.kit.outDir, 'output/prerendered/pages' + pathname);
|
|
104
|
+
let prerendered = is_file(filename);
|
|
105
|
+
|
|
106
|
+
if (!prerendered) {
|
|
107
|
+
filename += filename.endsWith('/') ? 'index.html' : '.html';
|
|
108
|
+
prerendered = is_file(filename);
|
|
121
109
|
}
|
|
122
110
|
|
|
123
|
-
|
|
111
|
+
if (prerendered) {
|
|
112
|
+
res.writeHead(200, {
|
|
113
|
+
'content-type': 'text/html',
|
|
114
|
+
etag
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
fs.createReadStream(filename).pipe(res);
|
|
118
|
+
} else {
|
|
119
|
+
next();
|
|
120
|
+
}
|
|
124
121
|
})
|
|
125
122
|
);
|
|
126
123
|
|
|
@@ -187,3 +184,8 @@ function scoped(scope, handler) {
|
|
|
187
184
|
}
|
|
188
185
|
};
|
|
189
186
|
}
|
|
187
|
+
|
|
188
|
+
/** @param {string} path */
|
|
189
|
+
function is_file(path) {
|
|
190
|
+
return fs.existsSync(path) && !fs.statSync(path).isDirectory();
|
|
191
|
+
}
|
|
@@ -373,6 +373,8 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
373
373
|
|
|
374
374
|
/** @param {import('./types').NavigationFinished} result */
|
|
375
375
|
function initialize(result) {
|
|
376
|
+
if (__SVELTEKIT_DEV__ && document.querySelector('vite-error-overlay')) return;
|
|
377
|
+
|
|
376
378
|
current = result.state;
|
|
377
379
|
|
|
378
380
|
const style = document.querySelector('style[data-sveltekit]');
|
|
@@ -485,6 +487,12 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
485
487
|
};
|
|
486
488
|
|
|
487
489
|
// TODO remove this for 1.0
|
|
490
|
+
Object.defineProperty(result.props.page, 'routeId', {
|
|
491
|
+
get() {
|
|
492
|
+
throw new Error('$page.routeId has been replaced by $page.route.id');
|
|
493
|
+
},
|
|
494
|
+
enumerable: false
|
|
495
|
+
});
|
|
488
496
|
/**
|
|
489
497
|
* @param {string} property
|
|
490
498
|
* @param {string} replacement
|
|
@@ -599,8 +607,8 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
599
607
|
|
|
600
608
|
// prerendered pages may be served from any origin, so `initial_fetch` urls shouldn't be resolved
|
|
601
609
|
return started
|
|
602
|
-
? subsequent_fetch(resolved, init)
|
|
603
|
-
: initial_fetch(requested,
|
|
610
|
+
? subsequent_fetch(requested, resolved, init)
|
|
611
|
+
: initial_fetch(requested, init);
|
|
604
612
|
},
|
|
605
613
|
setHeaders: () => {}, // noop
|
|
606
614
|
depends,
|
|
@@ -1353,9 +1361,9 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
1353
1361
|
|
|
1354
1362
|
/** @param {Event} event */
|
|
1355
1363
|
const trigger_prefetch = (event) => {
|
|
1356
|
-
const { url, options } = find_anchor(event);
|
|
1357
|
-
if (url && options.prefetch) {
|
|
1358
|
-
if (
|
|
1364
|
+
const { url, options, has } = find_anchor(event);
|
|
1365
|
+
if (url && options.prefetch && !is_external_url(url)) {
|
|
1366
|
+
if (options.reload || has.rel_external || has.target || has.download) return;
|
|
1359
1367
|
prefetch(url);
|
|
1360
1368
|
}
|
|
1361
1369
|
};
|
|
@@ -1387,7 +1395,7 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
1387
1395
|
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
|
1388
1396
|
if (event.defaultPrevented) return;
|
|
1389
1397
|
|
|
1390
|
-
const { a, url, options } = find_anchor(event);
|
|
1398
|
+
const { a, url, options, has } = find_anchor(event);
|
|
1391
1399
|
if (!a || !url) return;
|
|
1392
1400
|
|
|
1393
1401
|
const is_svg_a_element = a instanceof SVGAElement;
|
|
@@ -1407,15 +1415,10 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
1407
1415
|
)
|
|
1408
1416
|
return;
|
|
1409
1417
|
|
|
1410
|
-
if (
|
|
1418
|
+
if (has.download) return;
|
|
1411
1419
|
|
|
1412
1420
|
// Ignore the following but fire beforeNavigate
|
|
1413
|
-
|
|
1414
|
-
if (
|
|
1415
|
-
rel.includes('external') ||
|
|
1416
|
-
options.reload ||
|
|
1417
|
-
(is_svg_a_element ? a.target.baseVal : a.target)
|
|
1418
|
-
) {
|
|
1421
|
+
if (options.reload || has.rel_external || has.target) {
|
|
1419
1422
|
const navigation = before_navigate({ url, type: 'link' });
|
|
1420
1423
|
if (!navigation) {
|
|
1421
1424
|
event.preventDefault();
|
|
@@ -63,24 +63,17 @@ const cache = new Map();
|
|
|
63
63
|
* Should be called on the initial run of load functions that hydrate the page.
|
|
64
64
|
* Saves any requests with cache-control max-age to the cache.
|
|
65
65
|
* @param {RequestInfo | URL} resource
|
|
66
|
-
* @param {string} resolved
|
|
67
66
|
* @param {RequestInit} [opts]
|
|
68
67
|
*/
|
|
69
|
-
export function initial_fetch(resource,
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
let selector = `script[data-sveltekit-fetched][data-url=${url}]`;
|
|
73
|
-
|
|
74
|
-
if (opts?.body && (typeof opts.body === 'string' || ArrayBuffer.isView(opts.body))) {
|
|
75
|
-
selector += `[data-hash="${hash(opts.body)}"]`;
|
|
76
|
-
}
|
|
68
|
+
export function initial_fetch(resource, opts) {
|
|
69
|
+
const selector = build_selector(resource, opts);
|
|
77
70
|
|
|
78
71
|
const script = document.querySelector(selector);
|
|
79
72
|
if (script?.textContent) {
|
|
80
73
|
const { body, ...init } = JSON.parse(script.textContent);
|
|
81
74
|
|
|
82
75
|
const ttl = script.getAttribute('data-ttl');
|
|
83
|
-
if (ttl) cache.set(
|
|
76
|
+
if (ttl) cache.set(selector, { body, init, ttl: 1000 * Number(ttl) });
|
|
84
77
|
|
|
85
78
|
return Promise.resolve(new Response(body, init));
|
|
86
79
|
}
|
|
@@ -90,18 +83,39 @@ export function initial_fetch(resource, resolved, opts) {
|
|
|
90
83
|
|
|
91
84
|
/**
|
|
92
85
|
* Tries to get the response from the cache, if max-age allows it, else does a fetch.
|
|
86
|
+
* @param {RequestInfo | URL} resource
|
|
93
87
|
* @param {string} resolved
|
|
94
88
|
* @param {RequestInit} [opts]
|
|
95
89
|
*/
|
|
96
|
-
export function subsequent_fetch(resolved, opts) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
90
|
+
export function subsequent_fetch(resource, resolved, opts) {
|
|
91
|
+
if (cache.size > 0) {
|
|
92
|
+
const selector = build_selector(resource, opts);
|
|
93
|
+
const cached = cache.get(selector);
|
|
94
|
+
if (cached) {
|
|
95
|
+
if (performance.now() < cached.ttl) {
|
|
96
|
+
return new Response(cached.body, cached.init);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
cache.delete(selector);
|
|
101
100
|
}
|
|
102
|
-
|
|
103
|
-
cache.delete(resolved);
|
|
104
101
|
}
|
|
105
102
|
|
|
106
103
|
return native_fetch(resolved, opts);
|
|
107
104
|
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Build the cache key for a given request
|
|
108
|
+
* @param {RequestInfo | URL} resource
|
|
109
|
+
* @param {RequestInit} [opts]
|
|
110
|
+
*/
|
|
111
|
+
function build_selector(resource, opts) {
|
|
112
|
+
const url = JSON.stringify(resource instanceof Request ? resource.url : resource);
|
|
113
|
+
|
|
114
|
+
let selector = `script[data-sveltekit-fetched][data-url=${url}]`;
|
|
115
|
+
|
|
116
|
+
if (opts?.body && (typeof opts.body === 'string' || ArrayBuffer.isView(opts.body))) {
|
|
117
|
+
selector += `[data-hash="${hash(opts.body)}"]`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return selector;
|
|
121
|
+
}
|
|
@@ -58,7 +58,14 @@ export function find_anchor(event) {
|
|
|
58
58
|
noscroll,
|
|
59
59
|
prefetch,
|
|
60
60
|
reload
|
|
61
|
-
}
|
|
61
|
+
},
|
|
62
|
+
has: a
|
|
63
|
+
? {
|
|
64
|
+
rel_external: (a.getAttribute('rel') || '').split(/\s+/).includes('external'),
|
|
65
|
+
download: a.hasAttribute('download'),
|
|
66
|
+
target: !!(a instanceof SVGAElement ? a.target.baseVal : a.target)
|
|
67
|
+
}
|
|
68
|
+
: {}
|
|
62
69
|
};
|
|
63
70
|
}
|
|
64
71
|
|
package/src/utils/routing.js
CHANGED
|
@@ -72,11 +72,6 @@ export function parse_route_id(id) {
|
|
|
72
72
|
return (
|
|
73
73
|
content // allow users to specify characters on the file system in an encoded manner
|
|
74
74
|
.normalize()
|
|
75
|
-
// We use [ and ] to denote parameters, so users must encode these on the file
|
|
76
|
-
// system to match against them. We don't decode all characters since others
|
|
77
|
-
// can already be epressed and so that '%' can be easily used directly in filenames
|
|
78
|
-
.replace(/%5[Bb]/g, '[')
|
|
79
|
-
.replace(/%5[Dd]/g, ']')
|
|
80
75
|
// '#', '/', and '?' can only appear in URL path segments in an encoded manner.
|
|
81
76
|
// They will not be touched by decodeURI so need to be encoded here, so
|
|
82
77
|
// that we can match against them.
|