Webpack for The Fast and The Furious
One car in exchange for knowing what a config's made of
aging tutorial
- ποΈ Date:
- ποΈ Last modified:
- β±οΈ Time to read:
Table of Contents
Note: You can read this same article in Free Code Camp’s Medium Publication.
This is a guide that is meant to help you ease your development workflow and save your time by using a bunch of awesome tools that you’ve read about on the internet (does React Hot Loader ring any bells?)
It’s also meant to help you out with some of the most commonly encountered problems while using Webpack β and save some time in the process before you begin to pull your hair out. After all, you want to go fast and tear through other important problems.
Chances are that you’ve run into one or more of the following issues:
- How do I have multiple entries?
- How do I shim modules?
- One of the libraries/plugins that I use depends on jQuery, how do I handle that?
- I keep getting $ is not defined or some stupid crap like that in one of the jQuery Plugins
- My bundling takes like, forever to finish.
- I read a bunch of tutorials on Hot Module Replacement for ReactJS and think it’s really cool, but keep running into errors while setting it up.
If you’re running into these difficulties, finish this article before you resort to posting one of these questions on Stack Overflow.
I’m assuming that you already know about the advantages of Webpack and what it is used for. If you’re a beginner and have no clue about what Webpack is, I highly recommend reading about it here.
I’m also assuming that you’re building a web app and not just some static page, which means that you will have a web server running on Node and Express. You most likely also use a NodeJS driver to talk to your database β probably MongoDB or Redis.
Configuration
So here is what a typical webpack.config.js looks like:
This config assumes that you have use some node modules and dist version of few libraries saved inside a public/libs folder. Now if you’ve read other tutorials, you understand what the configs in this file do, however I’m still gonna briefly explain what few things in this file are for β
- Aliases / vendors Here is where you include all of your libraries/node modules/other vendors and map each of them to aliases. Then if you use a module in any part of your application logic, you can write this (in your app-main.js or any other JS file):
var React = ('react');
var ReactDom = ('reactDom');
var $ = ('jquery');
//Your application logic
Or if you prefer AMD over CommonJS:
define(
[
'react',
'reactDom',
'jquery'
],
(React, ReactDom, $) {
//Your application logic
}
);
Or in ES6 too:
import React from 'react';
import ReactDom from 'reactDom';
import $ from 'jquery';
- Defining your entry points
entry: {
}
This block in your config allows Webpack to determine where your app begins execution, and it creates chunks out of it. Having multiple entry points in your application is always advantageous. In particular, you can add all your vendor files β like jQuery and ReactJS β into one chunk. This way, your vendor files will remain the same, even when you modify your source files.
So in the above config, there are two entry points. One for your app’s entry where your JS begins, and one for your vendors β each of them mapped to a variable name.
- Your output directory and bundle file names
output: {
path: path.join(__dirname, "public"),
filename: "dist/js/[name].bundle.js"
},
This block tells Webpack what to name your files after the build process, and where to place them. In our example we have two entries named app and vendors, so after the build process you’ll have two files called app.bundle.js and vendors.bundle.js inside /public/dist/js directory.
- Plugins
Webpack comes with a rich ecosystem of plugins to help meet specific needs. I’ll briefly explain few of the most commonly used ones:
- Use the CommonsChunkPlugin to have Webpack determine what code/modules you use the most, and put it in a separate bundle to be used anywhere in your application.
- You can optionally use the ProvidePlugin to inject globals. There are many jQuery plugins that rely on a global jQuery variable like $, so by using this plugin Webpack can prepend
var $ = require("jquery")
every time it encounters the global$
identifier. Ditto for any other plugin out there, like Bootstrap.
By including noParse, you can tell Webpack not to parse certain modules. This is useful when you only have the dist version of these modules/libraries. Improves build time.
- Loaders
Now if you write JSX in your React code, you can either use the jsx-loader or babel-loader to pre-compile JSX into JavaScript. So you can run npm install jsx-loader
and include this in your config:
loaders: [
{
test: /.js$/,
loader: 'jsx-loader'
},
]
However, if you write your code in JSX and ES6, then you’ll need to use the babel-loader, along with the babel plugin for React. So run npm install babel-core babel-loader babel-preset-es2015 babel-preset-react
and then add this to your config instead of the above.
loaders: [
{
test: /\.js$/,
loader: 'babel',
query: {
presets: ['react', 'es2015']
},
include: path.join(__dirname, 'public')
}
]
Likewise, you have loaders to compile TypeScript, CoffeeScript, etc.
Example
- Your web-server file:
- app-main.js from where our front-end logic begins:
- home-page.js is our parent React component which could contain something like this:
Opening your terminal, going to your project’s root folder and running webpack will create two files: vendors.bundle.js and app.bundle.js. Include these two files in your index.html and hit http://localhost:8000 in your browser. This will render a component with your username displayed on the web page.
Now, as you work more on Webpack, you’ll get frustrated by constantly having to build your files manually to see changes reflected on your browser. Wouldn’t it be awesome if there was a way to automate the build process every time you make a change to a file? So if you’re tired of typing the command webpack and hitting the refresh button on your browser every time you change a class name, do read onβ¦
Automating Builds with Webpack Dev Server
We will use this awesome module called Webpack Dev Server. It’s an express server which runs on port 8080 and emits information about the compilation state to the client via a socket connection. We will also use React Hot Loader which is plugin for Webpack that allows instantaneous live refresh without losing state while editing React components.
- Step 1: Run
npm install webpack-dev-server β save-dev
and thennpm install react-hot-loader β save-dev
Then you need to tweak your Webpack config a little to use this plugin. In your loaders, add this before any other loader:
{
test: /\.jsx?$/,
loaders: ['react-hot'],
include: path.join(__dirname, 'public')
}
This tells Webpack to use React Hot Loader for your components. Make sure React Hot Loader comes before Babel in the loaders array. Also make sure you have include: path.join(__dirname, 'public')
to avoid processing node_modules, or you may get an error like this:
Uncaught TypeError: Cannot read property 'NODE_ENV' of undefined
- Step 2: Changes to your index.html
If your index.html has something like this:
<script src="/dist/js/vendors.js"></script>
<script src="/dist/js/app.bundle.js"></script>
Change this to point to your webpack-dev-server proxy:
<script src="http://localhost:8080/dist/js/vendors.js"></script>
<script src="http://localhost:8080/dist/js/app.bundle.js"></script>
- Step 3: Run
webpack-dev-server --hot --inline
, wait for the bundling to finish, then hit http://localhost:8000 (your express server port) in your browser.
If you run into any errors while setting up React Hot Loader, you’ll find this troubleshooting guide and this awesome answer on Stack Overflow on Managing jQuery Plugin Dependency with Webpack very helpful. In addition, you can take a look at the Webpack setup for my project here.
This is only meant for development. While in production, you need to minify all your files. Just running webpack -p
will minify/uglify/concatenate all your files.
Visualizing your dependencies
Wouldn’t it be awesome if there was a way to view all your file dependencies in a beautiful tree-like visualization? There is a web-app which does that.
In your terminal, run webpack β profile β json > stats.json
. This will generate a JSON file called stats.json. Go to http://webpack.github.io/analyse/ and upload the file, and you’ll see all dependencies in a tree like structure.