Skip to content

@fedify/nuxt: Nitro fails to bundle runtime because dist/mod.js references the TypeScript sources directly #716

@dahlia

Description

@dahlia

Summary

When a project created by fedify init -w nuxt runs npm run dev, Nitro's Rollup pipeline crashes while trying to bundle the server because @fedify/nuxt points Nuxt at the package's raw TypeScript sources instead of compiled JavaScript. rollup-plugin-inject runs before any TS transform and cannot parse type-only syntax like import type { Federation } from "@fedify/fedify/federation".

The net effect is that the current @fedify/nuxt@2.2.0-dev.* is unusable outside the monorepo. I couldn't find a Nuxt example under examples/, so I suspect the package has not been exercised end-to-end against a real npm install consumer yet.

Steps to reproduce

With @fedify/cli@2.2.0-dev.898 installed:

mkdir nuxt-repro && cd nuxt-repro
fedify init -w nuxt -p npm -k in-memory -m in-process .
npm run dev

Expected behavior

Nitro starts, the landing page is reachable on http://localhost:3000/, and /users/john returns a Person actor for any Accept: application/activity+json client.

Actual behavior

Nitro fails to build:

 WARN  [plugin inject] node_modules/@fedify/nuxt/src/runtime/server/middleware.ts:
   rollup-plugin-inject: failed to parse
   .../node_modules/@fedify/nuxt/src/runtime/server/middleware.ts.
   Consider restricting the plugin to particular files via options.include

 WARN  [plugin inject] node_modules/@fedify/nuxt/src/runtime/server/plugin.ts:
   rollup-plugin-inject: failed to parse ...

[nitro]  ERROR  RollupError:
  node_modules/@fedify/nuxt/src/runtime/server/middleware.ts (1:12):
  Expected ',', got '{'
  (Note that you need plugins to import files that are not JavaScript)

1: import type { Federation } from "@fedify/fedify/federation";
                ^
2: import { defineEventHandler, type H3Event, toWebRequest } from "h3";

Root cause

  1. packages/nuxt/src/module.ts passes TypeScript source paths to Nuxt Kit at module setup time:
    • resolver.resolve("../src/runtime/server/middleware.ts") used inside the addServerTemplate import string (around packages/nuxt/src/module.ts:119).
    • addServerPlugin(resolver.resolve("../src/runtime/server/plugin.ts")) (around packages/nuxt/src/module.ts:148).
  2. packages/nuxt/tsdown.config.ts only compiles src/mod.ts, so dist/ has no runtime/server/*.js. The source .ts files are shipped via "files": ["dist/", "src/runtime/", ...], but the module deliberately resolves back to those TS sources.
  3. Inside a consumer's Nitro build, rollup-plugin-inject runs before any TS transform and chokes on import type { ... } and import { ..., type X, ... } syntax that appears in middleware.ts, plugin.ts, logic.ts, and lib.ts.
  4. Within the monorepo pnpm workspace the symptom may be hidden because Nitro's TS handling picks up local src/ differently than an installed node_modules package.

Proposed fix

  1. Extend packages/nuxt/tsdown.config.ts to emit the runtime files as additional entry points, for example:
    entry: [
      "src/mod.ts",
      "src/runtime/server/middleware.ts",
      "src/runtime/server/plugin.ts",
    ],
    logic.ts and lib.ts should be bundled into the two entries (or added as entries too) so there is no residual .ts reference at runtime.
  2. Update packages/nuxt/src/module.ts to resolve the compiled paths:
    resolver.resolve("../dist/runtime/server/middleware.js")
    addServerPlugin(resolver.resolve("../dist/runtime/server/plugin.js"))
  3. Keep shipping src/runtime/ in files only if it's still needed for types; otherwise drop it to reduce package size.
  4. Add a minimal Nuxt example under examples/ (for instance examples/nuxt/) wired up like the other framework examples and referenced from examples/test-examples, so this class of regression is caught by mise test:examples.

Side findings (can be split into separate issues if preferred)

  • fedify init writes a Biome 1.8.3 formatted biome.json ("organizeImports": { "enabled": true }) but adds @biomejs/biome@^2.4.9 to devDependencies. Biome 2 rejects the file with Known keys: ... assist ... and organizeImports has moved to assist.actions.source.organizeImports. The $schema URL also pins 1.8.3.
  • fedify init prompts “Directory is not empty” even when only a freshly created empty .git is present, and there's no --force/--yes flag. The prompt crashes with ExitPromptError on a non-TTY stdin, which makes automated scaffolding impossible.

Environment

  • @fedify/cli: 2.2.0-dev.898+44ea8f2f
  • @fedify/nuxt: 2.2.0-dev.898+44ea8f2f
  • nuxt: 4.4.2
  • nitro: 2.13.3 (via Nuxt)
  • vite: 7.3.2
  • node: v22.22.2
  • OS: Linux 6.19.10 (Fedora 44)

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions