Introduction to webpack with ES2015 and React
The good old days when a webpage had just few JavaScript and CSS files are gone, now our web apps grow bigger and more complex every year.
And how to manage and develop all that code? First was Grunt but quickly replaced with Gulp and Browserify, which are great. But configuring them properly takes too much time. Fortunately for us developing tools are also evolving and Webpack comes with lots of functionalities ready out-of-box which can significantly speedup process of creating software.
How does webpack work? Like every other packer, it takes source files and combines them into bundle files. In this post we will create a webpack project from scratch, learn how webpack works and how it fits in your workflow.
Pre-configuration
Before we start make sure you have npm installed and project directory set.
After creating package.json
file better make sure if there is "private": true
option, because we don’t want to submit our project to npm repository.
Let’s see how it look in examples.
Basic configuration
Let’s start with creating a module. In this case it will be a plain string and name it print.js
In next step we will create index.js
file which imports print
module and write it on screen.
Now we can run webpack. As the first parameter goes source file and as second a destination filename.
To run our code we need HTML template:
Now you can open index.html file in the browser and see the result. It’s not very impressive example but shows the idea behind webpack.
Now, we’ll try to configure webpack to create bundle.js
without providing any parameters from command line, because any bigger project will require some additional options. Create a webpack.config.js
file.
This is really most basic configuration, which points on one entry file and one output file. After running a webpack
(without any parameters) command result should be exactly the same as the previous one.
And what if we want to include some CSS stylesheets? Webpack can handle it too. But first lets organize our code into a src
and dist
folders.
So now our project structure looks like this:
webpack.config.js
style.css
Of course we need to change src value of <script>
tag in index.html
file to ./dist/bundle.js
. To include stylesheet just use require
in index.js
But after running webpack command we might get errors like:
Yes, we can use require
for CSS, but we need a loader. What loaders do is they take files and transform them into a format usable in the project. They can, for instance, transform your CoffeeScript into Javascript. For more detailed description click here.
In this case we need style-loader
and css-loader
And alter index.js
file to
Loaders can be specified in require
separated with !
.
Now running webpack should go without a problem, and effect should look like that:
We can avoid adding loaders in require
statement by adding loaders in webpack config, which I think, is better practice.
So now we have one entry in loaders
array, which is used to contain automatically applied loaders.
Each loader must have test
property which is a RegEx for filename (otherwise file would not be processed by loader) and loaders
property containing array of used loaders (or loader
which contains loaders separated with !
).
Full example is available here.
If you are wondering how to serve this example to the browser, just use webpack-dev-server
, remember that it needs to be installed globally.
And then run it form command line
HTML templates and separate CSS file
Our configuration is starting to look better, but still we are using index.html
outside dist
directory and CSS is included in bundle.js
. Let’s create separate files for stylesheet and template HTML file. For that let’s get familiar with plugins.
Plugins are used to add functionality related to bundles.
Our webpack config file become a little bigger now, let’s have look at the changes.
Requiring previously installed loaders.
We changed the CSS loader, now it uses extract-text-webpack-plugin
plugin to separate CSS file.
New property plugins
is an array that holds all plugins.extract-text-webpack-plugin
– moves every CSS style into a separate output file and the styles are no longer inlined into the JavaScript.html-webpack-plugin
allows to use an HTML template for our project, and automatically insert stylesheets in link
tag and webpack output files with script
tag. For more detailed description you can go here.
Full example is available here.
Adding support for ES2015 and React
Now, when we know how webpack works we’ll try some more advanced configuration.
We will be using ReactJS with JSX and ES2015 syntax. Since even modern browsers don’t handle full specification of latest JavaScript version, files needs to be transformed into ES5 and for that we will use Babel. To help ourselves with the development we will create separate config files for development and production.
Another killer-feature we will be using is Hot Module Replacement, it allows to update code in the browser without reloading it while state of modules remains unchanged.
Let’s install required npm packages:
You may wonder what babel-preset-react
and babel-preset-es2015
are, but first what actually Babel is? It’s a generic multi-purpose compiler for JavaScript, allows for example to transpile ES2015 code to old ES5. But every functionality in Babel is actually a plugin and set of plugins is called “preset”. If we don’t want to assemble our own plugin list, we pick one of preset plugin packages provided by Babel. In this case we used react and ES2015 presets.
If we are gonna use Hot Module Replacement with React we also need to install this:
I’m assuming, that all packages from previous examples are also installed.
First we need to configure Babel to use previously installed presets and plugins. Let’s create .babelrc
file with following content:
In presets
we put a list of presets we use, env
property is object of keys that represent different environments (in this case only development). Our development environment will use react-transform
plugin and transform code using react-transform-hmr
.
Our new webpack.config.js
file:
It’s only a little bigger then previous one, so take a look on differences.
Turns debugging on, now we will see errors in our code and not in the code Babel produced.
Tells our webpack-dev-server
that we will be using HMR.
Adding Babel as loader for .jsx files so now all files matching /\.jsx$/
RegEx will be transpiled by babel-loader using configuration defined in .babelrc
.
Including webpack Hot Module Replacement Plugin.
For demo project source you can go here
Running our dev server is now a little different, we need to enable inline mode with flag:
Inline mode adds a webpack-dev-server client entry to the bundle that allows notifying about every change we make in code.
And what if wee need to push our project on production? Create new file called webpack.config.production.js
and copy content from previous webpack config. Let’s change output path to:
Note: __dirname
is a Node global object which contains name of the directory that the currently executing script resides in.
Remove devtool
, devServer
options and HMR Plugin and we are good to go.
Option -p in webpack will perform code optimization and minimization.
Before we finish we can take advantage of npm scripts so we don’t have to type that long commands for starting dev server and deploying code on production.
In package.json
we add:
Webpack --config
option allows to select specific configuration file.
So now running dev server is npm run dev
and deploy is npm run deploy
.
Full example is available here.
Do you like this post? Want to stay updated? Follow us on Twitter or subscribe to our Feed.
See also