Skip to content

Fix/wordpress jsx runtime#44

Merged
retlehs merged 2 commits into
roots:mainfrom
csorrentino:fix/wordpress-jsx-runtime
Jun 1, 2026
Merged

Fix/wordpress jsx runtime#44
retlehs merged 2 commits into
roots:mainfrom
csorrentino:fix/wordpress-jsx-runtime

Conversation

@csorrentino
Copy link
Copy Markdown
Contributor

Problem

Projects using wordpressPlugin() with JSX block files fail to build under Vite 8 with:

Error: [vite]: Rolldown failed to resolve import "react/jsx-runtime" from "...block.jsx".

Oxc defaults to React's automatic JSX runtime and injects import { jsx as _jsx } from 'react/jsx-runtime' into every JSX file. WordPress block projects don't install react — they rely on wp.element — so this import can't be resolved and the build fails with a hard error.

Context

I ran into this while upgrading a Sage project that includes a lot of jsx blocks in the theme, similar to what Radicle does. I was very confused because another project using the most recent version of Radicle doesn't have this issue. It turns out this issue was masked in Radicle because react gets pulled in by @wordpress/icons.

What this PR does

Adds a config() hook to wordpressPlugin that switches the JSX transform to classic mode and points it at wp.element:

oxc: {
  jsx: {
    runtime: 'classic',
    pragma: 'wp.element.createElement',
    pragmaFrag: 'wp.element.Fragment',
  },
}

runtime: 'classic' disables the automatic JSX runtime import. pragma and pragmaFrag point JSX calls at wp.element.createElement and wp.element.Fragment, which are provided globally by WordPress.

Three new options are also added to WordPressPluginConfig for projects that need to override the defaults:

interface WordPressPluginConfig {
  jsx?: false;          // set to false to opt out of JSX configuration entirely
  jsxFactory?: string;  // default: 'wp.element.createElement'
  jsxFragment?: string; // default: 'wp.element.Fragment'
}

Happy to pull out this config override option if it seems unlikely to be used.

Also, although this seems like a sensible default, an alternative to this PR would be adding something like this to the vite config of each project:

// vite.config.js

oxc: {
  jsx: {
    runtime: 'classic',
    pragma: 'wp.element.createElement',
    pragmaFrag: 'wp.element.Fragment',
  },
}

**Debugged with a lot of help from Claude

Copy link
Copy Markdown
Member

@retlehs retlehs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@retlehs retlehs merged commit 3f812dd into roots:main Jun 1, 2026
3 checks passed
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