Skip to content

fix: resolve svelte/vue compilers from the project directory - #798

Merged
ieedan merged 3 commits into
mainfrom
claude/air-calculation-discrepancy-nyzce6
Jul 10, 2026
Merged

ieedan merged 3 commits into
mainfrom
claude/air-calculation-discrepancy-nyzce6

Conversation

@ieedan

@ieedan ieedan commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

What & why

Investigated discussion #797, where a user building a Svelte registry hit:

svelte is required for Svelte language support to work. Please install it.

…even though they had svelte@^5.56.1 installed in their project. The error being reported didn't add up.

Root cause

The Svelte and Vue language plugins loaded their compilers with a bare dynamic import:

// src/langs/svelte.ts
svelteCompiler = await import('svelte/compiler');

A bare import('svelte/compiler') resolves the module relative to jsrepo's own location on disk, not the user's project. resolveDependencies is already handed opts.cwd (the consumer's project root), but the loader ignored it.

So whenever jsrepo lives in a different node_modules than the framework — a global/npx/bunx install, a hoisted monorepo, or a package manager that doesn't hoist optional peer deps — the lookup fails and jsrepo throws MissingPeerDependencyError telling the user to install a package they already installed. This also lines up with the reporter's own resolution (a bun.lock conflict that was moving svelte out of the location jsrepo could see).

The DEFAULT_LANGS auto-detection in src/langs/index.ts had the same blind spot (createRequire(import.meta.url)), so the maintainer's suggested workaround — "remove languages from your config" — was equally unreliable.

Changes

  • src/langs/load-peer-compiler.ts (new): shared helper that resolves a peer compiler from the consumer's cwd first (via createRequire pointed at the project), then falls back to jsrepo's own resolution, and only throws MissingPeerDependencyError if both fail.
  • src/langs/svelte.ts / src/langs/vue.ts: thread opts.cwd into the compiler loader and use the shared helper.
  • src/langs/index.ts: isModuleAvailable now checks the project directory (process.cwd()) before jsrepo's own location, so auto-detection finds project-installed frameworks too.
  • Tests: tests/langs/load-peer-compiler.test.ts covers project-cwd resolution and the missing-dependency failure path.
  • Changeset: patch bump for jsrepo.

Verification

  • pnpm check (tsc) — clean
  • pnpm vitest run — 200/200 tests pass, including the new helper tests
  • biome check — clean on all touched files

🤖 Generated with Claude Code

https://claude.ai/code/session_01UwUar3KD5KEWVRN4GWgBu5


Generated by Claude Code

The svelte and vue language plugins loaded their compilers with a bare
`import('svelte/compiler')` / `import('vue/compiler-sfc')`, which resolves
against jsrepo's own install location rather than the user's project. When
jsrepo lives in a different node_modules than the framework (global/npx
installs, hoisted monorepos, package managers that don't hoist peer deps),
that lookup fails and the build reports "svelte is required for Svelte
language support to work" even though the user installed svelte in their
project.

Resolve the compiler from the consumer's `cwd` first (already threaded into
`resolveDependencies`), falling back to jsrepo's own resolution. Auto-detection
in `DEFAULT_LANGS` now checks the project directory as well.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UwUar3KD5KEWVRN4GWgBu5
@changeset-bot

changeset-bot Bot commented Jul 10, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 3ead72e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 11 packages
Name Type
jsrepo Patch
@jsrepo/bun Patch
@jsrepo/mcp Patch
@jsrepo/migrate Patch
@jsrepo/pnpm Patch
@jsrepo/shadcn Patch
@jsrepo/transform-biome Patch
@jsrepo/transform-filecasing Patch
@jsrepo/transform-javascript Patch
@jsrepo/transform-oxfmt Patch
@jsrepo/transform-prettier 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

@vercel

vercel Bot commented Jul 10, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
jsrepo.dev Ready Ready Preview, Comment Jul 10, 2026 6:18pm

Request Review

@pkg-pr-new

pkg-pr-new Bot commented Jul 10, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

jsrepo

pnpm add https://pkg.pr.new/jsrepojs/jsrepo@798

@jsrepo/mcp

pnpm add https://pkg.pr.new/jsrepojs/jsrepo/@jsrepo/mcp@798

@jsrepo/migrate

pnpm add https://pkg.pr.new/jsrepojs/jsrepo/@jsrepo/migrate@798

@jsrepo/transform-biome

pnpm add https://pkg.pr.new/jsrepojs/jsrepo/@jsrepo/transform-biome@798

@jsrepo/transform-filecasing

pnpm add https://pkg.pr.new/jsrepojs/jsrepo/@jsrepo/transform-filecasing@798

@jsrepo/transform-javascript

pnpm add https://pkg.pr.new/jsrepojs/jsrepo/@jsrepo/transform-javascript@798

@jsrepo/transform-oxfmt

pnpm add https://pkg.pr.new/jsrepojs/jsrepo/@jsrepo/transform-oxfmt@798

@jsrepo/transform-prettier

pnpm add https://pkg.pr.new/jsrepojs/jsrepo/@jsrepo/transform-prettier@798

commit: 3ead72e

svelte/compiler and vue/compiler-sfc ship as CommonJS. Importing them by an
explicit file URL (as loadPeerCompiler does after resolving from cwd) exposes
their exports under the namespace's `default` key rather than as top-level
named exports, so `compiler.preprocess` was undefined and the build failed with
"n.preprocess is not a function". Unwrap the CJS default when the imported
namespace only carries `default`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UwUar3KD5KEWVRN4GWgBu5
Importing the resolved svelte/compiler (CJS) file by URL puts its exports under
`default`, and whether the exports lexer surfaces named exports varies by Node
version (worked under Node 22 locally, failed under Node 24 in CI), so
`compiler.preprocess` was undefined and the build threw "n.preprocess is not a
function". Load these CommonJS compilers with require() instead, which returns
module.exports directly with the real API, matching the condition require.resolve
already selects. ESM-only modules fall back to a dynamic import with default
interop.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UwUar3KD5KEWVRN4GWgBu5
@ieedan
ieedan marked this pull request as ready for review July 10, 2026 20:24
@ieedan
ieedan merged commit fa66592 into main Jul 10, 2026
9 checks passed
@ieedan
ieedan deleted the claude/air-calculation-discrepancy-nyzce6 branch July 10, 2026 20:24

This branch was successfully deployed

1 active deployment
Preview — 3ead72e3 Deployed Jul 10, 2026 by vercel[bot]
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.

2 participants