How to use external React components in your Gutenberg blocks

Gutenberg itself already exposes a lot of components ready to be re-used in our custom blocks. Most of these are located in wp.components and wp.blocks, and they include helpful building blocks for every Gutenberg block: Text Controls, Toggles, Tooltips, Icon Buttons, Tabs, and many many others. Gutenberg’s native component library pretty much has us covered on all basic cases, on every kind of basic UI control we might need but still there are cases where we might need to take it a step further on some kind of more specialized custom block.

For example, while we were developing the new Icon Box block for our Gutenbee plugin we needed an Autocomplete Select component for our icon library, which Gutenberg does not provide (understandably):

For our Icon Box block we wanted to use the extremely flexible react-select library which covers all our needs.

Thankfully, as everything in Gutenberg is built on top of React, every single component in the vast React ecosystem is compatible and can be used in our custom blocks as well! All we need to do is npm install them and require them inside our codebase. However there’s one problem, if we were to just install any React component from npm, required it, and tried to compile our code we’d get something like:

That’s because react-select (as all React components) depends upon React and ReactDOM. Webpack (our bundle builder) doesn’t really know where to find React since we haven’t installed it as a project dependency.

The first solution would be to simply install react and react-dom from npm. This will easily solve everything, as React and ReactDOM would be fixed as dependencies in our project, but has the drawback of increasing our bundle size by about ~100kb as that’s the total filesize of React plus ReactDOM (minified). Another more serious drawback of this solution is that we’re going to end up with a disparity between the React version that Gutenberg uses and the version that our plugin uses. What we’d really really want would be to have a guaranteed version parity (i.e. use the same React version as WordPress).

Thankfully, Gutenberg also exposes React as a library in the global scope (the browser’s window object) and we can use that same React object with just a tiny adjustment in our Webpack configuration.

Webpack externals

Webpack provides a powerful externals property in its configuration which allows us to do just that.

The externals configuration option provides a way of excluding dependencies from the output bundles. Instead, the created bundle relies on that dependency to be present in the consumer’s environment.

The consumer’s environment in our case is the browser’s window object and Gutenberg makes sure to populate it with the React library. All we need to do is declare React and ReactDOM as an external dependency in our Webpack config:

And that’s it! Our module will compile perfectly now and use Gutenberg’s (i.e. WordPress’s) React, with same version guarantees and all!

In case you have been following our blog and you’ve read and implemented how to import Gutenberg’s native libraries as ES Modules you can achieve the same outcome by modifying the configuration we provided there by adding React and ReactDOM as keys to the initial object we’re passing into our reduce method:

The above code will handle everything, importing Gutenberg’s native libraries as ES modules and exposing React and ReactDOM into our bundle as a global dependency.

About the author

Vassilis Mastorostergios

Don’t let this guy’s surname scare you. It’s hard for Greeks too. Vassilis constantly struggles between his love for design and his passion for front-end development. Between the two though, one thing is absolutely certain, WordPress holds a special section in his heart.

4 comments

I started building with cgb-scripts and it took me a while to find the location where to apply the settings: node_modules/cgb-scripts/config/webpack.config.dev.js (or webpack.config.prod.js) where I pasted

externals: {
‘react’: ‘React’,
‘react-dom’: ‘ReactDOM’,
},

into module.exports = { … }. Do you know about any location where it won’t be overwritten by the next cgb-scripts update?

I’m afraid there’s no good way to have this in create-guten-block and not be overidden by an update or another npm install. If you want to do this properly you should really eject from (npm run eject) where you’ll have access to CGB’s webpack config and everything but from that point onwards you’d have to maintain that configuration yourself (no going back and you won’t be able to simply update CGB from npm). The other option would be to communicate this need to the CGB repo, perhaps the maintainers there will be helpful and somehow add it in their configuration. Hope this helps!