@sveltejs/kit 1.0.0-next.48 → 1.0.0-next.480
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 +12 -9
- package/package.json +93 -64
- package/scripts/special-types/$env+dynamic+private.md +10 -0
- package/scripts/special-types/$env+dynamic+public.md +8 -0
- package/scripts/special-types/$env+static+private.md +19 -0
- package/scripts/special-types/$env+static+public.md +7 -0
- package/scripts/special-types/$lib.md +1 -0
- package/src/cli.js +112 -0
- package/src/constants.js +7 -0
- package/src/core/adapt/builder.js +207 -0
- package/src/core/adapt/index.js +31 -0
- package/src/core/config/default-error.html +56 -0
- package/src/core/config/index.js +110 -0
- package/src/core/config/options.js +504 -0
- package/src/core/config/types.d.ts +1 -0
- package/src/core/env.js +121 -0
- package/src/core/generate_manifest/index.js +92 -0
- package/src/core/prerender/crawl.js +194 -0
- package/src/core/prerender/prerender.js +431 -0
- package/src/core/prerender/queue.js +80 -0
- package/src/core/sync/create_manifest_data/index.js +472 -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 +53 -0
- package/src/core/sync/write_client_manifest.js +106 -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 +673 -0
- package/src/core/utils.js +70 -0
- package/src/exports/hooks/index.js +1 -0
- package/src/exports/hooks/sequence.js +44 -0
- package/src/exports/index.js +45 -0
- package/src/exports/node/index.js +163 -0
- package/src/exports/node/polyfills.js +41 -0
- package/src/exports/vite/build/build_server.js +372 -0
- package/src/exports/vite/build/build_service_worker.js +90 -0
- package/src/exports/vite/build/utils.js +162 -0
- package/src/exports/vite/dev/index.js +576 -0
- package/src/exports/vite/index.js +597 -0
- package/src/exports/vite/preview/index.js +189 -0
- package/src/exports/vite/types.d.ts +3 -0
- package/src/exports/vite/utils.js +438 -0
- package/src/runtime/app/env.js +1 -0
- package/src/runtime/app/environment.js +11 -0
- package/src/runtime/app/forms.js +108 -0
- package/src/runtime/app/navigation.js +23 -0
- package/src/runtime/app/paths.js +1 -0
- package/src/runtime/app/stores.js +102 -0
- package/src/runtime/client/ambient.d.ts +26 -0
- package/src/runtime/client/client.js +1569 -0
- package/src/runtime/client/fetcher.js +107 -0
- package/src/runtime/client/parse.js +60 -0
- package/src/runtime/client/singletons.js +21 -0
- package/src/runtime/client/start.js +37 -0
- package/src/runtime/client/types.d.ts +85 -0
- package/src/runtime/client/utils.js +159 -0
- package/src/runtime/components/error.svelte +16 -0
- package/{assets → src/runtime}/components/layout.svelte +0 -0
- package/src/runtime/control.js +98 -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 +6 -0
- package/src/runtime/hash.js +16 -0
- package/src/runtime/paths.js +11 -0
- package/src/runtime/server/cookie.js +77 -0
- package/src/runtime/server/data/index.js +136 -0
- package/src/runtime/server/endpoint.js +66 -0
- package/src/runtime/server/index.js +343 -0
- package/src/runtime/server/page/actions.js +243 -0
- package/src/runtime/server/page/crypto.js +239 -0
- package/src/runtime/server/page/csp.js +249 -0
- package/src/runtime/server/page/fetch.js +286 -0
- package/src/runtime/server/page/index.js +304 -0
- package/src/runtime/server/page/load_data.js +124 -0
- package/src/runtime/server/page/render.js +346 -0
- package/src/runtime/server/page/respond_with_error.js +92 -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 +178 -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/filesystem.js +137 -0
- package/src/utils/functions.js +16 -0
- package/src/utils/http.js +55 -0
- package/src/utils/misc.js +1 -0
- package/src/utils/routing.js +117 -0
- package/src/utils/url.js +142 -0
- package/svelte-kit.js +1 -1
- package/types/ambient.d.ts +426 -0
- package/types/index.d.ts +410 -0
- package/types/internal.d.ts +384 -0
- package/types/private.d.ts +210 -0
- package/CHANGELOG.md +0 -469
- package/assets/components/error.svelte +0 -13
- package/assets/runtime/app/env.js +0 -5
- package/assets/runtime/app/navigation.js +0 -44
- package/assets/runtime/app/paths.js +0 -1
- package/assets/runtime/app/stores.js +0 -93
- package/assets/runtime/chunks/utils.js +0 -22
- package/assets/runtime/internal/singletons.js +0 -23
- package/assets/runtime/internal/start.js +0 -773
- package/assets/runtime/paths.js +0 -12
- package/dist/chunks/index.js +0 -3517
- package/dist/chunks/index2.js +0 -587
- package/dist/chunks/index3.js +0 -246
- package/dist/chunks/index4.js +0 -530
- package/dist/chunks/index5.js +0 -763
- package/dist/chunks/index6.js +0 -322
- package/dist/chunks/standard.js +0 -99
- package/dist/chunks/utils.js +0 -83
- package/dist/cli.js +0 -553
- package/dist/ssr.js +0 -2581
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import sirv from 'sirv';
|
|
4
|
+
import { pathToFileURL } from 'url';
|
|
5
|
+
import { getRequest, setResponse } from '../../../exports/node/index.js';
|
|
6
|
+
import { installPolyfills } from '../../../exports/node/polyfills.js';
|
|
7
|
+
import { SVELTE_KIT_ASSETS } from '../../../constants.js';
|
|
8
|
+
import { loadEnv } from 'vite';
|
|
9
|
+
|
|
10
|
+
/** @typedef {import('http').IncomingMessage} Req */
|
|
11
|
+
/** @typedef {import('http').ServerResponse} Res */
|
|
12
|
+
/** @typedef {(req: Req, res: Res, next: () => void) => void} Handler */
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {{
|
|
16
|
+
* middlewares: import('connect').Server;
|
|
17
|
+
* httpServer: import('http').Server;
|
|
18
|
+
* }} vite
|
|
19
|
+
* @param {import('vite').ResolvedConfig} vite_config
|
|
20
|
+
* @param {import('types').ValidatedConfig} svelte_config
|
|
21
|
+
*/
|
|
22
|
+
export async function preview(vite, vite_config, svelte_config) {
|
|
23
|
+
installPolyfills();
|
|
24
|
+
|
|
25
|
+
const { paths } = svelte_config.kit;
|
|
26
|
+
const base = paths.base;
|
|
27
|
+
const assets = paths.assets ? SVELTE_KIT_ASSETS : paths.base;
|
|
28
|
+
|
|
29
|
+
const protocol = vite_config.preview.https ? 'https' : 'http';
|
|
30
|
+
|
|
31
|
+
const etag = `"${Date.now()}"`;
|
|
32
|
+
|
|
33
|
+
const index_file = join(svelte_config.kit.outDir, 'output/server/index.js');
|
|
34
|
+
const manifest_file = join(svelte_config.kit.outDir, 'output/server/manifest.js');
|
|
35
|
+
|
|
36
|
+
/** @type {import('types').ServerModule} */
|
|
37
|
+
const { Server, override } = await import(pathToFileURL(index_file).href);
|
|
38
|
+
const { manifest } = await import(pathToFileURL(manifest_file).href);
|
|
39
|
+
|
|
40
|
+
override({
|
|
41
|
+
paths: { base, assets },
|
|
42
|
+
prerendering: false,
|
|
43
|
+
protocol,
|
|
44
|
+
read: (file) => fs.readFileSync(join(svelte_config.kit.files.assets, file))
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const server = new Server(manifest);
|
|
48
|
+
await server.init({
|
|
49
|
+
env: loadEnv(vite_config.mode, process.cwd(), '')
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return () => {
|
|
53
|
+
// generated client assets and the contents of `static`
|
|
54
|
+
vite.middlewares.use(
|
|
55
|
+
scoped(
|
|
56
|
+
assets,
|
|
57
|
+
sirv(join(svelte_config.kit.outDir, 'output/client'), {
|
|
58
|
+
setHeaders: (res, pathname) => {
|
|
59
|
+
// only apply to immutable directory, not e.g. version.json
|
|
60
|
+
if (pathname.startsWith(`/${svelte_config.kit.appDir}/immutable`)) {
|
|
61
|
+
res.setHeader('cache-control', 'public,max-age=31536000,immutable');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
)
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
vite.middlewares.use((req, res, next) => {
|
|
69
|
+
const original_url = /** @type {string} */ (req.url);
|
|
70
|
+
const { pathname } = new URL(original_url, 'http://dummy');
|
|
71
|
+
|
|
72
|
+
if (pathname.startsWith(base)) {
|
|
73
|
+
next();
|
|
74
|
+
} else {
|
|
75
|
+
res.statusCode = 404;
|
|
76
|
+
res.end(`Not found (did you mean ${base + pathname}?)`);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// prerendered dependencies
|
|
81
|
+
vite.middlewares.use(
|
|
82
|
+
scoped(base, mutable(join(svelte_config.kit.outDir, 'output/prerendered/dependencies')))
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
// prerendered pages (we can't just use sirv because we need to
|
|
86
|
+
// preserve the correct trailingSlash behaviour)
|
|
87
|
+
vite.middlewares.use(
|
|
88
|
+
scoped(base, (req, res, next) => {
|
|
89
|
+
let if_none_match_value = req.headers['if-none-match'];
|
|
90
|
+
|
|
91
|
+
if (if_none_match_value?.startsWith('W/"')) {
|
|
92
|
+
if_none_match_value = if_none_match_value.substring(2);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (if_none_match_value === etag) {
|
|
96
|
+
res.statusCode = 304;
|
|
97
|
+
res.end();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const { pathname } = new URL(/** @type {string} */ (req.url), 'http://dummy');
|
|
102
|
+
|
|
103
|
+
// only treat this as a page if it doesn't include an extension
|
|
104
|
+
if (pathname === '/' || /\/[^./]+\/?$/.test(pathname)) {
|
|
105
|
+
const file = join(
|
|
106
|
+
svelte_config.kit.outDir,
|
|
107
|
+
'output/prerendered/pages' +
|
|
108
|
+
pathname +
|
|
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
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
next();
|
|
124
|
+
})
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
// SSR
|
|
128
|
+
vite.middlewares.use(async (req, res) => {
|
|
129
|
+
const host = req.headers['host'];
|
|
130
|
+
|
|
131
|
+
let request;
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
request = await getRequest({
|
|
135
|
+
base: `${protocol}://${host}`,
|
|
136
|
+
request: req
|
|
137
|
+
});
|
|
138
|
+
} catch (/** @type {any} */ err) {
|
|
139
|
+
res.statusCode = err.status || 400;
|
|
140
|
+
return res.end(err.message || 'Invalid request body');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
setResponse(
|
|
144
|
+
res,
|
|
145
|
+
await server.respond(request, {
|
|
146
|
+
getClientAddress: () => {
|
|
147
|
+
const { remoteAddress } = req.socket;
|
|
148
|
+
if (remoteAddress) return remoteAddress;
|
|
149
|
+
throw new Error('Could not determine clientAddress');
|
|
150
|
+
}
|
|
151
|
+
})
|
|
152
|
+
);
|
|
153
|
+
});
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* @param {string} dir
|
|
159
|
+
* @returns {Handler}
|
|
160
|
+
*/
|
|
161
|
+
const mutable = (dir) =>
|
|
162
|
+
fs.existsSync(dir)
|
|
163
|
+
? sirv(dir, {
|
|
164
|
+
etag: true,
|
|
165
|
+
maxAge: 0
|
|
166
|
+
})
|
|
167
|
+
: (_req, _res, next) => next();
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* @param {string} scope
|
|
171
|
+
* @param {Handler} handler
|
|
172
|
+
* @returns {Handler}
|
|
173
|
+
*/
|
|
174
|
+
function scoped(scope, handler) {
|
|
175
|
+
if (scope === '') return handler;
|
|
176
|
+
|
|
177
|
+
return (req, res, next) => {
|
|
178
|
+
if (req.url?.startsWith(scope)) {
|
|
179
|
+
const original_url = req.url;
|
|
180
|
+
req.url = req.url.slice(scope.length);
|
|
181
|
+
handler(req, res, () => {
|
|
182
|
+
req.url = original_url;
|
|
183
|
+
next();
|
|
184
|
+
});
|
|
185
|
+
} else {
|
|
186
|
+
next();
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
}
|
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { loadConfigFromFile, loadEnv, normalizePath } from 'vite';
|
|
3
|
+
import { runtime_directory } from '../../core/utils.js';
|
|
4
|
+
import { posixify } from '../../utils/filesystem.js';
|
|
5
|
+
|
|
6
|
+
class IllegalModuleGuard {
|
|
7
|
+
/** @type {string} */
|
|
8
|
+
#lib_dir;
|
|
9
|
+
|
|
10
|
+
/** @type {string} */
|
|
11
|
+
#server_dir;
|
|
12
|
+
|
|
13
|
+
/** @type {string} */
|
|
14
|
+
#node_modules_dir = normalizePath(path.resolve(process.cwd(), 'node_modules'));
|
|
15
|
+
|
|
16
|
+
/** @type {string} */
|
|
17
|
+
#cwd = normalizePath(process.cwd());
|
|
18
|
+
|
|
19
|
+
/** @type {Set<string>} */
|
|
20
|
+
#illegal_imports = new Set([
|
|
21
|
+
'/@id/__x00__$env/dynamic/private', //dev
|
|
22
|
+
'\0$env/dynamic/private', // prod
|
|
23
|
+
'/@id/__x00__$env/static/private', // dev
|
|
24
|
+
'\0$env/static/private' // prod
|
|
25
|
+
]);
|
|
26
|
+
|
|
27
|
+
/** @type {Array<import('types').ImportNode>} */
|
|
28
|
+
#chain = [];
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @param {string} lib_dir
|
|
32
|
+
*/
|
|
33
|
+
constructor(lib_dir) {
|
|
34
|
+
this.#lib_dir = normalizePath(lib_dir);
|
|
35
|
+
this.#server_dir = normalizePath(path.resolve(lib_dir, 'server'));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {import('types').ImportNode} node
|
|
40
|
+
* @returns {void}
|
|
41
|
+
*/
|
|
42
|
+
assert_legal(node) {
|
|
43
|
+
this.#chain.push(node);
|
|
44
|
+
for (const child of node.children) {
|
|
45
|
+
if (this.#is_illegal(child.name)) {
|
|
46
|
+
this.#chain.push(child);
|
|
47
|
+
throw new Error(this.#format_illegal_import_chain(this.#chain));
|
|
48
|
+
}
|
|
49
|
+
this.assert_legal(child);
|
|
50
|
+
}
|
|
51
|
+
this.#chain.pop();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* `true` if the provided ID represents a server-only module, else `false`.
|
|
56
|
+
* @param {string} module_id
|
|
57
|
+
* @returns {boolean}
|
|
58
|
+
*/
|
|
59
|
+
#is_illegal(module_id) {
|
|
60
|
+
if (this.#is_kit_illegal(module_id) || this.#is_user_illegal(module_id)) return true;
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* `true` if the provided ID represents a Kit-defined server-only module, else `false`.
|
|
66
|
+
* @param {string} module_id
|
|
67
|
+
* @returns {boolean}
|
|
68
|
+
*/
|
|
69
|
+
#is_kit_illegal(module_id) {
|
|
70
|
+
return this.#illegal_imports.has(module_id);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* `true` if the provided ID represents a user-defined server-only module, else `false`.
|
|
75
|
+
* @param {string} module_id
|
|
76
|
+
* @returns {boolean}
|
|
77
|
+
*/
|
|
78
|
+
#is_user_illegal(module_id) {
|
|
79
|
+
if (module_id.startsWith(this.#server_dir)) return true;
|
|
80
|
+
|
|
81
|
+
// files outside the project root are ignored
|
|
82
|
+
if (!module_id.startsWith(this.#cwd)) return false;
|
|
83
|
+
|
|
84
|
+
// so are files inside node_modules
|
|
85
|
+
if (module_id.startsWith(this.#node_modules_dir)) return false;
|
|
86
|
+
|
|
87
|
+
return /.*\.server\..+/.test(path.basename(module_id));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @param {string} str
|
|
92
|
+
* @param {number} times
|
|
93
|
+
*/
|
|
94
|
+
#repeat(str, times) {
|
|
95
|
+
return new Array(times + 1).join(str);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Create a formatted error for an illegal import.
|
|
100
|
+
* @param {Array<{name: string, dynamic: boolean}>} stack
|
|
101
|
+
*/
|
|
102
|
+
#format_illegal_import_chain(stack) {
|
|
103
|
+
const dev_virtual_prefix = '/@id/__x00__';
|
|
104
|
+
const prod_virtual_prefix = '\0';
|
|
105
|
+
|
|
106
|
+
stack = stack.map((file) => {
|
|
107
|
+
if (file.name.startsWith(dev_virtual_prefix)) {
|
|
108
|
+
return { ...file, name: file.name.replace(dev_virtual_prefix, '') };
|
|
109
|
+
}
|
|
110
|
+
if (file.name.startsWith(prod_virtual_prefix)) {
|
|
111
|
+
return { ...file, name: file.name.replace(prod_virtual_prefix, '') };
|
|
112
|
+
}
|
|
113
|
+
if (file.name.startsWith(this.#lib_dir)) {
|
|
114
|
+
return { ...file, name: file.name.replace(this.#lib_dir, '$lib') };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return { ...file, name: path.relative(process.cwd(), file.name) };
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const pyramid = stack
|
|
121
|
+
.map(
|
|
122
|
+
(file, i) =>
|
|
123
|
+
`${this.#repeat(' ', i * 2)}- ${file.name} ${
|
|
124
|
+
file.dynamic ? '(imported by parent dynamically)' : ''
|
|
125
|
+
}`
|
|
126
|
+
)
|
|
127
|
+
.join('\n');
|
|
128
|
+
|
|
129
|
+
return `Cannot import ${stack.at(-1)?.name} into client-side code:\n${pyramid}`;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
class RollupImportGraph {
|
|
134
|
+
/** @type {(id: string) => import('rollup').ModuleInfo | null} */
|
|
135
|
+
#node_getter;
|
|
136
|
+
|
|
137
|
+
/** @type {import('rollup').ModuleInfo} */
|
|
138
|
+
#module_info;
|
|
139
|
+
|
|
140
|
+
/** @type {string} */
|
|
141
|
+
name;
|
|
142
|
+
|
|
143
|
+
/** @type {boolean} */
|
|
144
|
+
dynamic;
|
|
145
|
+
|
|
146
|
+
/** @type {Set<string>} */
|
|
147
|
+
#seen;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* @param {(id: string) => import('rollup').ModuleInfo | null} node_getter
|
|
151
|
+
* @param {import('rollup').ModuleInfo} node
|
|
152
|
+
* @param {boolean} dynamic
|
|
153
|
+
* @param {Set<string>} seen
|
|
154
|
+
*/
|
|
155
|
+
constructor(node_getter, node, dynamic = false, seen = new Set()) {
|
|
156
|
+
this.#node_getter = node_getter;
|
|
157
|
+
this.#module_info = node;
|
|
158
|
+
this.name = remove_query_from_path(normalizePath(node.id));
|
|
159
|
+
this.dynamic = dynamic;
|
|
160
|
+
this.#seen = seen;
|
|
161
|
+
void (/** @type {import('types').ImportNode} */ (this));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
get children() {
|
|
165
|
+
return this.#children();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
*#children() {
|
|
169
|
+
if (this.#seen.has(this.name)) return;
|
|
170
|
+
this.#seen.add(this.name);
|
|
171
|
+
for (const id of this.#module_info.importedIds) {
|
|
172
|
+
const child = this.#node_getter(id);
|
|
173
|
+
if (child === null) return;
|
|
174
|
+
yield new RollupImportGraph(this.#node_getter, child, false, this.#seen);
|
|
175
|
+
}
|
|
176
|
+
for (const id of this.#module_info.dynamicallyImportedIds) {
|
|
177
|
+
const child = this.#node_getter(id);
|
|
178
|
+
if (child === null) return;
|
|
179
|
+
yield new RollupImportGraph(this.#node_getter, child, true, this.#seen);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
class ViteImportGraph {
|
|
185
|
+
/** @type {Set<string>} */
|
|
186
|
+
#module_types;
|
|
187
|
+
|
|
188
|
+
/** @type {import('vite').ModuleNode} */
|
|
189
|
+
#module_info;
|
|
190
|
+
|
|
191
|
+
/** @type {string} */
|
|
192
|
+
name;
|
|
193
|
+
|
|
194
|
+
/** @type {Set<string>} */
|
|
195
|
+
#seen;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* @param {Set<string>} module_types Module types to analyze, eg '.js', '.ts', etc.
|
|
199
|
+
* @param {import('vite').ModuleNode} node
|
|
200
|
+
* @param {Set<string>} seen
|
|
201
|
+
*/
|
|
202
|
+
constructor(module_types, node, seen = new Set()) {
|
|
203
|
+
this.#module_types = module_types;
|
|
204
|
+
this.#module_info = node;
|
|
205
|
+
this.name = remove_query_from_path(normalizePath(node.id ?? ''));
|
|
206
|
+
this.#seen = seen;
|
|
207
|
+
void (/** @type {import('types').ImportNode} */ (this));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
get dynamic() {
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
get children() {
|
|
215
|
+
return this.#children();
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
*#children() {
|
|
219
|
+
if (this.#seen.has(this.name)) return;
|
|
220
|
+
this.#seen.add(this.name);
|
|
221
|
+
for (const child of this.#module_info.importedModules) {
|
|
222
|
+
if (!this.#module_types.has(path.extname(this.name))) {
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
yield new ViteImportGraph(this.#module_types, child, this.#seen);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* @param {import('vite').ResolvedConfig} config
|
|
232
|
+
* @param {import('vite').ConfigEnv} config_env
|
|
233
|
+
* @return {Promise<import('vite').UserConfig>}
|
|
234
|
+
*/
|
|
235
|
+
export async function get_vite_config(config, config_env) {
|
|
236
|
+
const loaded = await loadConfigFromFile(
|
|
237
|
+
config_env,
|
|
238
|
+
config.configFile,
|
|
239
|
+
undefined,
|
|
240
|
+
config.logLevel
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
if (!loaded) {
|
|
244
|
+
throw new Error('Could not load Vite config');
|
|
245
|
+
}
|
|
246
|
+
return { ...loaded.config, mode: config_env.mode };
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* @param {...import('vite').UserConfig} configs
|
|
251
|
+
* @returns {import('vite').UserConfig}
|
|
252
|
+
*/
|
|
253
|
+
export function merge_vite_configs(...configs) {
|
|
254
|
+
return deep_merge(
|
|
255
|
+
...configs.map((config) => ({
|
|
256
|
+
...config,
|
|
257
|
+
resolve: {
|
|
258
|
+
...config.resolve,
|
|
259
|
+
alias: normalize_alias(config.resolve?.alias || {})
|
|
260
|
+
}
|
|
261
|
+
}))
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Takes zero or more objects and returns a new object that has all the values
|
|
267
|
+
* deeply merged together. None of the original objects will be mutated at any
|
|
268
|
+
* level, and the returned object will have no references to the original
|
|
269
|
+
* objects at any depth. If there's a conflict the last one wins, except for
|
|
270
|
+
* arrays which will be combined.
|
|
271
|
+
* @param {...Object} objects
|
|
272
|
+
* @returns {Record<string, any>} the merged object
|
|
273
|
+
*/
|
|
274
|
+
export function deep_merge(...objects) {
|
|
275
|
+
const result = {};
|
|
276
|
+
/** @type {string[]} */
|
|
277
|
+
objects.forEach((o) => merge_into(result, o));
|
|
278
|
+
return result;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* normalize kit.vite.resolve.alias as an array
|
|
283
|
+
* @param {import('vite').AliasOptions} o
|
|
284
|
+
* @returns {import('vite').Alias[]}
|
|
285
|
+
*/
|
|
286
|
+
function normalize_alias(o) {
|
|
287
|
+
if (Array.isArray(o)) return o;
|
|
288
|
+
return Object.entries(o).map(([find, replacement]) => ({ find, replacement }));
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Merges b into a, recursively, mutating a.
|
|
293
|
+
* @param {Record<string, any>} a
|
|
294
|
+
* @param {Record<string, any>} b
|
|
295
|
+
*/
|
|
296
|
+
function merge_into(a, b) {
|
|
297
|
+
/**
|
|
298
|
+
* Checks for "plain old Javascript object", typically made as an object
|
|
299
|
+
* literal. Excludes Arrays and built-in types like Buffer.
|
|
300
|
+
* @param {any} x
|
|
301
|
+
*/
|
|
302
|
+
const is_plain_object = (x) => typeof x === 'object' && x.constructor === Object;
|
|
303
|
+
|
|
304
|
+
for (const prop in b) {
|
|
305
|
+
if (is_plain_object(b[prop])) {
|
|
306
|
+
if (!is_plain_object(a[prop])) {
|
|
307
|
+
a[prop] = {};
|
|
308
|
+
}
|
|
309
|
+
merge_into(a[prop], b[prop]);
|
|
310
|
+
} else if (Array.isArray(b[prop])) {
|
|
311
|
+
if (!Array.isArray(a[prop])) {
|
|
312
|
+
a[prop] = [];
|
|
313
|
+
}
|
|
314
|
+
a[prop].push(...b[prop]);
|
|
315
|
+
} else {
|
|
316
|
+
a[prop] = b[prop];
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Transforms kit.alias to a valid vite.resolve.alias array.
|
|
323
|
+
* Related to tsconfig path alias creation.
|
|
324
|
+
*
|
|
325
|
+
* @param {import('types').ValidatedKitConfig} config
|
|
326
|
+
* */
|
|
327
|
+
export function get_aliases(config) {
|
|
328
|
+
/** @type {import('vite').Alias[]} */
|
|
329
|
+
const alias = [
|
|
330
|
+
{ find: '__GENERATED__', replacement: path.posix.join(config.outDir, 'generated') },
|
|
331
|
+
{ find: '$app', replacement: `${runtime_directory}/app` },
|
|
332
|
+
// For now, we handle `$lib` specially here rather than make it a default value for
|
|
333
|
+
// `config.kit.alias` since it has special meaning for packaging, etc.
|
|
334
|
+
{ find: '$lib', replacement: config.files.lib }
|
|
335
|
+
];
|
|
336
|
+
|
|
337
|
+
for (let [key, value] of Object.entries(config.alias)) {
|
|
338
|
+
value = posixify(value);
|
|
339
|
+
if (value.endsWith('/*')) {
|
|
340
|
+
value = value.slice(0, -2);
|
|
341
|
+
}
|
|
342
|
+
if (key.endsWith('/*')) {
|
|
343
|
+
// Doing just `{ find: key.slice(0, -2) ,..}` would mean `import .. from "key"` would also be matched, which we don't want
|
|
344
|
+
alias.push({
|
|
345
|
+
find: new RegExp(`^${escape_for_regexp(key.slice(0, -2))}\\/(.+)$`),
|
|
346
|
+
replacement: `${path.resolve(value)}/$1`
|
|
347
|
+
});
|
|
348
|
+
} else if (key + '/*' in config.alias) {
|
|
349
|
+
// key and key/* both exist -> the replacement for key needs to happen _only_ on import .. from "key"
|
|
350
|
+
alias.push({
|
|
351
|
+
find: new RegExp(`^${escape_for_regexp(key)}$`),
|
|
352
|
+
replacement: path.resolve(value)
|
|
353
|
+
});
|
|
354
|
+
} else {
|
|
355
|
+
alias.push({ find: key, replacement: path.resolve(value) });
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return alias;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* @param {string} str
|
|
364
|
+
*/
|
|
365
|
+
function escape_for_regexp(str) {
|
|
366
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, (match) => '\\' + match);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Load environment variables from process.env and .env files
|
|
371
|
+
* @param {import('types').ValidatedKitConfig['env']} env_config
|
|
372
|
+
* @param {string} mode
|
|
373
|
+
*/
|
|
374
|
+
export function get_env(env_config, mode) {
|
|
375
|
+
const entries = Object.entries(loadEnv(mode, env_config.dir, ''));
|
|
376
|
+
|
|
377
|
+
return {
|
|
378
|
+
public: Object.fromEntries(entries.filter(([k]) => k.startsWith(env_config.publicPrefix))),
|
|
379
|
+
private: Object.fromEntries(entries.filter(([k]) => !k.startsWith(env_config.publicPrefix)))
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const query_pattern = /\?.*$/s;
|
|
384
|
+
|
|
385
|
+
/** @param {string} path */
|
|
386
|
+
function remove_query_from_path(path) {
|
|
387
|
+
return path.replace(query_pattern, '');
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Vite does some weird things with import trees in dev
|
|
392
|
+
* for example, a Tailwind app.css will appear to import
|
|
393
|
+
* every file in the project. This isn't a problem for
|
|
394
|
+
* Rollup during build.
|
|
395
|
+
* @param {Iterable<string>} config_module_types
|
|
396
|
+
*/
|
|
397
|
+
const get_module_types = (config_module_types) => {
|
|
398
|
+
return new Set([
|
|
399
|
+
'',
|
|
400
|
+
'.ts',
|
|
401
|
+
'.js',
|
|
402
|
+
'.svelte',
|
|
403
|
+
'.mts',
|
|
404
|
+
'.mjs',
|
|
405
|
+
'.cts',
|
|
406
|
+
'.cjs',
|
|
407
|
+
'.svelte.md',
|
|
408
|
+
'.svx',
|
|
409
|
+
'.md',
|
|
410
|
+
...config_module_types
|
|
411
|
+
]);
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Throw an error if a private module is imported from a client-side node.
|
|
416
|
+
* @param {(id: string) => import('rollup').ModuleInfo | null} node_getter
|
|
417
|
+
* @param {import('rollup').ModuleInfo} node
|
|
418
|
+
* @param {string} lib_dir
|
|
419
|
+
* @returns {void}
|
|
420
|
+
*/
|
|
421
|
+
export function prevent_illegal_rollup_imports(node_getter, node, lib_dir) {
|
|
422
|
+
const graph = new RollupImportGraph(node_getter, node);
|
|
423
|
+
const guard = new IllegalModuleGuard(lib_dir);
|
|
424
|
+
guard.assert_legal(graph);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Throw an error if a private module is imported from a client-side node.
|
|
429
|
+
* @param {import('vite').ModuleNode} node
|
|
430
|
+
* @param {string} lib_dir
|
|
431
|
+
* @param {Iterable<string>} module_types File extensions to analyze in addition to the defaults: `.ts`, `.js`, etc.
|
|
432
|
+
* @returns {void}
|
|
433
|
+
*/
|
|
434
|
+
export function prevent_illegal_vite_imports(node, lib_dir, module_types) {
|
|
435
|
+
const graph = new ViteImportGraph(get_module_types(module_types), node);
|
|
436
|
+
const guard = new IllegalModuleGuard(lib_dir);
|
|
437
|
+
guard.assert_legal(graph);
|
|
438
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
throw new Error('$app/env has been renamed to $app/environment');
|