Let’s get started with a couple definitions.
What is ES.Next?
ES.Next refers to versions of ECMAScript from ES6 and beyond. ES6+ brings a load of great features to the scripting language but is not completely supported by all browsers. In order for us to take advantage of these new features we must add a build process to our project with a transpiler.
What is a transpiler?
A transpiler is a source-to-source compiler that takes the source code of a program written in one programming language as its input and produces the equivalent source code in another programming language (Wikipedia).
Setting up the build process
Create a new folder in the plugins directory of your WordPress installation and initialize the NPM package.json file:
# Create our plugin folder and move into it $ mkdir wp-content/plugins/esnext-starter $ cd wp-content/plugins/esnext-starter # Initialize our NPM package.json file. $ npm init -y
Next we’ll install our dependencies that NPM will track in our newly created package.json file.
# Install webpack $ npm install --save-dev webpack webpack-cli # Install Babel $ npm install --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader # Install utility for using environment variables across platforms. $ npm install --save-dev cross-env
Let’s go over each dependency we just installed to understand the purpose behind installing it.
webpack and webpack-cli
Webpack is our module bundler and the core of the build process. We will setup a configuration file which tells webpack how to bundle together all of our assets. Webpack-cli is a tool used to run webpack on the command line.
@babel/core and babel-loader
@babel/core is the compiler core. We need this to use Babel within our build process. Babel-loader is a transformation (loader) for webpack that is applied on your source code. This package tells webpack to run the transpiling we’ve configured using Babel.
.browserlistrc file with our target environment(s) which the preset will use to transpile everything.
This package is a configuration preset for Babel that includes plugins specific to transpiling with React. Since we are using React to develop Gutenberg blocks, we’re going to need this.
These are the packages included with this preset as of this writing:
@babel/plugin-syntax-jsx: Allow parsing of JSX.
@babel/plugin-transform-react-jsx: Turn JSX into React function calls.
@babel/plugin-transform-react-display-name: Add displayName to React.createClass calls. The displayName string is used in debugging messages.
This package allows us to set and use environment variables across platforms. The most common use I’ve experienced is setting the environment to development or production which is used to set or load separate configurations.
Configuring Babel, webpack, and scripts
First let’s create a
.browserlistrc file and add the following content to it. Remember this file is automatically read by the
@babel/preset-env package which sets our transpiler target environments. I’m using the same configuration that the Gutenberg project is using to ensure consistency.
Now create a
.babelrc file and add the following content to it. For now we’re just telling Babel to load the
@babel/preset-react presets when it runs.
Finally, lets configure webpack by creating a
webpack.config.js file with the following contents.
At the top of this configuration we are setting up a few variables that we use in the actual webpack configuration (the
module.exports code block).
By configuring our “externals” we are telling webpack to exclude these dependencies, which are referenced throughout our code, from the compiled output. WordPress Core provides Gutenberg’s own components from the
wp global variable as well as React and ReactDOM from
react-dom respectively. We don’t need to include these in our own output just like we’ve not had to include jQuery with our plugins and themes.
You can read more about Externals in the webpack documentation.
With the next two lines we are ensuring a mode has been set for webpack based on an environment variable passed. The mode options tells webpack which built-in optimizations it should use. We are setting this explicitly because webpack does not automatically set it.
You can read more about the Mode configuration option in the webpack documentation. You can also see what the built-in optimizations are set based on this setting.
And finally we put it all together at the end to finish our webpack configuration. For this walk-through we are going to write our Gutenberg block in a single file named
block.js. We are setting this as the entry file for webpack to start bundling from. From there we are telling webpack to put the output into a
The last bit of our configuration has to do with Babel. Within the
module property we are setting rules that webpack goes through and passes the target files to the module that will handle it. Here we are telling webpack to pass any file with the
.js extension to the
babel-loader module. Babel will do its magic and pass its result back to webpack for bundling.
Now that we’ve configured our build process, we should setup a couple scripts we can use to easily run our build process. Add the following to your
Now from the terminal you can run
npm run build to bundle everything together according to webpack’s
production optimizations. Alternatively run
npm run dev to bundle with webpack’s
development optimizations and re-run when a change has been detected.
Setting up our plugin
Now that our build process is setup we need to hook into WordPress and load our Gutenberg block. Let’s create a few new files in our plugin directory:
editor.css: This file will contain the styles for our block while in the editor interface.
style.css: This file will contain the styles for our block within the editor and in our theme. It’s important that these styles are shared to keep the look exactly the same in the editor as it is on the front-end.
index.php: This is our plugin file where we will enqueue all the assets for our block.
There are only two hooks we need to use in order to load our Gutenberg block:
We will hook into
enqueue_block_assets to enqueue our
style.css file for both the editor and front-end.
And we will hook into
enqueue_block_editor_assets to enqueue our
editor.css file and the bundled
block.build.js file for the editing interface.
Create a Block
Let’s add some code to our
block.js file to create our new block. In order to register a new block we need to use the
registerBlockType function from the
Remember we don’t have to
npm install @wordpress/blocks and instead Gutenberg exposes this package through the
wp external we defined earlier. There are a number of packages accessible through this global variable but we only need
wp.blocks right now. Here is how I’d access the
The minimal properties we need to create a block is a name, title, category, an edit function, and a save function.
The name needs to be a unique string. According to the Gutenberg Handbook names need to be structured as
namespace/block-name, where namespace is the name of your plugin or theme. I’m going to use
gwg/esnext-starter for this walk-through.
I think the Gutenberg Handbook explains the
save functions best:
“When registering a block, the edit and save functions provide the interface for how a block is going to be rendered within the editor, how it will operate and be manipulated, and how it will be saved.”
In my experience you will be working within the
edit function the most. The edit function is where you will hook into different parts of the Gutenberg editor. Settings and controls for manipulating your block from within the editor will also be added and managed here.
save function defines what the final markup should be. It’s important to think about your final markup before you dive deep into developing a block. It is possible to change the markup later but we’ll go over that in a future article.
save function is not just used to define the final markup but also to verify the markup when the block is loaded within the editor. Should the markup not be exactly the same after the block has been saved you will see an invalid block error. My tip for avoiding this is to ensure only static content is returned here. Dynamic content doesn’t belong here.
You’ll notice we are rendering a paragraph tag with
props.className as the selector. The
save functions receive a number of values through the
className is one of them and is generated from our block name. Our block name would be converted to
.wp-block-gwg-esnext-starter selector which we will use in our stylesheets for both the front-end and back-end.
Once you’ve added your own styles to the stylesheets we created, you will have created your first Gutenberg block! Here’s a couple screens of the block within the front-end and the back-end.
I hope this walk-through has helped you understand the why and how of a basic build process with React, Babel, and webpack. Most importantly I hope it’s helped you get started with block development for Gutenberg and WordPress.
I’ve put all the code for this walk-through up on Github for reference.