Skip to content

Astro: void/email crashes astro dev with 'exports is not defined' when void is installed #411

Closed

Description

@Brooooooklyn

Summary

In an Astro app with @astrojs/cloudflare, importing void/email crashes astro dev with ReferenceError: exports is not defined when void is installed from npm. This is the same crash #407 fixes for runtimes Void owns, but Astro is left out of that fix.

Cause

#407 adds optimizeDeps.include: ['void > email-validator'] only when !isNodeTarget(config.target) && !frameworkOwnsCloudflareRuntime. frameworkOwnsCloudflareRuntime is true for every class b/c framework (plugin-inference.ts: SvelteKit, Nuxt, Analog, Astro). The stated reason is that those frameworks run dev server rendering in Node, which loads CommonJS itself.

That holds for SvelteKit (getPlatformProxy), Nuxt and Analog (Nitro). It does not hold for Astro: @astrojs/cloudflare 14.x calls cfVitePlugin({ viteEnvironment: { name: 'ssr' } }), so Astro's dev ssr environment runs in workerd. Void still applies only exclude: ['void'] there.

Vite skips dep discovery for bare imports whose importer is inside node_modules. So an installed void importing email-validator (CommonJS) sends it to workerd unconverted. The Astro playground links void via workspace:*, which hides the bug in this repo.

docs/guide/email/sending.md says sends from Astro in dev return BINDING_MISSING. In practice the route fails with a 500.

Reproduction

  1. Copy playground/astro and install void as a packed tarball (vp pm pack), not a symlink.
  2. Add src/pages/api/email.ts, which calls sendEmail from void/email, then run astro dev.
  3. GET /api/email returns 500 exports is not defined (at runInRunnerObject (workers/runner-worker/index.js)).
  4. With optimizeDeps.include: ['void > email-validator'] added to the ssr environment, it returns 200 {"ok":false,"error":"BINDING_MISSING"}, which matches the docs.

Suggested fix

Decide per environment whether it runs in workerd, not per framework class. For example, check whether the environment's resolve conditions include workerd, or at minimum treat detected?.name === 'astro' as needing the include. Add an Astro case next to the Analog case in plugin-dev-asset-routing.test.ts.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions