Production Build

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

During development, we are not minifying our assets: yep, they're full of comments and spaces. And that's perfect for development! I like spaces! And those comments might be useful! Also... minification takes extra time, so we don't want to slow down our builds unnecessarily.

In other words, while developing, no minification! But for production, yes minification! That means that - somehow - we need to be able to pass a flag to webpack.config.js that tells it to compile in dev or production mode.

Using NODE_ENV

Tip

If you are using Webpack 4 or higher, use this to configure the Webpack mode:

// webpack.config.js
//...
const webpackConfig = {
    mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
    //...
}

In Node applications, there's a standard way to signal the environment to your apps: by setting an environment variable called NODE_ENV. To read this, you can say process.env.NODE_ENV:

135 lines webpack.config.js
... lines 1 - 8
console.log(process.env.NODE_ENV);
... lines 10 - 135

Let's log that. Run webpack like normal:

./node_modules/.bin/webpack --watch

Ok! It prints undefined. So... how do we set that? On a UNIX system, prefix the command:

NODE_ENV=production ./node_modules/.bin/webpack --watch

Yes! It prints production. If you're on Windows, there's a library called cross-env that can help do this.

The point is: we can now send a flag into Webpack to tell it the environment.

Minify JavaScript

Awesome! Let's use this flag to minify our JavaScript first, via a plugin.

Start by replacing module.exports with a new variable: const webpackConfig =:

140 lines webpack.config.js
... lines 1 - 33
const webpackConfig = {
... lines 35 - 131
};
... lines 133 - 140

Then, all the way at the bottom, export this: module.exports = webpackConfig:

140 lines webpack.config.js
... lines 1 - 33
const webpackConfig = {
... lines 35 - 131
};
... lines 133 - 139
module.exports = webpackConfig;

Before that, add an if statement: if process.env.NODE_ENV === 'production'), then we will add a new plugin. So, webpackConfig.plugins.push() then new webpack.optimize.UglifyJsPlugin:

140 lines webpack.config.js
... lines 1 - 33
const webpackConfig = {
... lines 35 - 131
};
if (process.env.NODE_ENV === 'production') {
webpackConfig.plugins.push(
new webpack.optimize.UglifyJsPlugin()
);
}
module.exports = webpackConfig;

Tip

This is for Webpack 4 or higher. At first, install terser-webpack-plugin and then use the following configuration

// webpack.config.js
//...
const TerserPlugin = require('terser-webpack-plugin');

//...

if (process.env.NODE_ENV === 'production') {
    webpackConfig.optimization.minimizer = [new TerserPlugin()];
}

And... that's it!

Try it! Run webpack without the NODE_ENV flag first:

./node_modules/.bin/webpack --watch

Ok cool. The un-uglified layout.js file is 1.62 megabytes. Stop and re-run in production:

NODE_ENV=production ./node_modules/.bin/webpack --watch

Ahh... this takes longer to run! But, the JavaScript files are way, way smaller!

Open up the built login.js. Ah, yes, one beautiful, single line.

Tip

License comments from outside libraries are not removed from the Uglified files for legal reasons. To remove them, see the extractComments option.

Adding package.json scripts

But, remembering this long command is a bummer. Heck, the command was already long, before adding the NODE_ENV stuff! My fingers are so tired...

There's a great way to improve this. Open package.json. Add a new key called scripts set to a hash. Inside, you can put something like dev set to NODE_ENV=dev webpack:

36 lines package.json
{
... lines 2 - 7
"scripts": {
"dev": "NODE_ENV=dev webpack",
... lines 10 - 11
},
... lines 13 - 34
}

Thanks to that, we have a shortcut! Just run:

yarn dev

Yep, it runs NODE_ENV=dev webpack! And we don't even need to say node_module/.bin/webpack: the scripts know to look there already for webpack.

Let's add two more: watch set to the same thing with --watch on the end. And finally, production, with NODE_ENV=production:

36 lines package.json
{
... lines 2 - 7
"scripts": {
"dev": "NODE_ENV=dev webpack",
"watch": "NODE_ENV=dev webpack --watch",
"production": "NODE_ENV=production webpack"
},
... lines 13 - 34
}

I love it! Try them out:

yarn watch

Nice! Stop that, and try:

yarn production

The command looks right... and the final JavaScript files are super small.

But! Our work is not done yet: we still need to minify the CSS files... and handle a few other things.

Leave a comment!

This tutorial explains the concepts of an old version of Webpack using an old version of Symfony. The most important concepts are still the same, but you should expect significant differences in new versions.

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.2.0",
        "symfony/symfony": "3.3.*", // v3.3.16
        "twig/twig": "2.10.*", // v2.10.0
        "doctrine/orm": "^2.5", // v2.7.0
        "doctrine/doctrine-bundle": "^1.6", // 1.10.3
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.5
        "symfony/swiftmailer-bundle": "^2.3", // v2.6.3
        "symfony/monolog-bundle": "^2.8", // v2.12.1
        "symfony/polyfill-apcu": "^1.0", // v1.4.0
        "sensio/distribution-bundle": "^5.0", // v5.0.22
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.26
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.2
        "friendsofsymfony/user-bundle": "^2.0", // v2.1.2
        "doctrine/doctrine-fixtures-bundle": "~2.3", // v2.4.1
        "doctrine/doctrine-migrations-bundle": "^1.2", // v1.3.2
        "friendsofsymfony/jsrouting-bundle": "^1.6" // 1.6.0
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.1.6
        "symfony/phpunit-bridge": "^3.0" // v3.3.5
    }
}

What JavaScript libraries does this tutorial use?

// package.json
{
    "dependencies": [],
    "devDependencies": {
        "babel-core": "^6.25.0", // 6.25.0
        "babel-loader": "^7.1.1", // 7.1.1
        "babel-plugin-syntax-dynamic-import": "^6.18.0", // 6.18.0
        "babel-preset-env": "^1.6.0", // 1.6.0
        "bootstrap-sass": "^3.3.7", // 3.3.7
        "clean-webpack-plugin": "^0.1.16", // 0.1.16
        "copy-webpack-plugin": "^4.0.1", // 4.0.1
        "core-js": "^2.4.1", // 2.4.1
        "css-loader": "^0.28.4", // 0.28.4
        "extract-text-webpack-plugin": "^3.0.0", // 3.0.0
        "file-loader": "^0.11.2", // 0.11.2
        "font-awesome": "^4.7.0", // 4.7.0
        "jquery": "^3.2.1", // 3.2.1
        "lodash": "^4.17.4", // 4.17.4
        "node-sass": "^4.5.3", // 4.5.3
        "resolve-url-loader": "^2.1.0", // 2.1.0
        "sass-loader": "^6.0.6", // 6.0.6
        "style-loader": "^0.18.2", // 0.18.2
        "sweetalert2": "^6.6.6", // 6.6.6
        "webpack": "^3.4.1", // 3.4.1
        "webpack-chunk-hash": "^0.4.0", // 0.4.0
        "webpack-dev-server": "^2.6.1", // 2.6.1
        "webpack-manifest-plugin": "^1.2.1" // 1.2.1
    }
}