Skip to content

fix: resolve remote modules as external during dev prebundling so packages can re-export remote functions - #16426

Merged
Rich-Harris merged 3 commits into
sveltejs:version-3from
Nic-Polumeyv:fix-remote-lib-prebundle
Jul 20, 2026
Merged

fix: resolve remote modules as external during dev prebundling so packages can re-export remote functions#16426
Rich-Harris merged 3 commits into
sveltejs:version-3from
Nic-Polumeyv:fix-remote-lib-prebundle

Conversation

@Nic-Polumeyv

@Nic-Polumeyv Nic-Polumeyv commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Fixes #16353.

#14583 stops dependency tracing at .remote.* files by loading them as empty modules during prebundling, so their server-only imports stay out of the client bundle. An empty module also has no exports, so a package entry that re-exports from a remote file kills the dev server during dependency optimization

[MISSING_EXPORT] "lib_echo" is not exported by ".../data.remote.js"
   1 │ export { lib_echo } from './data.remote.js';

The docs say third party libraries can provide remote functions, so this should work without per-package optimizeDeps config.

Externalizing the resolved id instead keeps tracing stopped and the export surface intact, and the dev server serves the real module through the normal transform. Build mode never ran the optimizer and stays green.

@pkg-svelte-dev

pkg-svelte-dev Bot commented Jul 19, 2026

Copy link
Copy Markdown

Install the latest version of @sveltejs/kit from 57d3f9c:

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

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

Note

This PR is from a fork. A maintainer must approve approve each commit before it can be built and installed.

@changeset-bot

changeset-bot Bot commented Jul 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 57d3f9c

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 Patch

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

…-prebundle

# Conflicts:
#	packages/kit/src/exports/vite/index.js

@Rich-Harris Rich-Harris left a comment

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.

clever!

@Rich-Harris
Rich-Harris merged commit c9b5544 into sveltejs:version-3 Jul 20, 2026
17 of 18 checks passed
@pevey

pevey commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

clever!

Won't this prevent the bundler from resolving $app/server?

My current workaround as of 3.0.0-next.10 is:

// vite.config.js
	optimizeDeps: {
		exclude: ['sveltekit-medusa-sdk'] // don't prebundle to prevent SvelteKit from dropping the remote functions in installed packages
	},
	ssr: {
		noExternal: ['sveltekit-medusa-sdk'] // treat the package as internal to the app so that $app/server can resolve
	},

@dummdidumm

Copy link
Copy Markdown
Member

Could explain why exactly?
Btw I think the real solution is to have a peer dependency on Svelte so that vite-plugin-svelte does add the library as a whole to exclude ; or we adjust v-p-s to also do this for packaged with SvelteKit (peer) dependencies, because this confusion comes up often

@Nic-Polumeyv

Nic-Polumeyv commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

Won't this prevent the bundler from resolving $app/server?

No. The optimizer never resolved $app/server in the first place. $app and $env are already in Kit's own optimizeDeps.exclude, and the remote file is now external as a /@fs URL, served through the dev server pipeline. On the client the remote module is replaced by fetch proxies, so $app/server never reaches the browser.

Once this ships the optimizeDeps.exclude half of the workaround can go. On the peer dependency point, sveltekit-medusa-sdk already has the svelte peer dep and svelte field, so vite-plugin-svelte should already be adding it to ssr.noExternal. It gets prebundled anyway because prebundleSvelteLibraries defaults to true in dev, which clears the library excludes.

Rich-Harris pushed a commit that referenced this pull request Jul 24, 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/kit@3.0.0-next.12

### Major Changes

- breaking: rename `Pathname` type to `Path` and `Asset` to `AssetPath`
([#16430](#16430))
  breaking: remove leading `/` from `Path` and `AssetPath`
- breaking: write tsconfig to `node_modules/$app/tsconfig`
([#16458](#16458))

- breaking: error on `event.url`, `event.params` and `event.route`
access inside queries
([#16452](#16452))

- breaking: delete `$service-worker` module
([#16450](#16450))

- breaking: detect new deployments on data, remote, and form action
responses, tab focus, and visibility change, and default
`version.pollInterval` to 1 hour
([#16496](#16496))

### Minor Changes

- feat: add `$app/manifest` module with `immutable`, `assets`,
`prerendered`, and `routes` exports
([#16372](#16372))

- feat: validate that all remote form fields were created with
form.fields.foo.as(...)
([#16331](#16331))

- feat: make `$app/paths` importable in service workers
([#16441](#16441))

- feat: `$app/service-worker` module
([#16458](#16458))

- feat: better tsconfig validation
([#16458](#16458))

- fix: default cookies to `secure` to `false` during development
([#16462](#16462))

### Patch Changes

- fix: allow `undefined` values to be passed to form field `.as(...)`
where applicable ([#15681](#15681))

- fix: include queries refreshed from within another query in the
serialized response
([#16461](#16461))

- fix: generate sourcemaps for remote modules
([#16440](#16440))

- fix: avoid empty getElementById() call on hash routing navigation
([#16448](#16448))

- fix: warn if hook files are spelled as "hook" instead of "hooks"
([#16483](#16483))

- chore: deprecate the `alias` option
([#16470](#16470))

- fix: prevent infinite loops when server-side queries refresh each
other in a cycle during the single-flight drain
([#16461](#16461))

- fix: populate `version` in service workers
([#16434](#16434))

- fix: resolve remote modules as external during dev prebundling so
packages can re-export remote functions
([#16426](#16426))

- fix: refetch route-tracking server data when navigating away from an
error page ([#16381](#16381))

- fix: serialize `query(...).set(...)`/`query(...).refresh()` values
into the rendered HTML when called from within a query during SSR
([#16461](#16461))

- fix: fall back to the page's form actions when a sibling endpoint has
no POST handler ([#16349](#16349))

- fix: return a lightweight 404 instead of rendering the error page for
subresource requests
([#16463](#16463))

- fix: preserve stripped path prefixes by making trailing-slash
redirects relative
([#16431](#16431))

- chore: deduplicate type-stripping logic in `tweak_types`
([#16454](#16454))

- fix: more informative error message when running a command inside a
query or prerender function
([`eb5c973`](eb5c973))
## @sveltejs/adapter-cloudflare@8.0.0-next.3

### Patch Changes

- chore: bump `@cloudflare/workers-types` to `4.20260621.1`
([#16455](#16455))
- Updated dependencies
[[`adc4c5b`](adc4c5b),
[`ecb0701`](ecb0701),
[`4b4cc60`](4b4cc60),
[`7390dbe`](7390dbe),
[`2e71340`](2e71340),
[`c87bc3a`](c87bc3a),
[`af15c6c`](af15c6c),
[`c6fa431`](c6fa431),
[`bfe4dea`](bfe4dea),
[`df7dc72`](df7dc72),
[`5ae11a1`](5ae11a1),
[`781205c`](781205c),
[`c87bc3a`](c87bc3a),
[`a1bfeb9`](a1bfeb9),
[`c87bc3a`](c87bc3a),
[`9f0127d`](9f0127d),
[`4b4cc60`](4b4cc60),
[`8f5b9c7`](8f5b9c7),
[`c9b5544`](c9b5544),
[`fe1d4a4`](fe1d4a4),
[`4b4cc60`](4b4cc60),
[`5f78e95`](5f78e95),
[`25510fc`](25510fc),
[`c99a6cf`](c99a6cf),
[`17a45ca`](17a45ca),
[`2ca20c3`](2ca20c3),
[`eb5c973`](eb5c973)]:
  - @sveltejs/kit@3.0.0-next.12
## @sveltejs/adapter-netlify@7.0.0-next.4

### Patch Changes

- fix: await `init` on every request to prevent race condition
([#16467](#16467))

- chore: bump Rolldown to `1.2.0`
([#16455](#16455))
- Updated dependencies
[[`adc4c5b`](adc4c5b),
[`ecb0701`](ecb0701),
[`4b4cc60`](4b4cc60),
[`7390dbe`](7390dbe),
[`2e71340`](2e71340),
[`c87bc3a`](c87bc3a),
[`af15c6c`](af15c6c),
[`c6fa431`](c6fa431),
[`bfe4dea`](bfe4dea),
[`df7dc72`](df7dc72),
[`5ae11a1`](5ae11a1),
[`781205c`](781205c),
[`c87bc3a`](c87bc3a),
[`a1bfeb9`](a1bfeb9),
[`c87bc3a`](c87bc3a),
[`9f0127d`](9f0127d),
[`4b4cc60`](4b4cc60),
[`8f5b9c7`](8f5b9c7),
[`c9b5544`](c9b5544),
[`fe1d4a4`](fe1d4a4),
[`4b4cc60`](4b4cc60),
[`5f78e95`](5f78e95),
[`25510fc`](25510fc),
[`c99a6cf`](c99a6cf),
[`17a45ca`](17a45ca),
[`2ca20c3`](2ca20c3),
[`eb5c973`](eb5c973)]:
  - @sveltejs/kit@3.0.0-next.12
## @sveltejs/adapter-node@6.0.0-next.6

### Patch Changes

- fix: preserve stripped path prefixes by making trailing-slash
redirects relative
([#16431](#16431))

- chore: bump Rolldown to `1.2.0`
([#16455](#16455))
- Updated dependencies
[[`adc4c5b`](adc4c5b),
[`ecb0701`](ecb0701),
[`4b4cc60`](4b4cc60),
[`7390dbe`](7390dbe),
[`2e71340`](2e71340),
[`c87bc3a`](c87bc3a),
[`af15c6c`](af15c6c),
[`c6fa431`](c6fa431),
[`bfe4dea`](bfe4dea),
[`df7dc72`](df7dc72),
[`5ae11a1`](5ae11a1),
[`781205c`](781205c),
[`c87bc3a`](c87bc3a),
[`a1bfeb9`](a1bfeb9),
[`c87bc3a`](c87bc3a),
[`9f0127d`](9f0127d),
[`4b4cc60`](4b4cc60),
[`8f5b9c7`](8f5b9c7),
[`c9b5544`](c9b5544),
[`fe1d4a4`](fe1d4a4),
[`4b4cc60`](4b4cc60),
[`5f78e95`](5f78e95),
[`25510fc`](25510fc),
[`c99a6cf`](c99a6cf),
[`17a45ca`](17a45ca),
[`2ca20c3`](2ca20c3),
[`eb5c973`](eb5c973)]:
  - @sveltejs/kit@3.0.0-next.12
## @sveltejs/adapter-vercel@7.0.0-next.3

### Patch Changes

- fix: await `init` on every request to prevent race condition
([#16467](#16467))

- chore: bump Rolldown to `1.2.0`
([#16455](#16455))
- Updated dependencies
[[`adc4c5b`](adc4c5b),
[`ecb0701`](ecb0701),
[`4b4cc60`](4b4cc60),
[`7390dbe`](7390dbe),
[`2e71340`](2e71340),
[`c87bc3a`](c87bc3a),
[`af15c6c`](af15c6c),
[`c6fa431`](c6fa431),
[`bfe4dea`](bfe4dea),
[`df7dc72`](df7dc72),
[`5ae11a1`](5ae11a1),
[`781205c`](781205c),
[`c87bc3a`](c87bc3a),
[`a1bfeb9`](a1bfeb9),
[`c87bc3a`](c87bc3a),
[`9f0127d`](9f0127d),
[`4b4cc60`](4b4cc60),
[`8f5b9c7`](8f5b9c7),
[`c9b5544`](c9b5544),
[`fe1d4a4`](fe1d4a4),
[`4b4cc60`](4b4cc60),
[`5f78e95`](5f78e95),
[`25510fc`](25510fc),
[`c99a6cf`](c99a6cf),
[`17a45ca`](17a45ca),
[`2ca20c3`](2ca20c3),
[`eb5c973`](eb5c973)]:
  - @sveltejs/kit@3.0.0-next.12

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@Nic-Polumeyv
Nic-Polumeyv deleted the fix-remote-lib-prebundle branch July 30, 2026 22:53
Rich-Harris added a commit that referenced this pull request Aug 4, 2026
…de_modules (#16492)

Fixes #16473 by implementing the rule from
#16473 (comment).
Files in node_modules are only treated as remote modules when the
package they belong to lists `@sveltejs/kit` in its `peerDependencies`;
files outside node_modules behave as before.

The check walks up from the file to the owning `package.json`, past
`dist/package.json` type stubs and stopping at the node_modules
boundary, so pnpm virtual-store paths and scoped packages resolve
correctly. Results are cached per directory. It gates the remote
transform, the dev prebundle externalization from #16426, and the dev
watcher. The chain check that picks the "enable remoteFunctions" error
message still uses the raw pattern, because the import graph there holds
root-relative ids that can't be reliably resolved to a package.

Reproducing the issue requires the dependency to be processed by Vite,
so the new fixture package has a `svelte` field, which makes
vite-plugin-svelte mark it `ssr.noExternal` like the reporter's
`@auth/sveltekit` chain; a plain server-external package never reaches
the transform. Without the fix, the async test app build fails with the
exact error from the issue. The existing `e2e-test-dep-remote` fixture
now declares the peer dependency, which keeps its test passing and
covers the other side of the rule.

---------

Co-authored-by: Rich Harris <rich.harris@vercel.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.

Remote functions re-exported from an installed package break dev pre-bundling (MISSING_EXPORT)

4 participants