Skip to content

@astrojs/astro2tsx fails to load under Yarn 1: missing @emnapi/runtime #214

Open

Description

@andret2344

@astrojs/language-server 2.17.3 depends on @astrojs/astro2tsx 0.1.3, which imports @napi-rs/wasm-runtime 1.2.4. That package needs @emnapi/runtime as a peer dependency. astro2tsx lists @emnapi/core but not @emnapi/runtime, and Yarn 1 does not install peers, so loading @astrojs/check throws ERR_MODULE_NOT_FOUND: Cannot find package '@emnapi/runtime'. astro check then reports @astrojs/check as not installed, even though it is. The @astrojs/compiler-binding-wasm32-wasi package lists both @emnapi/core and @emnapi/runtime and does not have this problem.

Repro: Yarn 1.22, astro@7.4.5, @astrojs/check@0.9.12, then yarn astro check. Workaround: add @emnapi/runtime to devDependencies. Suggested fix: add @emnapi/runtime to astro2tsx's dependencies.

Activity

  1. astro-factory commented on Nov 2, 2026

    @astro-factory
    Contributor

    Triage complete

    • Prepare the workspace: ready
    • Install dependencies: complete
    • Reproduce the issue: confirmed
    • Diagnose the cause: high confidence
    • Verify the diagnosis: bug
    • Attempt a fix: verified
    • Publish the result: set triage: fix pending

    • Reproduced: Yes
    • Exploration: Yes — View branch
    • Unit Test: No — this is a package dependency declaration issue, not a compiler-output issue, so the existing snapshot/unit-test suites do not cover it
    • Priority: P2: has workaround. Users can work around the Yarn 1 failure by manually adding @emnapi/runtime to their project's devDependencies, so this is not build-breaking for most users, but it is a real packaging bug that breaks the out-of-the-box experience for an entire package manager.

    The problem is in crates/astro2tsx/package.json: @emnapi/runtime is listed only in devDependencies, but @napi-rs/wasm-runtime/runtime.js imports it unconditionally and lists it as a peer dependency. Package managers that do not auto-install peers (Yarn 1) therefore fail to load @astrojs/astro2tsx with ERR_MODULE_NOT_FOUND: Cannot find package '@emnapi/runtime'.

    I found a potential fix for this issue. The branch moves @emnapi/runtime into dependencies in crates/astro2tsx/package.json and updates pnpm-lock.yaml accordingly. A manual reproduction confirms the runtime module is then installed even under --legacy-peer-deps.

    Try this fix

    You can test this fix right now without waiting for a release:

    # @astrojs/compiler-binding
    npm i https://pkg.pr.new/@astrojs/compiler-binding@a36d6b5
    # @astrojs/compiler-rs
    npm i https://pkg.pr.new/@astrojs/compiler-rs@a36d6b5

    If this fixes your issue, please leave a comment letting us know (for example
    "confirmed, this fixes it"). A pull request will then be opened to get it merged.

    Full Triage Report

    Issue #214 Reproduction Report

    Original issue

    Title: @astrojs/astro2tsx fails to load under Yarn 1: missing @emnapi/runtime

    @astrojs/astro2tsx@0.1.3 depends on @napi-rs/wasm-runtime@1.2.4, which declares @emnapi/runtime as a peer dependency. astro2tsx itself only lists @emnapi/core and @napi-rs/wasm-runtime in dependencies; @emnapi/runtime is listed only in devDependencies. Yarn 1 does not auto-install peer dependencies, so consuming @astrojs/check (which pulls in @astrojs/language-server → @astrojs/astro2tsx) throws:

    ERR_MODULE_NOT_FOUND: Cannot find package '@emnapi/runtime'
    

    The suggested fix is to move/add @emnapi/runtime to astro2tsx's dependencies.

    Reproduction

    Because the issue is a package-installation / dependency-declaration bug rather than a compiler-output bug, there is no .astro input. I reproduced it by simulating a package manager that does not install peer dependencies (npm install --legacy-peer-deps).

    Files created

    • /triage/gh-214/astro2tsx-pkg/package.json — copy of /repo/crates/astro2tsx/package.json, with scripts.prepack removed so npm pack does not try to build.
    • /triage/gh-214/astro2tsx-pkg/index.js — copy of /repo/crates/astro2tsx/index.js.
    • /triage/gh-214/astro2tsx-pkg/index.d.ts — copy of /repo/crates/astro2tsx/index.d.ts.
    • /triage/gh-214/consumer/package.json — a minimal consumer package depending on @astrojs/astro2tsx from the tarball above.

    Steps

    cd /triage/gh-214/consumer
    npm install /triage/gh-214/astrojs-astro2tsx-0.1.3.tgz --legacy-peer-deps
    node --input-type=module -e "import * as m from '@astrojs/astro2tsx'; console.log(typeof m.convertToTsx);"

    Actual output

    Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@emnapi/runtime' imported from /triage/gh-214/consumer/node_modules/@napi-rs/wasm-runtime/runtime.js
        at Object.getPackageJSONURL (node:internal/modules/package_json_reader:314:9)
        at packageResolve (node:internal/modules/esm/resolve:768:81)
        ...
    

    This matches the reporter's ERR_MODULE_NOT_FOUND: Cannot find package '@emnapi/runtime'.

    Expected behavior

    Loading @astrojs/astro2tsx should not fail due to a missing peer dependency that the package itself relies on.

    Confirmation that the missing runtime is the blocker

    After manually installing the missing peer:

    npm install @emnapi/runtime@1.11.3 --legacy-peer-deps

    the loader gets past the runtime import and fails only because the reproduction tarball intentionally omits the .wasm file:

    Error: ENOENT: no such file or directory, open '/triage/gh-214/consumer/node_modules/@astrojs/astro2tsx/astro2tsx.wasm32-wasi.wasm'
    

    That confirms the original failure was the missing @emnapi/runtime dependency.

    Relevant source

    /repo/crates/astro2tsx/package.json currently has:

    "dependencies": {
      "@emnapi/core": "1.11.3",
      "@napi-rs/wasm-runtime": "1.2.4"
    },
    "devDependencies": {
      "@emnapi/runtime": "1.11.3",
      ...
    }

    @emnapi/runtime must move from devDependencies to dependencies for consumers that don't auto-install peers.

    Outcome

    Reproduced.


    Diagnosis

    Root cause

    /repo/crates/astro2tsx/package.json declares the runtime dependency on @emnapi/runtime only as a devDependency. However, the published loader (index.js) imports @napi-rs/wasm-runtime, and @napi-rs/wasm-runtime/runtime.js imports @emnapi/runtime at the top level:

    import * as emnapiRuntime from '@emnapi/runtime'

    @napi-rs/wasm-runtime@1.2.4 declares both @emnapi/core and @emnapi/runtime as peer dependencies:

    "peerDependencies": {
      "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4",
      "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4"
    }

    Package managers that auto-install peer dependencies (pnpm, npm ≥7) work because they see the devDependency version in the workspace/locally-published package and provide it transitively. Yarn 1 does not install peer dependencies, so consumers get ERR_MODULE_NOT_FOUND: Cannot find package '@emnapi/runtime' as soon as the loader is evaluated.

    Affected file

    • /repo/crates/astro2tsx/package.json (lines 29–39)

    Suggested fix

    Move @emnapi/runtime from devDependencies to dependencies (using the same pinned version as @emnapi/core, currently 1.11.3). Then run pnpm install so /repo/pnpm-lock.yaml reflects the change.

    This is consistent with the sibling @astrojs/compiler-binding-wasm32-wasi package, which lists both @emnapi/core and @emnapi/runtime in its dependencies.

    Confidence

    High. The error message, the peer-dependency declaration, and the reproduction all point to a single missing dependencies entry.


    Verification

    Claim

    @astrojs/astro2tsx should load in a Yarn 1 project without the user manually installing @emnapi/runtime.

    Verdict

    Bug.

    Evidence

    1. @napi-rs/wasm-runtime/runtime.js imports @emnapi/runtime unconditionally, so @emnapi/runtime is a real runtime requirement, not a development-only tool.
    2. @napi-rs/wasm-runtime@1.2.4 declares @emnapi/runtime as a peer dependency. A package that needs a peer for its own loader should either declare that package as a direct dependency or declare the peer itself; astro2tsx does neither.
    3. git blame shows the split (@emnapi/core / @napi-rs/wasm-runtime in dependencies, @emnapi/runtime in devDependencies) was introduced by 16dc5d1a "fix(napi): update WASI runtime bindings (fix(napi): update WASI runtime bindings #158)". There is no comment, commit message, or PR rationale indicating the runtime was intentionally left as a devDependency — the change bumped versions but kept the previous devDependency layout. This is best explained as an oversight during the update.
    4. The sibling @astrojs/compiler-binding-wasm32-wasi package (mentioned by the reporter) already lists both @emnapi/core and @emnapi/runtime in its dependencies, establishing the expected convention for emnapi-based wasm packages in this project.
    5. The reproduction confirms that a package-manager environment that does not auto-install peers fails with exactly the reported error.

    Confidence

    High. The missing entry is an accidental dependency-declaration omission, not a documented design choice.


    Fix

    What changed

    Moved @emnapi/runtime from devDependencies to dependencies in /repo/crates/astro2tsx/package.json and updated /repo/pnpm-lock.yaml accordingly.

    Diff

    --- a/crates/astro2tsx/package.json
    +++ b/crates/astro2tsx/package.json
    @@ -34,10 +34,10 @@
       },
       "dependencies": {
         "@emnapi/core": "1.11.3",
    +    "@emnapi/runtime": "1.11.3",
         "@napi-rs/wasm-runtime": "1.2.4"
       },
       "devDependencies": {
    -    "@emnapi/runtime": "1.11.3",
         "@napi-rs/cli": "3.7.4",
         "@types/node": "^22",
         "emnapi": "1.11.3",

    /repo/pnpm-lock.yaml was updated to move the @emnapi/runtime specifier from the devDependencies block to the dependencies block for crates/astro2tsx.

    Verification

    I rebuilt the reproduction tarball from the updated package.json and installed it with npm install --legacy-peer-deps. The install now pulls in @emnapi/runtime, so the loader gets past the runtime import. The only remaining error is the intentional absence of the .wasm bundle from the reproduction tarball:

    Error: ENOENT: no such file or directory, open '/triage/gh-214/consumer2/node_modules/@astrojs/astro2tsx/astro2tsx.wasm32-wasi.wasm'
    

    A real published package would include the .wasm file, so the reported ERR_MODULE_NOT_FOUND: Cannot find package '@emnapi/runtime' is resolved.

    Regression test

    No compiler snapshot or unit test applies because this is a dependency-declaration issue, not an output issue. The existing packages/compiler and crates/astro2tsx test suites do not exercise package-installation behavior. The reproduction in /triage/gh-214/consumer2 serves as a manual regression check.

    Changeset

    Added .changeset/runtime-peer-dep.md:

    ---
    "@astrojs/astro2tsx": patch
    ---
    
    Moves `@emnapi/runtime` from `devDependencies` to `dependencies` so package managers that do not auto-install peer dependencies (e.g. Yarn 1) can load `@astrojs/astro2tsx` without a manual install.

    Result

    Fixed.

    This report was made by an LLM. The analysis may be wrong, and the potential fix might not work, but is intended as a starting point for exploring the issue.

  2. added
    triage: fix pendingFix pushed to branch, waiting for reporter confirmation
    and removed on Nov 2, 2026
  3. andret2344 commented on Nov 2, 2026

    @andret2344
    Author

    The diff on factory/fix-214 is the right change. Note that the "Try this fix" links point at @astrojs/compiler-binding and @astrojs/compiler-rs, but the change is in @astrojs/astro2tsx, and no preview of it is published for a36d6b5 (pkg.pr.new/@astrojs/astro2tsx@a36d6b5 returns 404). So I could not test the fixed package itself. Adding @emnapi/runtime by hand under Yarn 1 does make astro check work, which matches the diagnosis.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions