Skip to content

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

Closed

Description

@pevey

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 dev

The 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 .remote files 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.4

Severity

annoyance

Additional Information

No response

Activity

  1. pevey commented on Jul 15, 2026

    @pevey
    ContributorAuthor

    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:

    optimizeDeps: {
    		include: ['remote-functions-lib > cookie'], // add back the cjs transitive dependency
    		exclude: ['remote-functions-lib'] // don't prebundle to prevent SvelteKit from dropping the remote functions in installed packages in dev mode
    	},

    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.

  2. added a commit that references this issue on Jul 20, 2026
    c9b5544
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions