Skip to content

Throw a strict build error for missing, unresolved, or externalized virtual: modules #22673

Description

@rtritto

Description

Currently, if a virtual: module is imported (e.g. import 'virtual:my-plugin:global-state') but cannot be resolved by any plugin, or is inadvertently marked as external during an SSR build, the bundler might succeed silently or just emit a non-blocking warning. This causes the application to crash at runtime with a Cannot find module 'virtual:...' error.
Additionally, if a virtual module is resolved but lacks explicit side-effects, it might be silently tree-shaken from the output, leading to successful builds that are intrinsically broken at runtime.

Suggested solution

Since virtual: (and \0 prefixed) modules are strictly build-time constructs provided by plugins, they inherently cannot exist at runtime. I would like Vite / Rolldown to enforce a strict behavior:

  1. Throw a hard build error if an import path starting with virtual: remains unresolved after all plugins have been executed
  2. Prevent virtual: modules from being externalized: they should automatically circumvent external SSR configurations. If a virtual module ends up as a raw import in the final bundle output, the build must fail
  3. (Optional but helpful) Emit a warning/error if a bare virtual import used for side-effects (e.g. import 'virtual:plugin-init') is completely tree-shaken and dropped from the final bundle

Alternative

  • Relying on plugin authors to correctly flag moduleSideEffects, though this doesn't protect the user from missing plugins or misconfigured SSR externalization
  • Manually inspecting the generated .mjs server bundles to verify that virtual modules haven't leaked into the runtime code, which is a slow and error-prone DX

Why is this needed?

Failing the build early and explicitly with a dedicated error (e.g. [UNRESOLVED_VIRTUAL_MODULE]) would save developers hours of debugging runtime crashes in production or SSR environments. Virtual modules leaking into runtime or being silently ignored is silently dropped is a guaranteed fatal error, so the build should fail immediately.

Validations

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions