How to use external React components in your Gutenberg blocks

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:

ERROR in ./node_modules/react-select/dist/react-select.es.js Module not found: Error: Can't resolve 'react' in '/node_modules/react-select/dist' ERROR in ./node_modules/react-select/dist/react-select.es.js Module not found: Error: Can't resolve 'react-dom' in '/node_modules/react-select/dist'

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:

// ... const webpackConfig = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'build'), filename: 'myplugin.build.js', libraryTarget: 'window', }, externals: { 'react': 'React' 'react-dom': 'ReactDOM', }, }; // ... webpack.config.js

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:

const wplib = [ 'blocks', 'components', 'date', 'editor', 'element', 'i18n', 'utils', 'data', ]; const webpackConfig = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'build'), filename: 'myplugin.build.js', library: ['wp', '[name]'], libraryTarget: 'window', }, externals: wplib.reduce((externals, lib) => { externals[`wp.${lib}`] = { window: ['wp', lib], }; return externals; }, { 'react': 'React', 'react-dom': 'ReactDOM', }), } webpack.config.js

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.

Via https://www.cssigniter.com/how-to-use-external-react-components-in-your-gutenberg-blocks/