Can't get React to work with Sage 10 using bud

Hi folks!

I have been trying to get Sage 10 to use React 18.2 but so far nothing. I added @bud-react to see if it would make it easy, but can’t get it to run. I keep getting the same error:

TypeError: (0 , react_dom__WEBPACK_IMPORTED_MODULE_2__.createRoot) is not a function

If it helps here’s my package.json and the app.js file.

// package.json
{
  "name": "sage",
  "private": true,
  "browserslist": [
    "extends @roots/browserslist-config"
  ],
  "engines": {
    "node": ">=16.0.0"
  },
  "type": "module",
  "scripts": {
    "dev": "bud dev",
    "build": "bud build",
    "translate": "yarn translate:pot && yarn translate:update",
    "translate:pot": "wp i18n make-pot . ./resources/lang/sage.pot --include=\"app,resources\"",
    "translate:update": "for filename in ./resources/lang/*.po; do msgmerge -U $filename ./resources/lang/sage.pot; done; rm -f ./resources/lang/*.po~",
    "translate:compile": "yarn translate:mo && yarn translate:js",
    "translate:js": "wp i18n make-json ./resources/lang --pretty-print",
    "translate:mo": "wp i18n make-mo ./resources/lang ./resources/lang"
  },
  "devDependencies": {
    "@roots/bud": "6.8.0",
    "@roots/bud-react": "6.8.0",
    "@roots/bud-tailwindcss": "6.8.0",
    "@roots/sage": "6.8.0"
  }
}
// app.js
import domReady from '@roots/sage/client/dom-ready';
import React from 'react';
import { createRoot } from 'react-dom';

/**
 * Application entrypoint
 */
domReady(async () => {
  const App = () => <div>Hello world</div>;

  createRoot(document.getElementById('root')).render(<App />);
});

/**
 * @see {@link https://webpack.js.org/api/hot-module-replacement/}
 */
import.meta.webpackHot?.accept(console.error);

And I’m using the default configuration from sage on my bud.config.js I just really updated the proxy origin.

Any help would be appreciated.

Digging a little bit deeper it seems that whenever I import React. Sage forces it to be:

<script src='https://mydomain.test/wp-includes/js/dist/vendor/react.min.js?ver=17.0.1' id='react-js'></script>
<script src='https://mydomain.test/wp-includes/js/dist/vendor/react-dom.min.js?ver=17.0.1' id='react-dom-js'></script>

It doesn’t matter if I added react 18.2 to the project manually, so I’m curious about this behaivior and how I can avoid it.

You’ll need to disable the two extensions that map wordpress provided modules to the versions provided by wordpress:

app.extensions.get(`@roots/bud-wordpress-dependencies`).disable()
app.extensions.get(`@roots/bud-wordpress-externals`).disable()

There are a couple things to look out for:

  • You will need to install @wordpress/blocks, or remove the code that uses it from ./resources/scripts (since this is no longer mapped to window.wp.blocks webpack will now see it as a missing dep).
  • I have no idea what happens if a plugin uses the provided React and you are using React 18. Hopefully t’s okay but if you see an error about “multiple copies of React” or “breaking the rules of hooks” this could be the culprit.

Thanks!

This seems to solve the issue, I wonder if I will run into @wordpress/blocks being an issue since the plan for this small website is to just use React as the main front end and consume the WP content via the REST API.

I will keep an eye open in case I find anything!

It’s probably not going to be a problem unless you are trying to do development in the editor.

In that case you’d probably be better off setting up your editor mods in a site-specific plugin anyway. I don’t think themes should register blocks :man_shrugging:t3:.