Skip to content

@shopify/ui-extensions-server-kit@5.4.1 ships vendored React 18, crashes on React 19 consumers #7576

@shopify-river

Description

@shopify-river

Summary

@shopify/ui-extensions-server-kit@5.4.1 (latest on npm) ships a broken CJS bundle that vendors its own copy of React 18 via a hardcoded pnpm-store path. Any consumer that does not have React 18 installed at that exact path (e.g. a React 19 consumer, or a consumer using a different package manager) crashes at module load with:

TypeError: Cannot read properties of undefined (reading 'ReactCurrentDispatcher')

Repro

mkdir repro && cd repro
npm init -y
npm install react@19 @shopify/ui-extensions-server-kit@5.4.1
node -e "require('@shopify/ui-extensions-server-kit')"

…or in any project that pins React 19, simply import { INITIAL_STATE } from '@shopify/ui-extensions-server-kit' is enough to blow up at import time inside Jest, Vitest, Node, etc.

Root cause

Inspecting the tarball published to npm:

$ tar -tzf ui-extensions-server-kit-5.4.1.tgz | grep node_modules | head
package/node_modules/@testing-library/react/...
package/node_modules/@types/react/...
package/node_modules/@vitejs/plugin-react/...
package/dist/node_modules/.pnpm/react@18.3.1/node_modules/react/...

The package unintentionally ships its own node_modules/ and the build emits dist/_virtual/jsx-runtime.cjs.js with a hardcoded require:

// dist/_virtual/jsx-runtime.cjs.js
const e = require("../node_modules/.pnpm/react@18.3.1/node_modules/react/jsx-runtime.cjs.js");

5.4.0 did not have this problem — its ExtensionServerProvider.cjs.js simply does require("react") (and peerDependencies correctly declares react: ">=17.0.2"). Between 5.4.0 and 5.4.1 the build pipeline started bundling React (and testing-library/plugin-react devDeps) into the published artifact.

Suggested fix

Whatever Rollup/Vite plugin change introduced the _virtual/jsx-runtime.cjs.js redirection in 5.4.1 should be reverted so react (and react/jsx-runtime) remain external. The package should not ship a node_modules/ directory at all — adding a files field to package.json, or fixing the prepublish/pack step, would prevent this from recurring.

Impact

5.4.1 is currently the only stable version that exposes supportedFeatures.runsOffline on ExtensionPayload (renamed from offlineMode in 5.4.0). Consumers that want that field — including Shopify/pos-mobile, which pins React 19 — currently cannot bump past 5.3.x without applying local workarounds (TypeScript module augmentation), because 5.4.0 has the wrong field name and 5.4.1 won't load.

Workaround

Pin to 5.4.0 and live with supportedFeatures.offlineMode, or stay on 5.3.x and augment the type locally.

cc Aaron Schubert aaron.schubert@shopify.com — surfaced while landing shop/world#730930.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions