Gutenberg Sidebar – Setting up Webpack

Gutenberg Sidebar - Setting up Webpack

In this post, I’ll go over how to set up Webpack for our WordPress plugin. Webpack, in simple terms, will read an input and parse together an output.

Webpack can be a monster. We’ll have a fairly simple Webpack config that’ll handle our sidebar JavaScript and parse our SASS files.

Webpack has a concept of an entry point (i.e., starting point). In the case of our plugin, the entry point will be /src/js/index.js.

As a reminder, here’s our current plugin structure:

└── landing-page-gutenberg-template ├── landing-page-gutenberg-template.php ├── autoloader.php ├── languages ├── src │ ├── js │ │ └── index.js │ ├── scss │ │ ├── style.scss │ │ └── common.scss │ ├── languages │ └── includes │ └── Include files go here. ├── webpack.config.js └── .babel
Code language: AsciiDoc (asciidoc)

Our entry point for our SASS files will be /src/scss/style.scss.

Creating our JS and SASS Files

Let’s go ahead and create the empty JavaScript file and the empty SASS files.

Our JavaScript file will just contain a simple alert. Our SASS file will just include an import statement to load in common.scss.

Here is what I currently have as far as files go. All of the files are currently empty.

Gutenberg Folder Structure in VS Code.
Gutenberg Folder Structure in VS Code.

Here’s the contents of our JavaScript file:

alert("Hi there");
Code language: JavaScript (javascript)

And our common.scss and style.scss files are empty for now.

Basic Webpack Config for our JS Files

Here’s some basic Webpack config for parsing our JS file. When Webpack runs successfully, it’ll dump everything in a /dist/ folder in our plugin folder.

const BabelMinifyPlugin = require("babel-minify-webpack-plugin"); module.exports = { mode: process.env.NODE_ENV, entry: { sidebar: ["./src/js/index.js"], }, output: { filename: "[name].js", }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /(node_modules|bower_components)/, loader: "babel-loader", options: { presets: ["@babel/env"] }, }, ], }, externals: { // Use external version of React react: "React", }, optimization: { minimizer: [new BabelMinifyPlugin()], }, };
Code language: JavaScript (javascript)

As mentioned previously, our JavaScript entry point is at /src/js/index.js. We tell Webpack to look at this file, and if it is determined to be a .js or .jsx file, it loads Babel, prevents React from being included in the bundle, and minifies the output so the file size isn’t astronomical.

A Quick Note about Babel

We’ll be writing fairly modern JavaScript, which not every browser and client can recognize. Babel allows us to write code in a format we’re comfortable with and compile it down so other clients can recognize and run the code.

You can include Babel-specific functionality in Webpack, but sometimes it’s just cleaner placing them in the .babelrc file at the root of our plugin.

For example, here’s what our .babelrc file will look like completed:

{ "presets": ["@babel/env", "@babel/preset-react"], "plugins": [ "@babel/plugin-proposal-class-properties", [ "minify-mangle-names", { "exclude": { "__": true, "_n": true, "_x": true, "_nx": true } } ] ] }
Code language: JSON / JSON with Comments (json)

The main crux of the above is that we have several presets and plugins we’ll have to install with Node.

You may be wondering why we have an exclude portion that references common WordPress translation functions like __ and _n. Since our JavaScript will be minimized, we have to tell Babel that when it minifies our file, to skip these particular function names so they can be translated.

Setting Up Dependencies via Node and Command Line

Looking up at the Webpack code example, there are several options we haven’t included. Furthermore, we need to configure our start scripts in our package.json file.

Modifying Package.json

The easiest way to set up Webpack with Node is to directly modify our package.json file to point to common Webpack modes.

For example, we want a command that’ll allow us to watch our files without having to run a build script every time. We’ll also want a development and production build. So we’ll need a total of three commands.

For brevity sake, here are the commands we want to set up:

  • npm run start – Will watch our files for any changes via Webpack.
  • npm run dev – Will create a development build of our files.
  • npm run build – Will create a production build of our files.

Of note is that you can modify the shortcuts above if they are not to your liking, but for the sake of this series, these will be the commands we’ll be using.

"scripts": { "start": "webpack --watch", "dev": "webpack --mode development", "build": "webpack --mode production" },
Code language: JSON / JSON with Comments (json)

Now if you run npm run start, you’ll instruct Webpack to watch for any changes and build the files needed. Command npm run dev will instruct Webpack to build a development build of the files, which is useful for debugging. Command npm run build is when we’re ready to show the world our completed project.

Running NPM Commands

If we were to run npm run dev in our plugin folder via command line, Webpack will scream at you saying there are dependencies missing. For example, here’s some output I received running Webpack as-is with no further dependencies installed.

Error: Cannot find module 'mini-css-extract-plugin'
Code language: Bash (bash)

That’s just one of many dependencies we’ll need, and you can run npm run dev indefinitely as you install your dependencies.

Here’s an example of installing the above missing dependency:

npm install --save-dev mini-css-extract-plugin
Code language: Bash (bash)

If you were to run npm run dev again, it’ll error out on the next dependency missing.

Installing Babel with Node

First, we’ll want to install all our Babel dependencies via CLI.

npm install --save-dev @babel/cli @babel/core @babel/preset-env @babel/preset-react babel-loader babel-minify-webpack-plugin babel-plugin-minify-mangle-names
Code language: Bash (bash)

At this point, running npm run dev should result in sidebar.js being placed in a dist folder in our plugin.

If you look at sidebar.js in the dist folder, it’ll have some nice funky syntax like so:

(()=>{alert("Hi there")})();
Code language: JavaScript (javascript)

An additional Babel dependency to install allows us to use the awesome JavaScript arrow functions in our code:

npm install --save-dev @babel/plugin-proposal-class-properties
Code language: Bash (bash)

Setting up our SCSS Files

To compile our SASS files to a CSS file, we have to configure Webpack to look at a new entry-point. This can theoretically be done in the same Webpack configuration, but I’ve found it’s a bit cleaner to have them as separate declarations.

const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const BabelMinifyPlugin = require("babel-minify-webpack-plugin"); module.exports = [ { mode: process.env.NODE_ENV, entry: { sidebar: ["./src/js/index.js"], }, output: { filename: "[name].js", }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /(node_modules|bower_components)/, loader: "babel-loader", options: { presets: ["@babel/env"] }, }, ], }, externals: { // Use external version of React react: "React", }, optimization: { minimizer: [new BabelMinifyPlugin()], }, }, { mode: process.env.NODE_ENV, entry: { style: ["./src/scss/style.scss"], }, module: { rules: [ { test: /\.scss$/, exclude: /(node_modules|bower_components)/, use: [ { loader: MiniCssExtractPlugin.loader, }, { loader: "css-loader", options: { sourceMap: true, }, }, "sass-loader", ], }, ], }, plugins: [ new MiniCssExtractPlugin({ filename: "[name].css", }), ], }, ];
Code language: JavaScript (javascript)

If we run npm run dev again, Node will scream at us and telling us we are needing yet even more dependencies to process SCSS files.

npm install --save-dev css-loader sass-loader node-sass
Code language: Bash (bash)

Finally, we should be able to run npm run dev without any further issues (for now).

If all is well, you have fairly blank files in the /dist/ folder of your plugin’s root.

Conclusion

We now have a functioning Webpack build script which will build our JavaScript and CSS files for us. Up next is setting up our main plugin file so we can eventually enqueue the scripts so we can begin working on our Gutenberg sidebar.