Skip to content

Dep prebundling does not preprocess .svelte.ts modules: compileSvelteModule omits the svelte.preprocess call its .svelte sibling makes #1396

Description

@jm9e

Describe the bug

When a dependency ships .svelte.ts rune modules, dep prebundling in dev hands them to svelte.compileModule without preprocessing, so any TypeScript syntax in them is a parse error and vite dev fails.

The .svelte path and the .svelte.[jt]s path in setup-optimizer.js are asymmetric. compileSvelte preprocesses:

// src/plugins/setup-optimizer.js:157, 174-182  (v7.3.0)
async function compileSvelte(options, { filename, code }, generate, environment, statsCollection) {
  
  if (options.preprocess) {
    preprocessed = await svelte.preprocess(code, options.preprocess, { filename });
    
  }
  const finalCode = preprocessed ? preprocessed.code : code;

compileSvelteModule does not:

// src/plugins/setup-optimizer.js:228  (v7.3.0)
async function compileSvelteModule(options, { filename, code }, generate, statsCollection) {
  const endStat = statsCollection?.start(filename);
  const compiled = svelte.compileModule(code, {          // <-- raw `code`, never preprocessed
    dev: options.compilerOptions?.dev ?? true,
    filename,
    generate
  });

svelte.compileModule is a JS parser, so a type annotation, an interface, or an import type in a dependency's .svelte.ts throws js_parse_error.

This looks like an oversight rather than a design choice — the two functions are siblings in the same file, invoked from the same load hook, and only one of them consults options.preprocess.

Reproduction

Minimal shape, no repo needed:

  1. Publish (or npm link) a library that exports a .svelte.ts module containing any TypeScript — e.g.

    // src/context.svelte.ts
    export interface Ctx { width: number }
    export const COMPACT_BELOW = 640;
    export function plan(ctx: Ctx): 'strip' | 'bar' {
      return ctx.width < COMPACT_BELOW ? 'bar' : 'strip';
    }
  2. Consume it from a fresh Vite + Svelte 5 app with no optimizeDeps block and no plugin option.

  3. vite devjs_parse_error from the prebundle step.

Measured on Vite 8.2.2 · Svelte 5.56.10 · @sveltejs/vite-plugin-svelte 7.3.0, against a published package (@nighthq/components@0.2.0) that ships three such modules: 3 errors. With the same package's three files' types stripped in node_modules and nothing else changed: starts clean, ready in 3249 ms, zero errors. That isolates preprocessing as the only variable.

Expected behaviour

.svelte.[jt]s modules from a prebundled dependency are preprocessed on the same terms as .svelte files, so a library may ship TypeScript rune modules without every consumer configuring around it.

Why the documented workarounds do not cover it

  • optimizeDeps.exclude: ['<lib>'] works, and is what we document today — but it is per-consumer config for a library-side property, and a consumer only discovers the need when their dev server dies with an error that names none of this.
  • The svelte export condition puts a library on the auto-exclude list, but prebundleSvelteLibraries defaults to true in dev and the list is discarded — so declaring the condition correctly does not help.

So there is currently no library-side fix: the only remedies are consumer config, or shipping compiled JS and giving up publishing source.

Suggested fix

Add the same options.preprocess branch to compileSvelteModule that compileSvelte already has, passing the preprocessed code to svelte.compileModule and carrying preprocessed.map into sourcemap.

Happy to open a PR if the direction is welcome — say the word and I will.

Versions

@sveltejs/vite-plugin-svelte  7.3.0
vite                          8.2.2
svelte                        5.56.10

Activity

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