Skip to content

[Bug] ssr.target: 'webworker' still defaults Rolldown SSR builds to Node-style CJS interop, emitting createRequire(import.meta.url) and crashing on Workers #21962

Description

@jmalmo

Describe the bug

For SSR builds with ssr.target: 'webworker', Vite still defaults build.rolldownOptions.platform to 'node' for every server build. This causes Rolldown to emit createRequire(import.meta.url) for CJS interop, which crashes on Cloudflare Workers / workerd because import.meta.url is undefined in bundled worker modules.

The worker fails during module initialization before any request is handled:

TypeError: The argument 'path' must be a file URL object, a file URL string,
or an absolute path string. Received 'undefined'
  at createRequire (node:module:34:15)
  at null.<anonymous> (jsx-runtime.mjs:34:33)

Vite already treats ssr.target === 'webworker' as a special case elsewhere — ssr.resolve.conditions defaults to webworker/browser-style conditions, resolveEnvironmentOptions() threads isSsrTargetWebworkerEnvironment into resolve + keepProcessEnv, and resolveRolldownOptions() special-cases SSR webworker output defaults. But resolveBuildEnvironmentOptions() still hard-defaults all server builds to platform: 'node'.

We intend to submit a PR for this — see #21963 (currently draft).

Reproduction

This does not require Nitro / TanStack / a framework. A plain Vite SSR repro:

vite.config.js

import { defineConfig, defaultClientConditions } from 'vite'

export default defineConfig({
  build: { minify: false },
  ssr: {
    target: 'webworker',
    noExternal: true,
    external: ['node:assert'],
    resolve: {
      conditions: [...defaultClientConditions, 'worker'],
    },
  },
})

dep-cjs-node-assert/package.json

{ "name": "dep-cjs-node-assert", "private": true, "main": "index.cjs" }

dep-cjs-node-assert/index.cjs

const { ok } = require('node:assert')
ok(true)
module.exports = 'cjs-ok'

src/entry-worker.js

import msg from 'dep-cjs-node-assert'
addEventListener('fetch', (event) => {
  event.respondWith(new Response(msg))
})

Steps to reproduce

  1. Set up the files above (or use the existing playground/ssr-webworker with a CJS fixture added)
  2. Run vite build
  3. Inspect the output: grep "createRequire" dist/entry-worker.js — it contains createRequire(import.meta.url)
  4. Run under a worker runtime: npx wrangler dev dist/entry-worker.js — crashes at startup

System Info

System:
  OS: macOS 15.5 (Darwin 24.6.0)
  CPU: Apple M3 Max
  Memory: 36 GB
Binaries:
  Node: 22.14.0
  pnpm: 10.32.1
  bun: 1.3.2
npmPackages:
  vite: npm:rolldown-vite@^7.3.1 => 7.3.1
  rolldown: 1.0.0-rc.10

Used Package Manager

pnpm

Logs

Click to expand!
# Build output contains createRequire:
$ grep "createRequire" .output/server/_chunks/jsx-runtime.mjs
import { createRequire } from "node:module";
var __require = /* @__PURE__ */ createRequire(import.meta.url);

# Worker crashes at startup:
$ wrangler dev .output/server/index.mjs
TypeError: The argument 'path' must be a file URL object, a file URL string,
or an absolute path string. Received 'undefined'
  at createRequire (node:module:34:15)
  at null.<anonymous> (jsx-runtime.mjs:34:33)

Validations

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions