10 KiB
Webpack is awesome!
There are an endless amount of javascript libraries out there today, and webpack is one that you should learn how to use. Webpack is a module builder, which allows you to bundle all of your javascript and css into a single minified file.
I am by no means an expert with webpack, but I feel I have used it enough to explain how it works and give my opinion on it. I've use it with both React and Angular applications and it works very well. It also includes tools such as webpack-dev-server, which offers hot module reloading.
Why use webpack?
If you want an easier life, use webpack. It's as simple as that. It's something that seems intimidating and hard to understand at first (especially if you have never used a mondule bundler like myself). It keeps your files clean and modularized. There are also many different useful tools and plugins such as PostCSS and autoprefixer. Autoprefixer adds many different browser prefixes to your css as it goes through the build process.
Webpack is something that is extremely useful when you start using javascript frameworks such as React and Angular. It may seem unnecessary until you start building projects with a lot of javascript. It may seem easier to just include your javascript tag at the end of your HTML files. With webpack, this is done for you.
Getting started
First we will create a new project and initialize it with npm. Then install webpack globally and save it. This will allow us to run webpack from the command line.
npm init
npm install -g --save webpack
You should now have a package.json file. Create an index.html file in a public folder and create an src folder as well. Within src create app.js. This is your main javascript file in which everything will be contained.
Let's put some dummy code in app.js
window.onload = function(){
console.log("test123");
}
Create a new file called webpack.config.js. This is the file that webpack will look for when you run the command webpack. Within this file we need to define a few things in order to get started.
webpack.config.js
//dependencies
var webpack = require('webpack');
var path = require('path');
module.exports = {
//our main javascript file where everything is included
entry: ['./src/app.js'],
//the path we want to output all files
output: {
path: './public',
filename: 'bundle.min.js'
}
}
The folder structure will look like this
root
|-package.json
|-webpack.config.js
|-src
|-app.js
Let's issue the command webpack. You will notice the public directory is created with bundle.min.js. When we are ready to deploy to production we can use webpack -p to minify the javascript.
The new folder structure will look like:
root
|-webpack.config.js
|-package.json
|-src
|-app.js
|-public
|-index.html
|-bundle.min.js
Webpack Loaders
Loaders allow us to do things with our code before it is bundled and minified. I say "things" because there are all sorts of loaders out there that do various things. I will go over a few of the more common loaders and how they work. Every time we include a new file type into our javascript we need to make sure there is a loader for it (like css, scss, jpg, svg, etc.).
Let's upgrade to ES6, because it is the new thing right? If you are unaware, ES6 or referred to as ES2015 is a newer version of javascript with some different syntax. I will not be covering ES6 at all here, but it isn't a whole lot different than ES5 so don't worry.
There are a few different things we need to install to get all of the features of ES6. We need babel-loader as well as babel-preset-2015 for syntax and babel-polyfill for extra features.
npm install --save babel-loader babel-preset-es2015 babel-polyfill
Let's add the loader to the webpack config file so our ES6 gets converted to ES5 when we build with webpack. Notice babel-polyfill and presets: ['es2015'].
//dependencies
var webpack = require('webpack');
var path = require('path');
module.exports = {
//our main javascript file where everything is included
entry: ['babel-polyfill', './src/app.js'],
//the path we want to output all files
output: {
path: './public',
filename: 'bundle.min.js'
},
module: {
//defines how we want to process each type of file before building
loaders: [
{
//all files with .js extension are loaded
test: /\.js?$/,
//exclude folders here
exclude: [/(node_modules)/],
loader: 'babel-loader',
//include the presets
query: {
presets: ['es2015']
}
}
]
}
}
Just like that we can start writing ES6 javascript. We can also start using imports now and split up our javascript into multiple files.
print.js
//this is imported by default if functions aren't specified
export default function print(text){
console.log(text);
}
export function printAgain(text){
console.log(text);
}
export function printAgainAgain(text){
console.log(text);
}
Let's import these functions into the app. Only javascript files do not need to have file extensions when imported.
app.js
//x can be named anything because it is exported from print.js by default
//we have to specify each function in {} if it is not default
import x, {printAgain, printAgainAgain} from './print';
window.onload = function(){
x(1);
printAgain(2);
printAgainAgain(3);
}
Loading CSS with webpack
This part is going to seem confusing at first because you are probably used to including css in the HTML head. Now, with webpack, we can include this in our javascript file. It gets bundled in as well which is nice. When the page loads the javascript will inject the css into the head of the HTML document.
It may seem odd to load CSS this way, but it's nice loading everything as if the webapp is a complete javascript application. For example, in Angular or React the CSS can be loaded in each component separately. This can be nice since all of your application is going to be injected into a div of the index.html file. This will make more sense if you are familiar with single page web applications.
npm install --save style-loader css-loader
Let's now add the loader object to the loaders array in our webpack.config.js file.
{
test: /\.css$/,
loader: "style-loader!css-loader"
}
We can add some CSS now. It's also a good idea to adjust the folder structer now that we are adding some new types of files. Keep in mind when we do this the entry in webpack.config.js needs to be updated accordingly. We must also adjust the imports in the javascript files.
Create a CSS file in a new folder.
root
|-webpack.config.js
|-package.json
|-src
|-js
|-app.js
|-print.js
|-style
|-app.css
|-public
|-bundle.min.js
|-index.html
Let's add some CSS to test it out.
html{
color: red;
}
Now we can import the CSS into our app.js file.
//x can be named anything because it is exported from print.js by default
//we have to specify each function in {} if it is not default
import x, {printAgain, printAgainAgain} from './print';
//import css
import '../style/app.css';
window.onload = () => {
x(1);
printAgain(2);
printAgainAgain(3);
}
We can then start creating more CSS files and import them into relative Angular/React components.
CSS is boring these days so let's use SCSS. Let's also add autoprefixer so our CSS works across browsers out of the box.
npm install --save sass-loader node-sass postcss-loader autoprefixer
We have a few more thins to do now before this works. We need to add a new loader for SCSS files.
{
test: /\.scss$/,
loader: "style-loader!css-loader!postcss-loader!sass-loader"
}
We also need to import autoprefixer and tell postcss to use it. The new webpack.config.js file is below.
//dependencies
var webpack = require('webpack');
var path = require('path');
//autoprefixer for css
var autoprefixer = require('autoprefixer');
module.exports = {
//our main javascript file where everything is included
entry: ['babel-polyfill', './src/js/app.js'],
//the path we want to output all files
output: {
path: './public',
filename: 'bundle.min.js'
},
module: {
//defines how we want to process each type of file before building
loaders: [{
//all files with .js extension are loaded
test: /\.js?$/,
//exclude folders here
exclude: [/(node_modules)/],
loader: 'babel-loader',
query: {
presets: ['es2015']
}
}, {
test: /\.css$/,
loader: "style-loader!css-loader"
}, {
test: /\.scss$/,
loader: "style-loader!css-loader!postcss-loader!sass-loader"
}, ]
},
//use postcss for autoprefixer
postcss: function() {
return [autoprefixer]
}
}
Now we just need to change our CSS file to an SCSS file. Also remember to change the import in the javscript file. Just like that we can start writing SCSS and not have to worry about the annoyance of adding CSS prefixes.
I am going to end this post right here before it gets too long. There are many other things that webpack offers, but now you should have the general idea of how it works. I may discuss some of the other plugins in future posts.
A link to the branch that I used in this post can be found here.