Using Webpack with WordPress

Using Webpack with WordPress has many advantages. The first and most obvious is the ability to create a single JS file that will serve your website’s entire JavaScript and CSS. In the process, Webpack also preprocesses your SASS or LESS if you are using those ( and you should), compiles your ES6 JavaScript and all sorts of awesome goodness. The end result is a faster website that hopefully loads instantly. The only problem is that Webpack is not the easiest to configure and was not intentionally built to work with WordPress. So here’s a quick guide to setting up Webpack with WordPress.

First, you will need to use NPM in order to install Webpack and a few basic loaders. Webpack uses those to parse files that are not initially written in JS like CSS for example.

Go to your console, navigate your way to the directory of your theme or child theme and type:

npm init

Press enter several times to quickly have the default settings apply to your project (you can change those later) and type:

sudo npm install -g --save webpack

Punch in your password and press enter. You’ve just installed Webpack globally on your machine. Now we need to install Webpack locally in the project. In your console type:

npm install --save webpack

That should give you the ability to load numerous JavaScript files to your website in a single file, so let’s do that now. In your theme folder create a file and name it webpack.config.js. In it, you will set up Webpack’s configuration object.
The first thing you need to do is to import Webpack and create a function that receives an environment as an argument and returns an object.

//webpack.config.js

var webpack = require('webpack')

module.exports = function(env) {
    return {

    }
}

This is the basic structure of your config file and now you need to tell Webpack several things. First, you need to specify an entry point to your app so Webpack knows where to take the files it needs to bundle and an output location in which to place the bundled files. Add an entry and an exit point to your config object:

//webpack.config.js

var webpack = require('webpack')

module.exports = function(env) {
    return {
        entry: "./js/app.js",
        output: {
            path: __dirname + "/dist",
            filename: "bundle.js"
        },
    }
}

Now go ahead and create a directory and name it js and inside it create your app.js file. Webpack will go to this file first so you will use it to require all the JS and CSS of your app. For example, you can import a JavaScript file called script.js that is located in the same directory as app.js like so:

//js/app.js

//Require scripts
require('./script')

Write some code in js/script.js and in the console go to your theme’s directory and write down the command

webpack

You will see that a directory named dist was created and in it a file called bundle.js. This file contains all the output from Webpack. By the way, if you want Webpack to watch your files for changes and recompile each time a file changes add the --watch flag after the webpack command.
Now all you need to do is head over to your functions.php file and enqueue bundle.js like you would any other script in WordPress:

//functions.php

<?php
add_action( 'wp_enqueue_scripts', 'my_theme_enqueue_scripts' );
function my_theme_enqueue_scripts() {
	wp_enqueue_script( 'bundle', get_stylesheet_directory_uri() . '/dist/bundle.js', array('jquery'), 1, false );

}

Bundling Styles

Ok, so you’re all set for JS files. Now let’s continue and handle the style files. First, we should install some loaders to help Webpack deal with all these different kind of files. In your terminal, while in your theme’s directory, type:

npm install style-loader css-loader sass-loader node-sass file-loader url-loader raw-loader --save

In your webpack.config.js file add the modules section so that your entire file looks like so:

//webpack.config.js

var webpack = require('webpack')

module.exports = function(env) {
    return {
        entry: "./js/app.js",
        output: {
            path: __dirname + "/dist",
            filename: "bundle.js"
        },
        module: {
            loaders: [
                {test: /\.html$/, loader: 'raw-loader', exclude: /node_modules/},
                {test: /\.css$/, loader: "style-loader!css-loader", exclude: /node_modules/},
                {test: /\.scss$/, loader: "style-loader!css-loader!sass-loader", exclude: /node_modules/},
                {test: /\.woff($|\?)|\.woff2($|\?)|\.ttf($|\?)|\.eot($|\?)|\.svg($|\?)/, loader: 'url-loader'}
            ]
        },
    }
}

You can see that each loader is “testing” for files with a specific extension and deals with it using the specified loaders. In the loaders that handle the CSS and SASS we are chaining loaders from right to left. We are also excluding the node_modules folder because we don’t want all that in our bundle. Ok, now that Webpack can handle style files we should “require” them into our entry point file – app.js.

//js/app.js

//Require SASS
require('../scss/main.scss')

//Require CSS
require('../style.css')

//Require scripts
require('./script')

Great. We are almost done. The last thing we will need to deal with is jQuery plugins. Some of the most popular ones, like Slick, for example, use global variables and should be imported in a special way. If you’d like to install some of these plugins you should use the script loader. Head over to your console and install the loader by entering this command:

npm install --save script-loader

Lets also pull in the Slick package from npm just for the sake of convenience:

npm install --save slick-carousel

In our app.js file we’ll import the Slick JS like so:

//js/app.js

//Require SASS
require('../scss/main.scss')

//Require CSS
require('../style.css')

//Require scripts
require('./script')

//Require Slick
require('script-loader!../node_modules/slick-carousel/slick/slick')

That’s it. We should be ready to go. Don’t forget to run webpack --watch in your console while in your theme directory when working on the project or your changes won’t take effect.

If you find this guide helpful please let us know in the comments section below. Also, if you feel something is unclear or not fully explained, don’t hesitate to comment so we can update the guide and make it better.

Don't Miss Out

Join our mailing list for more amazing content!

  • What is the best method to automate this for websites that do not use a build cycle? I.e.: standard wordpress sites?

    • I don’t understand what you mean with “automate”. Are you interested in including webpack in a commercial theme in which the user won’t have access to the console?

  • jashwantsingh

    How can I include masonry ( included with wordpress ) with webpack ?

    • Find where the masonry script is located and require it using the script-loader like I demonstrated with Slick

      • jashwantsingh

        It’s not possible with masonry provided by wordpress core. It’s located in wp-includes folder.

        • WordPress does not include any front end masonry solution. All front end stuff is located on the theme level.

          • jashwantsingh

            Sorry,I think I was not clear enough.
            I was talking about including masonry like this `wp_enqueue_script(‘masonry’);`
            It is done at theme level, but masonry javascript is included from wp-includes folder.

          • Just follow the Slick example in the article and change the path to lead to the masonry.pkgd.js file in the wp-includes folder.

  • Ilan Diamond

    Thanks so much – Great blog !

  • How can I add autoprefixer?

  • Brian Meyer

    I wasn’t able to run webpack from the theme folder with the local install because ./npm_modules/webpack isn’t going to be in your path vars. Following the view that it’s not best practice to add those to your shell config, but still wanting the ease of typing in webpack, I stumbled on: https://www.npmjs.com/package/add-local-binaries-to-path

    I don’t know if this is a security issue / maintenance problem (not my normal wheel house), but it was a solution for me to move forward with this tutorial.

    • Thanks for this, Brian. It turns out that need to have Webpack installed globally on your machine. Since I had mine already installed, I didn’t notice that. I’ve added that step to the tutorial

  • Brian Meyer

    It’s not really clear to me how your styles are getting loaded? Adding `require ‘./sass-dir/styles.scss’` does get itself loaded into your bundled.js file, but.. that’s now updating your theme’s styles.css file.

    • Webpack loads the css within the bundle.js and serves the styles from that file. The styles.css file is left empty.

      • Brian Meyer

        I’m aware of the functionality through various JS frameworks, but WordPress loads CSS through the enqueue function, looking for a distinct output file. Your tutorial doesn’t mention this, nor how the styles are actually loading on page. Maybe it’s obvious if you’re use to the pattern you’re referring to you but I’m completely lost. Is the suggestion that Webpack is running on the front-end in production?

  • Joe

    How would you add browsersync? could you give an example?
    I got confused in the part that https://www.npmjs.com/package/browser-sync-webpack-plugin for example requires to register the plugin in webpack.config.js, while you are using a different approach.

  • Michael Laurence Smith

    I’m building a plugin and I’m using webpack to bundle the JS. I’m working in a src directory. When I run build, it creates the bundled JS files, but the php file is not added to the dist folder. I could just move it manually, but is there way of having webpack do this?

  • Lance Monotone

    This was a very helpful article. I got the js portion working with ease, but I feel like you rushed through the ending with regard to bundling styles.

    1. What good is importing main.scss into app.js? How does the browser read those styles? Is style.css the result of SCSS compilation?
    2. Why did you choose to include those loaders – style-loader css-loader sass-loader node-sass file-loader url-loader raw-loader? What do each of them contribute?

  • Karl Schipul

    This article is as clear as mud when it comes to converting sass/scss to css. And there seems like a good amount of bloat and scope creep for simply making scss into css. Finally, WHERE IS THE FINAL CSS FILE RENDERED? ffs.

    Or is the css actually being rendered inline on the page? That’s a real no no. It just makes the page take longer to render and the css can not be cached. If it is a separate file that is called in, it can be cached. Inline css is also considered by many to be bad practice.