This guide is for you who want to write code for Gutenberg with ES6, ESNext and JSX syntaxes, and need to set up webpack and babel to transform these into files you can use in the Gutenberg editor. We’ll look at what you need to do, why, and how we can use and extend the defaults from WordPress and customize them to fit our needs.
If you are brand new to the whole npm, webpcak and Babel concepts, you should read the following section that aims to explain the basics of how these tools work and how you use them. However if you have done this before and are familiar with the process, perhaps by developing with React, skip ahead to the next section where we’ll actually set things up.
For beginners: npm, webpack and babel
If you are unsure why we need to do all this for writing Javascript for Gutenberg, I’d recommend that you read my post that explores the basics of developing for Gutenberg – where I explain the difference in Javascript versions and why it’s worth the trouble.
If you have never done this before, you will first need to install Node.js on your computer. Click the link, download and install it. Included in Node.js you’ll get a tool that we’ll use to set up most of the configuration. This tool is npm
, which allows you to install Javascript libraries and run scripts through command-line / terminal. You can alternatively use yarn
if you prefer it, but for this guide we’ll use npm
.
npm
This guide won’t go into detail about all the things you can do with npm
, but it’ll explain the basic concept of it and things that are relevant for our purposes. We’ll use npm
for two things; for installing required libraries into our project, and for running commands to build (compile) our Javascript files.
With npm
you can install any public open-source Javascript packages. If we were to develop with React (outside WordPress) we would need to install React libraries and webpack libraries. WordPress offers a whole range of libraries (mainly for Gutenberg) you can install, but we are really only interested in one: @wordpress/scripts
– which helps us simplify our configuration.
Whenever you install a library, npm
will create a subfolder “node_modules
” where the installed libraries are stored. You will never need to enter this folder or change anything here, but keep in mind that this folder will easily contain (literally!) tens of thousand of files. This is a folder you never should commit to git or include in any finished theme or plugin. The libraries are only needed while developing.
When your environment is set up you can use npm
to run scripts defined in your package.json
file. Depending on the project you’d normally have at least two scripts; one for building the scripts, and one for starting “watch mode”. In “watch mode” npm
starts a process in the terminal that waits and listens to changes made in any file, and compiles them at run-time whenever you hit save. You might be familiar with this concept if you have used SCSS or LESS compiler programs before. It’s much more efficient to run a “watch” script in the background that recompiles every time you save, instead of going to terminal and run the build command after every change.
webpack and babel
You can get by developing for Gutenberg without doing any webpack or babel configuration. Because we use WordPress’ libraries they will handle it for us. However this has one drawback – it defaults to a fixed location and filename for both your source and output files. Your whole Javascript development needs to be written inside one file, in project-folder/src/index.js
, and the build will always end up in project-folder/build/index.js
. If you are fine with this, you can skip the whole part about webpack configuration. However if you are developing a theme or plugin with several Gutenberg features (custom blocks, filters, etc) you might at least want a different output filename and location as well as allowing for multiple files.
If you use WordPress’ package to handle setup (@wordpress/scripts
), Babel is already set up. But you should be aware that WordPress’ package might not include plugins you might want to use. There’s for example a package that allows you to use the new so-called “arrow functions” ( myFunction = (param) => { }
), for defining functions without needing to bind this
. If you absolutely want to use these ESNext features, you’ll need to configure Babel yourself instead of using WordPress’ defaults. I’ll go through how below.
The process
The process of developing with webpack once everything is set up and installed, is to navigate to your project folder in terminal and start the “watch” script. It’ll stay open and listen to changes made in your JS files. Whenever you hit save in your Javascript files, the terminal will output information (hopefully) that it has successfully re-compiled the file. If there were any compile errors, they will appear in the terminal. To stop the “watch” process, hit CTRL + C.
Setting up the environment
I assume you already have a local WordPress running on some LAMP stack (programs such as WampServer, XAMPP, Docker or similar), and that you have either a plugin or theme ready to start coding your Javascript in.
I recommend creating a subfolder dedicated for your Javascript development as you might end up with several config files and folders. This makes it easier to separate out files and folders (for example node_modules/
) you don’t want to include in git commits or final builds. But it’s perfectly fine to use your main theme or plugin folder as project folder for Javascript development.
In terminal (Mac OS terminal or Windows Command Prompt both work fine) navigate to your project folder. As for this tutorial I’ll assume we’re in a theme and have created an empty subfolder gutenberg-dev/
as our project folder.
The first step is initializing a npm project – which is basically just telling npm
to generate a package.json
file. This package.json
file informs npm
about what packages are required and what scripts are available for running. Type this in terminal;
npm init -y
This generates a package.json
file with default content in your project folder.
Next we’ll install WordPress’ package that will help us reduce the amount of configuration we’ll need to do. Run this command:
npm install --save-dev --save-exact @wordpress/scripts
The tag --save-dev
is informing npm
that the given libraries are only necessary for development, and --save-exact
is making sure npm
only installs one version, the latest.
Open the package.json
file in your editor. (npm
will also have generated a package-lock.json
upon installing packages, you can just ignore this file, it’s package.json
you’ll make changes in). It should be filled with default configuration, and you might notice that the package installation we did earlier added an entry of @wordpress/scripts
of a certain version in devDependencies
. As you’ll install more packages, npm
will update package.json
with entries for each package. All we need to be concerned about in this file is the scripts
property, which are for scripts (commands) that you can use npm
to run. Update the scripts property into this (you can remove the default “test”):
package.json
"scripts": { "build": "wp-scripts build", "start": "wp-scripts start" },
This piece of code tells npm
that we have two scripts we can run in this project folder; “build” and “start”. We run a script with the command npm run <scriptname>
, in which npm
will look in package.json
and perform the command defined as its value. We use the tool wp-scripts
that came in the package we installed just now to either compile our Javascript once ("build"
) or start “watch” / “listen” mode to compile whenever we save changes ("start"
).
This also allows us to use WordPress’ webpack and Babel config, so we don’t have to do it ourself.
In your project folder create a subfolder called src/
. Inside this folder create an index.js
file.
If you are fine with the webpack defaults, you are now done! Write your ES6 and JSX code in index.js
, and tell npm
to compile them by either running the build command:
npm run build
or start a “watch” process in terminal that listens to changes made with this command (use CTRL+C to stop the watching process):
npm run start
Running either of these will generate a build/
subfolder in your project directy with the compiled result in build/index.js
.
If you wish to change the location and filenames of your source or output files, read on.
Configuring source and output filenames and paths
If you, like me, are not satisfied with the default filename and structure – especially for the output file(s), you need to look into configuring webpack. Normally, for example if you were developing for React outside WordPress, you’d need to set up a full webpack configuration with Babel plugin. Luckily WordPress takes care of this for us, and allows us to extend WordPress’ own webpack config and adjust only the parts we want to change.
In your project folder (same folder as package.json
) create a file named webpack.config.js
and open it in your editor. Write the following in this file:
webpack.config.js
const defaultConfig = require("@wordpress/scripts/config/webpack.config"); const path = require('path'); module.exports = { ...defaultConfig, entry: { 'block-mynamespace-myblock': './src/block-mynamespace-myblock.js' }, output: { path: path.join(__dirname, '../assets/js/gutenberg'), filename: '[name].js' } }
The first thing we do is fetching @wordpress/scripts
‘s webpack config into the variable defaultConfig
. Inside the webpack config module.exports
, the first thing we do is applying everything in defaultConfig
by using the spread operator (...
). These two parts are making sure we extend WordPress’ webpack config by including everything inside it. After the spread operator we can adjust or add any property we wish to change; in our case the source location and output location.
The entry
property defines the source files, which is by default ./src/index.js
. Each entry in entry
property is a key+value pair that webpack will compile (and watch) from. In the above example I’ve defined ‘block-mynamespace-myblock
‘ located in src/block-mynamespace-myblock.js
as one entry point. You can add as many key+value pairs here for each source file you wish to compile.
The output
property decides the location of compiled files. In path
you define the destination folder for all compiled files. I’m using a path helper to be able to navigate directories properly in my config. In the example above I’m telling webpack that all compiled files should end up in my theme-folder/assets/js/gutenberg/
folder. The important thing is using ../
to traverse up in the directory tree, out of the project folder, and into another folder where I want all my theme’s Javascript files to be. Adjust the path to fit your project structure.
Secondly I’m telling webpack that all filenames should be named as their corresponding entry
key names. This webpack config will compile my theme-folder/gutenberg-dev/src/block-mynamespace-myblock.js
into theme-folder/assets/js/gutenberg/block-mynamespace-myblock.js
. If I were to add another sourcefile as key+value pair in entry
, it would be compiled into the same folder with the key as its filename.
Make your desired adjustments in your webpack.config.js
file and save. Rerun any of the npm
build commands to generate files in their new locations.
However I want to include one last tip in this guide. WordPress’ default config for Babel might be lacking certain Babel plugins for certain new features in ESNext. For example with the above default and WordPress’ defaults you will not be able to use arrow-functions in your code. If this matters to you, read on.
Add support for newest ESNext syntaxes with Babel
As of the time of writing this WordPress’ default Babel setup is missing support for “experimental syntaxes”, which includes for instance arrow functions. To add support for this, you need to provide your Babel config file, and as of yet I have not found a way to extend WordPress’ Babel config like we did with webpack config above. So we need to redefine Babel presets as well as adding the “experimental syntaxes” plugin. But don’t worry, it’s a very small file.
The first step is installing some packages we need for Babel presets – we need to install the same ones defined in WordPress’ Babel config. Run this command for installing @babel/preset-env
and @babel/preset-react
, as well as the package we’re interested in; @babel/plugin-proposal-class-properties
:
npm install --save-dev @babel/preset-env @babel/preset-react @babel/plugin-proposal-class-properties
The second step is adding the Babel configuration file. In your project folder, create a file named .babelrc
(no file extension).
Note for Windows: If you are sitting on a Windows machine you are not allowed to create files without file extensions. To go around this you can create this file using terminal/Command prompt. Run this command:
echo hi > .babelrc
This command will output “hi” into the file .babelrc
in the current folder. You can now open this file in your editor, remove the “hi”, and add the actual content below.
Your .babelrc
should look something like this:
.babelrc
{ "presets": ["@babel/preset-env", "@babel/preset-react"], "plugins": [ [ "@babel/plugin-proposal-class-properties" ] ] }
We define the same presets as you’d normally do in a React project, and the same as WordPress does it. What we are adding is the plugins
property. Inside the array of plugins
we add the @babel/plugin-proposal-class-properties
which is the necessary Babel plugin for “experimental syntaxes” such as arrow functions.
Conclusion
Keep in mind that WordPress can change its configuration any time, this is especially likely to happen because Gutenberg is fairly new. Because we extend WordPress’ configuration we might at one point need to update our configuration again to fit our needs. Perhaps WordPress decides to include support for experimental syntaxes so we don’t have to do the whole Babel configuration.
This is by no means an exhaustive guide in setting up Webpack and Babel, but the result of a whole lot of experimenting and figuring things out. I hope this has helped you in learning how to set up your own Gutenberg development environment, and made it easy enough so this is not such a big hurdle in starting to learn ES6, ESNext, JSX, and all that good stuff beneficial for developing for Gutenberg!