This is a blog of AmberBit - a Elixir and Ruby web development company. Hire us for your project!

Polish Up your JavaScript #01: Setting up development project with Webpack

Hubert

Posted by Hubert Łępicki

Hubert is partner at AmberBit. Rails, Elixir and functional programming are his areas of expertise.
@hubertlepicki @hubertlepicki

In series so far:

  1. Setting up development project with Webpack
  2. Adding React

Intro to this series

I have been doing programming, both front-end and back-end for a good while (over a decade), but recently I realized I need to pay more attention to what I am doing, and what I should be doing on the front-end side of things. It’s not the same JavaScript I started writing in 2006 anymore, and things are moving super fast. I am taking some notes for myself and others like me. I hope you find this series useful!

Random awesome Polish thing #01: Pierogi (photo credit: Freeimages.com/Agnieszka Stach)

The war of asset builders

There’s been a war going on for years now in the front-end ecosystem. You would not know which asset builder to pick, and the currently trendy one was already obsolete in months.

There’s been a galore of tools with similar - but not precisely exact - set of features to choose from: Gulp, Brunch, Browserify, Grunt, Parcel… You could also use framework-invented tools, like Rails Assets Pipeline or there’s been people advocating on simply using GNU Make or NPM scripts directly… Oh, what a mess!

Luckily, I think* the war is over, and we have a winner: Webpack, version 4. It looks like we are going to stick with it for a while, and many frameworks like Ruby on rails and Phoenix now use Webpack by default.

Let’s get our hands dirty and set up our development front-end stack.

* this is my personal opinion! Surely lots of people disagree…

Create project

$ mkdir my_app
$ cd my_app
$ echo "node_modules/" > .gitignore
$ git init
$ git add .
$ git commit -m "Initial commit"

We are adding top-level node_modules folder to .gitignore here, so that the libraries we use will not be added to git. Every time you clone your repository to new machine, you will need to run npm install to populate your node_modules directory.

Setting up Node.js

To avoid problems in the future, I strongly advise you, to lock your Node.js version. I use asdf-vm to manage multiple versions of my development tools like Elixir, Ruby, but it also has excellent asdf-nodejs plugin that takes care of having multiple Node.js versions installed on your system. Grab it and install according to instructions from links above.

To lock your project to use given Node.js version, you need to pick this version (do pick most recent LTS version from: https://nodejs.org/en/) and then create your .tool-versions file:

$ echo "nodejs 10.13.0" > .tool-versions

And install it:

$ asdf install

That is going to give you consistent results when coming back to project after several months, when Node.js versions already change. Your build environment will force installation and usage of older Node.js until you manually upgrade.

After Node.js is installed, you can generate a JavaScript project’s package.json file with:

$ npm init -y

Edit your package.json to change author, name, keywords, description, but leave out dependencies and devDependencies fields since these will be managed by npm when we install our dependencies.

devDependencies

We want to install number of tools that will help us with development. I prepared handy one-liner for you:

$ npm install --save-dev webpack webpack-cli webpack-dev-server @babel/core babel-loader @babel/preset-env html-webpack-plugin html-loader css-loader node-sass sass-loader style-loader

At the moment of writing, this will result in package.json’s devDependencies as follows:

"devDependencies": {
  "@babel/core": "^7.1.6",
  "@babel/preset-env": "^7.1.6",
  "babel-loader": "^8.0.4",
  "css-loader": "^1.0.1",
  "html-loader": "^0.5.5",
  "html-webpack-plugin": "^3.2.0",
  "node-sass": "^4.10.0",
  "sass-loader": "^7.1.0",
  "style-loader": "^0.23.1",
  "webpack": "^4.26.0",
  "webpack-cli": "^3.1.2",
  "webpack-dev-server": "^3.1.10"
},

If you are person from the distant future, reading this article long time from now (months!), you will need to update the versions according to the above file more than likely in order to reproduce working set up. But then, the set up will be out of date anyway ;). Welcome to JavaScript :D.

I am installing Webpack and it’s addons, Babel (JS6 to JS5 transpiler), and plugins you likely need and things we’ll need to compile SASS to CSS.

You can adjust the lines above to remove SASS if you do not intend to use it, or replace with LESS (or something else) if you prefer.

devDependencies vs. dependencies, –save-dev vs. –save

Webpack, transpilers, loaders, plugins & development web server are some of the things you don’t want to be loaded to your compiled JavaScript bundle. This would blow up the size of the bundle significantly. NPM projects have two sections in their package.js file to separate these from the libraries you otherwise want to have included in the bundle. You want to make sure you install your development tools passing --save-dev switch (like above), and --save for libraries you will need at run time.

Babel configuration

You can configure Babel (remember: ES6+/next/whatever transpiler to ES5) in two ways: a) using separate .babelrc b) via webpack.config.js. Using .babelrc has this advantage that it will be picked up by scripts that don’t even use Webpack in your project, so I’d opt in for going with this.

Create your .babelrc file in root directory of your project (next to package.json):

{
  "presets": ["@babel/preset-env"]
}

For now, we are just instructing Babel to compile ES6 to ES5. We will add more presets, enhancing the ES6 syntax with more funky features later in this series.

Webpack configuration

Create webpack.config.js file in root of your project:

const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /\.scss$/,
        use: [
            "style-loader",
            "css-loader",
            "sass-loader"
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin()
  ]
};

This is the simplest configuration you need to start your application development with ES6 & SASS (.scss files to be precise as this is what we’ll use and what is configured to be compiled).

Start building your application

Once you have functioning Babel & Webpack in your project, you can start coding!

Since we are using HtmlWebpackPlugin - we will not have to write any HTML template, it will be generated for us. Later we can decide to use own template, or configure the generated HTML with available options.

The generated HTML will be pretty much empty, but will include our JavaScript bundle, and JavaScript bundle will include the stylesheets compiled to JavaScript*.

* You have read it right, but please feel free to re-read the above paragraph as many times as you need to. In near future we will drop this pattern, but since it’s default let’s give it a try for now!

Alright, we need to create two files, let’s start with our stylesheet. Place your styles in src/index.scss:

html {
  body {
    background-color: cyan;
  }
}

That will give us some nice retro background color for our HTML.

Then, you need to create your JavaScript (ES6) in src/index.js:

import "./index.scss"

(() => alert("Hello, ES6 world!"))()

What are we doing here is: 1. we instruct Webpack to compile & load our stylesheets as JavaScript module. This stylesheet will be automatically applied to our document when JavaScript executes. 2. we create alert window in an arrow function - to test if ES6 compilation works.

Development server

We have installed webpack-dev-server already, and it should be in our devDependencies. Next thing we need is a means of starting it. We can do it by editing our package.json file to include a script that will start it for us:

...
"scripts": {
  "start": "webpack-dev-server --open --mode development",
},
...

The development server will not write any resulting files to disk. We will tweak our configuration to support building to files in production mode shortly, but now we just want to focus on simplest development flow.

We can start our simple application by issuing the command:

$ npm run start

The command above should start development server for us on port 8080, and open default system browser to point it there. You should see our “Hello, ES6 world!” alert, and once you accept it the background of HTML page will turn cyan. If the browser does not open, and you don’t see anything suspicious on the console, manually visit http://localhost:8080/ to see your beautiful application.

You can play with your stylesheet and JavaScript sources and webpack-dev-server will take care of updating these and reloading page for us. Pretty sweet!

Sources for this blog post

You can find the project’s source files for this blog post on our GitHub under https://github.com/amberbit/polish-up-your-javascript/tree/master/polish-up-your-javascript-1

What’s next?

In blog post #02, we will install React and write our first component. In next posts we will discuss building assets for production, explore React & ES6 features that you may not be familiar with, start using MobX for our state. Stay tuned!

Hubert

Hi there!

I hope you enjoyed the blog post. Can we help you with Elixir or Ruby work? We are looking for new opportunities at the very moment, and we do have team available just for you.

Email me at: contact@amberbit.com or use the contact form below.

Want to get in touch about a project? Drop us a line!

When submitting the form, you are sending your personal information (including your name and e-mail as entered above) to contact@amberbit.com. AmberBit Sp. z o. o. is the receiving party, and a data controller, and will use the information you provided for the purpose of establishing relationship leading to possibly signing a services contract, and fulfillment of such contract only. We will not subscribe you to marketing lists, newsletters etc. You can read more about it in our Privacy Policy.