Repository navigation
Remote functions re-exported from an installed package break dev pre-bundling (MISSING_EXPORT) #16353
Description
Describe the bug
When an installed node_modules package re-exports a remote function (query, command, form, prerender) from its barrel entry, vite dev fails to start with a MISSING_EXPORT error during dependency optimization.
This makes it impossible to ship remote functions from a library and consume them from an app in dev mode, unless the consumer manually adds the package to optimizeDeps.exclude. That workaround is not free — excluding a package also opts its whole dependency subtree out of Vite's CommonJS→ESM conversion and module bundling, so CJS transitive deps break in the browser and larger packages slow down dev, leaving every consumer to hand-maintain their Vite config.
It reproduces on @sveltejs/kit@3.0.0-next.8 and on the 2.x line, so it is not resolved by the upcoming 3.0 release as of next.8.
Reproduction
https://github.com/pevey/kit-remote-functions-package-missing-import-repro
pnpm install
pnpm devThe library (remote-lib) ships a single remote function re-exported through its barrel:
// remote-lib/dist/message.remote.js
import { query } from '$app/server';
export const getMessage = query(() => 'hello from a library remote function');
// remote-lib/dist/index.js
export { getMessage } from './message.remote.js';The app enables remote functions and imports getMessage from remote-lib.
Note: the library is installed from a packed tarball rather than a workspace link on purpose. Vite does not pre-bundle linked/
workspace:dependencies, so a symlinked library would not reproduce the bug — its.remotefiles would flow through the normal transform. A real install is required to trigger dependency pre-bundling, which is where the bug lives.
Expected
vite dev starts and / renders the string returned by the library's remote function.
Actual
vite dev aborts during dependency pre-bundling:
Error during dependency optimization:
Build failed with 1 error:
[MISSING_EXPORT] "getMessage" is not exported by ".../remote-lib/dist/message.remote.js".
.../remote-lib/dist/index.js:2 │ export { getMessage } from './message.remote.js';
─────┬────
╰────── Missing export
Adding optimizeDeps: { exclude: ['remote-lib'] } to vite.config.js works around it.
Root cause
When experimental.remoteFunctions is enabled, SvelteKit registers a plugin into Vite's dependency optimizer that replaces the contents of every *.remote.<ext> file with an empty string during pre-bundling (packages/kit/src/exports/vite/index.js, the vite-plugin-sveltekit-setup:optimize-remote-functions plugin):
// treat .remote.js files as empty for the purposes of prebundling
const remote_id_filter = new RegExp(
`.remote(${kit.moduleExtensions.join('|')})$`.replaceAll('.', '\\.')
);
// ...
load: {
filter: { id: remote_id_filter },
handler() {
return '';
}
}The filter is a bare .remote.<ext> suffix match with no path scoping, so it also blanks .remote files inside pre-bundled node_modules packages. When Vite pre-bundles such a package's barrel and follows export { getMessage } from './message.remote.js' into the now-empty module, the export is gone and it reports MISSING_EXPORT.
SvelteKit already handles the analogous case for other features — the base config adds $app and $env to optimizeDeps.exclude specifically "so that libraries using them work even when they are prebundled":
exclude: [
'@sveltejs/kit',
// exclude kit features so that libraries using them work even when they are prebundled
// this does not affect app code, just handling of imported libraries that use $app or $env
'$app',
'$env'
]There is no equivalent handling for packages that contain .remote files. (The main-thread remote transform itself already works for library files — it filters on the same .remote suffix with no node_modules exclusion — so simply keeping these packages out of the optimizer is enough for them to be handled correctly.)
Suggested fix
When experimental.remoteFunctions is enabled, exclude packages that contain .remote files from dependency pre-bundling (mirroring the existing $app/$env handling) instead of blanking those files mid-optimization. The maintainers may prefer a different mechanism; at minimum it would help if the MISSING_EXPORT error mentioned remote functions and the optimizeDeps.exclude workaround, since the current message gives no hint that remote functions are involved.
Logs
System Info
System:
OS: Linux 7.0 Arch Linux
Binaries:
Node: 24.18.0
pnpm: 11.13.0
npmPackages:
@sveltejs/adapter-auto: 7.0.1
@sveltejs/kit: 3.0.0-next.8
@sveltejs/vite-plugin-svelte: 7.2.0
svelte: 5.56.5
vite: 8.1.4Severity
annoyance
Additional Information
No response
Activity
pevey commentedon Jul 15, 2026
I dug into it more, and I see that remote files were intentionally blanked out during pre-bundling by #14583 to address #14519. I admit I don't fully understand the original issue in 14519.
The fix says "Import tracing should stop at .remote.js files, because these don't run in the client." But even though they don't run in the client, they are called from the client. Blanking them out completely breaks any usage of them in the app in dev mode.
I'm not sure there really is a better solution than adding packages with remote functions to optimizeDeps: exclude and then (when necessary), using some fancy syntax to include back transitive dependencies that are cjs and otherwise would break the site in dev mode.
Eg:
It seems like this leaves a pretty big footgun, especially since I feel like remote functions will likely become a widely-used, framework-defining feature.
fix: resolve remote modules as external during dev prebundling so pac…