Skip to content

Commit c9cd1de

Browse files
Merge branch 'sveltejs:main' into cloudflare-workers-exports
2 parents ee87b35 + d0f2d7b commit c9cd1de

File tree

29 files changed

+758
-112
lines changed

29 files changed

+758
-112
lines changed

documentation/docs/20-core-concepts/40-page-options.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ export const ssr = false;
127127

128128
If you add `export const ssr = false` to your root `+layout.js`, your entire app will only be rendered on the client — which essentially means you turn your app into an SPA.
129129

130-
> [!NOTE] Even with `ssr` set to `false`, code that relies on browser APIs should be imported in your `+page.svelte` or `+layout.svelte` file instead. This is because page options can be overriden and need to be evaluated by importing your `+page.js` or `+layout.js` file on the server (if you have a runtime) or at build time (in case of prerendering).
130+
> [!NOTE] If all your page options are boolean or string literal values, SvelteKit will evaluate them statically. If not, it will import your `+page.js` or `+layout.js` file on the server (both at build time, and at runtime if your app isn't fully static) so it can evaluate the options. In the second case, browser-only code must not run when the module is loaded. In practice, this means you should import browser-only code in your `+page.svelte` or `+layout.svelte` file instead.
131131
132132
## csr
133133

packages/adapter-auto/CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# @sveltejs/adapter-auto
22

3+
## 6.0.1
4+
### Patch Changes
5+
6+
7+
- chore: remove `import-meta-resolve` dependency ([#13629](https://github.com/sveltejs/kit/pull/13629))
8+
9+
- Updated dependencies [[`bd1c04662332cbafa843c35a2e783486116af3d5`](https://github.com/sveltejs/kit/commit/bd1c04662332cbafa843c35a2e783486116af3d5), [`09f61ec2a14573e27769edb403c58aea5433a39f`](https://github.com/sveltejs/kit/commit/09f61ec2a14573e27769edb403c58aea5433a39f), [`09f61ec2a14573e27769edb403c58aea5433a39f`](https://github.com/sveltejs/kit/commit/09f61ec2a14573e27769edb403c58aea5433a39f)]:
10+
- @sveltejs/kit@2.21.0
11+
312
## 6.0.0
413
### Major Changes
514

packages/adapter-auto/index.js

Lines changed: 75 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import { execSync } from 'node:child_process';
2-
import { pathToFileURL } from 'node:url';
3-
import { resolve } from 'import-meta-resolve';
42
import { adapters } from './adapters.js';
5-
import { dirname, join } from 'node:path';
6-
import { existsSync } from 'node:fs';
3+
import path from 'node:path';
4+
import fs from 'node:fs';
75
import process from 'node:process';
86

97
/** @type {Record<string, (name: string, version: string) => string>} */
@@ -17,12 +15,15 @@ const commands = {
1715
function detect_lockfile() {
1816
let dir = process.cwd();
1917

18+
/** @param {string} file */
19+
const exists = (file) => fs.existsSync(path.join(dir, file));
20+
2021
do {
21-
if (existsSync(join(dir, 'pnpm-lock.yaml'))) return 'pnpm';
22-
if (existsSync(join(dir, 'yarn.lock'))) return 'yarn';
23-
if (existsSync(join(dir, 'package-lock.json'))) return 'npm';
24-
if (existsSync(join(dir, 'bun.lockb')) || existsSync(join(dir, 'bun.lock'))) return 'bun';
25-
} while (dir !== (dir = dirname(dir)));
22+
if (exists('pnpm-lock.yaml')) return 'pnpm';
23+
if (exists('yarn.lock')) return 'yarn';
24+
if (exists('package-lock.json')) return 'npm';
25+
if (exists('bun.lockb') || exists('bun.lock')) return 'bun';
26+
} while (dir !== (dir = path.dirname(dir)));
2627

2728
return 'npm';
2829
}
@@ -38,12 +39,40 @@ function detect_package_manager() {
3839
}
3940
}
4041

41-
/** @param {string} name */
42-
function import_from_cwd(name) {
43-
const cwd = pathToFileURL(process.cwd()).href;
44-
const url = resolve(name, cwd + '/x.js');
42+
/**
43+
* Resolves a peer dependency relative to the current CWD. Duplicated with `packages/kit`
44+
* @param {string} dependency
45+
*/
46+
function resolve_peer(dependency) {
47+
let [name, ...parts] = dependency.split('/');
48+
if (name[0] === '@') name += `/${parts.shift()}`;
49+
50+
let dir = process.cwd();
51+
52+
while (!fs.existsSync(`${dir}/node_modules/${name}/package.json`)) {
53+
if (dir === (dir = path.dirname(dir))) {
54+
throw new Error(
55+
`Could not resolve peer dependency "${name}" relative to your project — please install it and try again.`
56+
);
57+
}
58+
}
59+
60+
const pkg_dir = `${dir}/node_modules/${name}`;
61+
const pkg = JSON.parse(fs.readFileSync(`${pkg_dir}/package.json`, 'utf-8'));
62+
63+
const subpackage = ['.', ...parts].join('/');
64+
65+
let exported = pkg.exports[subpackage];
66+
67+
while (typeof exported !== 'string') {
68+
if (!exported) {
69+
throw new Error(`Could not find valid "${subpackage}" export in ${name}/package.json`);
70+
}
71+
72+
exported = exported['import'] ?? exported['default'];
73+
}
4574

46-
return import(url);
75+
return path.resolve(pkg_dir, exported);
4776
}
4877

4978
/** @typedef {import('@sveltejs/kit').Adapter} Adapter */
@@ -56,47 +85,43 @@ async function get_adapter() {
5685

5786
if (!match) return;
5887

59-
/** @type {{ default: () => Adapter }} */
60-
let module;
88+
/** @type {string} */
89+
let resolved;
6190

6291
try {
63-
module = await import_from_cwd(match.module);
64-
} catch (error) {
65-
if (
66-
error.code === 'ERR_MODULE_NOT_FOUND' &&
67-
error.message.startsWith(`Cannot find package '${match.module}'`)
68-
) {
69-
const package_manager = detect_package_manager();
70-
const command = commands[package_manager](match.module, match.version);
71-
72-
try {
73-
console.log(`Installing ${match.module}...`);
74-
75-
execSync(command, {
76-
stdio: 'inherit',
77-
env: {
78-
...process.env,
79-
NODE_ENV: undefined
80-
}
81-
});
82-
83-
module = await import_from_cwd(match.module);
84-
85-
console.log(`Successfully installed ${match.module}.`);
86-
console.warn(
87-
`\nIf you plan on staying on this deployment platform, consider replacing @sveltejs/adapter-auto with ${match.module}. This will give you faster and more robust installs, and more control over deployment configuration.\n`
88-
);
89-
} catch (e) {
90-
throw new Error(
91-
`Could not install ${match.module}. Please install it yourself by adding it to your package.json's devDependencies and try building your project again.`,
92-
{ cause: e }
93-
);
94-
}
95-
} else {
96-
throw error;
92+
resolved = resolve_peer(match.module);
93+
} catch {
94+
const package_manager = detect_package_manager();
95+
const command = commands[package_manager](match.module, match.version);
96+
97+
try {
98+
console.log(`Installing ${match.module}...`);
99+
100+
execSync(command, {
101+
stdio: 'inherit',
102+
env: {
103+
...process.env,
104+
NODE_ENV: undefined
105+
}
106+
});
107+
108+
resolved = resolve_peer(match.module);
109+
110+
console.log(`Successfully installed ${match.module}.`);
111+
console.warn(
112+
`\nIf you plan on staying on this deployment platform, consider replacing @sveltejs/adapter-auto with ${match.module}. This will give you faster and more robust installs, and more control over deployment configuration.\n`
113+
);
114+
} catch (e) {
115+
throw new Error(
116+
`Could not install ${match.module}. Please install it yourself by adding it to your package.json's devDependencies and try building your project again.`,
117+
{ cause: e }
118+
);
97119
}
98120
}
99121

122+
/** @type {{ default: () => Adapter }} */
123+
const module = await import(resolved);
124+
100125
const adapter = module.default();
101126

102127
return {

packages/adapter-auto/package.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sveltejs/adapter-auto",
3-
"version": "6.0.0",
3+
"version": "6.0.1",
44
"description": "Automatically chooses the SvelteKit adapter for your current environment, if possible.",
55
"keywords": [
66
"adapter",
@@ -46,9 +46,6 @@
4646
"typescript": "^5.3.3",
4747
"vitest": "^3.1.1"
4848
},
49-
"dependencies": {
50-
"import-meta-resolve": "^4.1.0"
51-
},
5249
"peerDependencies": {
5350
"@sveltejs/kit": "^2.0.0"
5451
}

packages/enhanced-img/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# @sveltejs/enhanced-img
22

3+
## 0.6.0
4+
### Minor Changes
5+
6+
7+
- feat: add validation to ensure plugin occurs in correct order ([`1c3f36dc10265fb79c64643c3d7a91469d34e697`](https://github.com/sveltejs/kit/commit/1c3f36dc10265fb79c64643c3d7a91469d34e697))
8+
39
## 0.5.1
410
### Patch Changes
511

packages/enhanced-img/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sveltejs/enhanced-img",
3-
"version": "0.5.1",
3+
"version": "0.6.0",
44
"description": "Image optimization for your Svelte apps",
55
"repository": {
66
"type": "git",

packages/enhanced-img/src/vite-plugin.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,23 @@ export function image_plugin(imagetools_plugin) {
3030
/** @type {Partial<import('@sveltejs/vite-plugin-svelte').SvelteConfig | undefined>} */
3131
let svelte_config;
3232

33+
const name = 'vite-plugin-enhanced-img-markup';
34+
3335
return {
34-
name: 'vite-plugin-enhanced-img-markup',
36+
name,
3537
enforce: 'pre',
3638
async configResolved(config) {
3739
vite_config = config;
40+
for (const plugin of config.plugins || []) {
41+
if (plugin.name === name) {
42+
break;
43+
}
44+
if (plugin.name === 'vite-plugin-svelte') {
45+
throw new Error(
46+
'@sveltejs/enhanced-img must come before the Svelte or SvelteKit plugins'
47+
);
48+
}
49+
}
3850
svelte_config = await loadSvelteConfig();
3951
if (!svelte_config) throw new Error('Could not load Svelte config file');
4052
},

packages/kit/CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
# @sveltejs/kit
22

3+
## 2.21.0
4+
### Minor Changes
5+
6+
7+
- feat: allow running client-side code at the top-level of universal pages/layouts when SSR is disabled and page options are only boolean or string literals ([#13684](https://github.com/sveltejs/kit/pull/13684))
8+
9+
10+
### Patch Changes
11+
12+
13+
- chore: remove `import-meta-resolve` dependency ([#13629](https://github.com/sveltejs/kit/pull/13629))
14+
15+
16+
- fix: remove component code from server nodes that are never used for SSR ([#13684](https://github.com/sveltejs/kit/pull/13684))
17+
318
## 2.20.8
419
### Patch Changes
520

packages/kit/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sveltejs/kit",
3-
"version": "2.20.8",
3+
"version": "2.21.0",
44
"description": "SvelteKit is the fastest way to build Svelte apps",
55
"keywords": [
66
"framework",
@@ -18,11 +18,12 @@
1818
"homepage": "https://svelte.dev",
1919
"type": "module",
2020
"dependencies": {
21+
"@sveltejs/acorn-typescript": "^1.0.5",
2122
"@types/cookie": "^0.6.0",
23+
"acorn": "^8.14.1",
2224
"cookie": "^0.6.0",
2325
"devalue": "^5.1.0",
2426
"esm-env": "^1.2.2",
25-
"import-meta-resolve": "^4.1.0",
2627
"kleur": "^4.1.5",
2728
"magic-string": "^0.30.5",
2829
"mrmime": "^2.0.0",

packages/kit/src/core/sync/utils.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import fs from 'node:fs';
22
import path from 'node:path';
33
import { mkdirp } from '../../utils/filesystem.js';
4-
import { resolve_peer_dependency } from '../../utils/import.js';
4+
import { import_peer } from '../../utils/import.js';
55

66
/** @type {{ VERSION: string }} */
7-
const { VERSION } = await resolve_peer_dependency('svelte/compiler');
7+
const { VERSION } = await import_peer('svelte/compiler');
88

99
/** @type {Map<string, string>} */
1010
const previous_contents = new Map();

packages/kit/src/exports/vite/build/build_server.js

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import { mkdirp } from '../../../utils/filesystem.js';
33
import { filter_fonts, find_deps, resolve_symlinks } from './utils.js';
44
import { s } from '../../../utils/misc.js';
55
import { normalizePath } from 'vite';
6-
import { basename } from 'node:path';
6+
import { basename, join } from 'node:path';
7+
import { create_static_analyser } from '../static_analysis/index.js';
78

89
/**
910
* @param {string} out
@@ -14,7 +15,7 @@ import { basename } from 'node:path';
1415
* @param {import('vite').Rollup.OutputAsset[] | null} css
1516
* @param {import('types').RecursiveRequired<import('types').ValidatedConfig['kit']['output']>} output_config
1617
*/
17-
export function build_server_nodes(out, kit, manifest_data, server_manifest, client_manifest, css, output_config) {
18+
export async function build_server_nodes(out, kit, manifest_data, server_manifest, client_manifest, css, output_config) {
1819
mkdirp(`${out}/server/nodes`);
1920
mkdirp(`${out}/server/stylesheets`);
2021

@@ -73,7 +74,14 @@ export function build_server_nodes(out, kit, manifest_data, server_manifest, cli
7374
}
7475
}
7576

76-
manifest_data.nodes.forEach((node, i) => {
77+
const { get_page_options } = create_static_analyser(async (server_node) => {
78+
// Windows needs the file:// protocol for absolute path dynamic imports
79+
return import(`file://${join(out, 'server', resolve_symlinks(server_manifest, server_node).chunk.file)}`);
80+
});
81+
82+
for (let i = 0; i < manifest_data.nodes.length; i++) {
83+
const node = manifest_data.nodes[i];
84+
7785
/** @type {string[]} */
7886
const imports = [];
7987

@@ -101,12 +109,16 @@ export function build_server_nodes(out, kit, manifest_data, server_manifest, cli
101109
}
102110

103111
if (node.universal) {
104-
imports.push(
105-
`import * as universal from '../${
106-
resolve_symlinks(server_manifest, node.universal).chunk.file
107-
}';`
108-
);
109-
exports.push('export { universal };');
112+
const page_options = await get_page_options(node);
113+
if (!!page_options && page_options.ssr === false) {
114+
exports.push(`export const universal = ${s(page_options, null, 2)};`)
115+
} else {
116+
imports.push(
117+
`import * as universal from '../${resolve_symlinks(server_manifest, node.universal).chunk.file}';`
118+
);
119+
// TODO: when building for analysis, explain why the file was loaded on the server if we fail to load it
120+
exports.push('export { universal };');
121+
}
110122
exports.push(`export const universal_id = ${s(node.universal)};`);
111123
}
112124

@@ -186,5 +198,5 @@ export function build_server_nodes(out, kit, manifest_data, server_manifest, cli
186198
`${out}/server/nodes/${i}.js`,
187199
`${imports.join('\n')}\n\n${exports.join('\n')}\n`
188200
);
189-
});
201+
}
190202
}

0 commit comments

Comments
 (0)