Skip to content

breaking: consistent special filename patterns#16382

Merged
Rich-Harris merged 20 commits into
version-3from
consistent-filename-patterns
Jul 20, 2026
Merged

breaking: consistent special filename patterns#16382
Rich-Harris merged 20 commits into
version-3from
consistent-filename-patterns

Conversation

@Rich-Harris

Copy link
Copy Markdown
Member

There are two special kinds of modules in SvelteKit projects: server-only modules and remote modules.

  • *.server.ts is server-only, as is *.server.*.ts — any .server. infix works
  • *.remote.ts is remote, but *.remote.*.ts is not

This inconsistency is weird. It's also weird that server.ts isn't a server-only module. Similarly, it's annoying that remote.ts isn't treated as a remote module, as it's not uncommon to have a folder structure like this...

src/lib/my/feature
  index.ts # the interface the rest of the app uses
  index.remote.ts # an implementation detail of `my/feature`

The index part of index.remote.ts is there just because you need something, but the name to identify it by is already in the path — my/feature. Forcing people to add junk to the start of the filename just to satisfy arbitrary internal assumptions is unsportsmanlike. Simpler to be able to say that if your module includes a 'server' segment in the filename it's server-only; same for remote modules.

Closes #16318


Please don't delete this checklist! Before submitting the PR, please make sure you do the following:

Tests

  • Run the tests with pnpm test and lint the project with pnpm lint and pnpm check

Changesets

  • If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running pnpm changeset and following the prompts. Changesets that add features should be minor and those that fix bugs should be patch. Please prefix changeset messages with feat:, fix:, or chore:.

Edits

  • Please ensure that 'Allow edits from maintainers' is checked. PRs without this option may be closed.

@pkg-svelte-dev

pkg-svelte-dev Bot commented Jul 17, 2026

Copy link
Copy Markdown

Install the latest version of @sveltejs/kit from b37230a:

pnpm add https://pkg.svelte.dev/@sveltejs/kit/c/b37230a6a2bf2ba213a7173b938bdc42f44c2607

Open in pkg.svelte.dev: https://pkg.svelte.dev/repos/kit/pr/16382

@changeset-bot

changeset-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c315920

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@sveltejs/kit Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Comment thread packages/kit/src/exports/vite/index.js Outdated
Comment thread documentation/docs/30-advanced/50-server-only-modules.md
Comment thread documentation/docs/30-advanced/50-server-only-modules.md Outdated
Comment thread documentation/docs/30-advanced/50-server-only-modules.md Outdated
Comment thread packages/kit/src/exports/vite/index.js Fixed
Comment thread packages/kit/src/exports/vite/index.js Fixed
Comment thread packages/kit/src/exports/vite/utils.js Dismissed
Comment thread packages/kit/src/exports/vite/utils.js Dismissed
Comment thread packages/kit/src/exports/vite/index.js Outdated
Rich-Harris and others added 4 commits July 17, 2026 11:16
…name/directory-based server-only detection and allowing server-only code to leak into client bundles

This commit fixes the issue reported at packages/kit/src/exports/vite/index.js:758

## Bug

In `packages/kit/src/exports/vite/index.js` the `plugin_guard` `load`/`handler` computes whether a module is server-only:

```js
let is_server_only = normalized === '$app/env/private' || normalized === '$app/server';

if (id.startsWith(normalized_cwd) && !id.startsWith(normalized_node_modules)) {
    is_server_only ??= server_only_module_pattern.test(id);
    is_server_only ??=
        server_only_directory_pattern.test(id) &&
        !id.startsWith(normalized_routes + '/') &&
        !id.startsWith(normalized_assets + '/');
}

if (!is_server_only) return;
```

`is_server_only` is initialized from `===` comparisons, so it is **always** a boolean (`true`/`false`), never `null`/`undefined`.

`a ??= b` only assigns when `a` is nullish. Since `is_server_only` is `false` for the overwhelmingly common case (the module is not `$app/server` / `$app/env/private`), the RHS of both `??=` statements never executes:

```js
let x = false; x ??= true; // x is still false
```

## Impact

The filename pattern (`*.server.*`) and `server/` directory checks are effectively dead code. Modules that should be flagged server-only via filename/directory conventions are no longer detected, so `find_chain` never fires and the guard that documentation/docs/30-advanced/50-server-only-modules.md promises is disabled. Server-only code (potentially containing secrets) can be silently bundled into the client — a security regression introduced by the refactor in commit caf79f3.

## Fix

Switch both `??=` to `||=` so the checks run whenever `is_server_only` is still falsy, matching the pre-refactor single boolean-OR behavior.


Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: Rich-Harris <[email protected]>
@svelte-docs-bot

Copy link
Copy Markdown

Comment thread documentation/docs/20-core-concepts/60-remote-functions.md Outdated
Comment thread documentation/docs/30-advanced/50-server-only-modules.md Outdated
Comment thread packages/kit/src/exports/vite/index.js
Comment thread packages/kit/src/exports/vite/index.js
expect(remote_module_pattern.test('dir/remote.js')).toBe(true);
expect(remote_module_pattern.test('dir/module.remote.ts')).toBe(true);
expect(remote_module_pattern.test('dir/module.remote.test.js')).toBe(true);
expect(remote_module_pattern.test('dir/module.remotely.js')).toBe(false);

@teemingc teemingc Jul 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
expect(remote_module_pattern.test('dir/module.remotely.js')).toBe(false);
expect(remote_module_pattern.test('dir/module.remotely.js')).toBe(false);
expect(remote_module_pattern.test('remote/index.js')).toBe(false);

Might be worth testing the directory name case for both module patterns?

@Rich-Harris
Rich-Harris merged commit fefb3ae into version-3 Jul 20, 2026
20 checks passed
@Rich-Harris
Rich-Harris deleted the consistent-filename-patterns branch July 20, 2026 01:46
Rich-Harris pushed a commit that referenced this pull request Jul 20, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to version-3, this PR
will be updated.

⚠️⚠️⚠️⚠️⚠️⚠️

`version-3` is currently in **pre mode** so this branch has prereleases
rather than normal releases. If you want to exit prereleases, run
`changeset pre exit` on `version-3`.

⚠️⚠️⚠️⚠️⚠️⚠️

# Releases
## @sveltejs/[email protected]

### Major Changes

- breaking: `config` exported from a universal route file takes
precedence over a server one
([#16400](#16400))

- breaking: consistent special filename patterns
([#16382](#16382))

### Minor Changes

- feat: support sourcemaps in production
([#16412](#16412))

- feat: support function validators for environment variables
([#16402](#16402))

- feat: better error logging
([#16374](#16374))

### Patch Changes

- fix: don't treat callable standard schemas as function param matchers
([#16403](#16403))

- fix: reject malformed streamed data encoding
([#16423](#16423))

- fix: hide stack traces for internal errors like 404s
([#16411](#16411))

- perf: match only unpaired surrogates when escaping HTML
([#16407](#16407))

- fix: don't report empty environment variables as missing
([#16401](#16401))

- chore: clarify which hooks run during server route resolution
([#16397](#16397))
## @sveltejs/[email protected]

### Minor Changes

- feat: better error logging
([#16374](#16374))

### Patch Changes

- Updated dependencies
[[`5220191`](5220191),
[`8cb2f7d`](8cb2f7d),
[`b88c7a7`](b88c7a7),
[`a6ea113`](a6ea113),
[`6446f64`](6446f64),
[`58f1789`](58f1789),
[`09774a2`](09774a2),
[`c542fdd`](c542fdd),
[`aedaa27`](aedaa27),
[`428ee1a`](428ee1a),
[`fefb3ae`](fefb3ae)]:
  - @sveltejs/[email protected]

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Treat remote.ts as a remote module

4 participants