Reader small image

You're reading from  Building Enterprise JavaScript Applications

Product typeBook
Published inSep 2018
Reading LevelIntermediate
PublisherPackt
ISBN-139781788477321
Edition1st Edition
Languages
Right arrow
Author (1)
Daniel Li
Daniel Li
author image
Daniel Li

Daniel Li is a full-stack JavaScript developer at Nexmo. Previously, he was also the Managing Director of Brew, a digital agency in Hong Kong that specializes in MeteorJS. A proponent of knowledge-sharing and open source, Daniel has written over 100 blog posts and in-depth tutorials, helping hundreds of thousands of readers navigate the world of JavaScript and the web.
Read more about Daniel Li

Right arrow

Chapter 4. Setting Up Development Tools

The first section of this book (Chapters 1-3) was written to provide sufficient background knowledge so that we can code without interruption. In this chapter, we will actually start building our user directory application, called 'hobnob', by setting up our local development environment.

The aim of this chapter is to help you understand how different tools and standards in the Node.js ecosystem work together. Specifically, we'll cover the following:

  • What is Node.js?
  • Different formats/standards for JavaScript modules
  • Managing modules with npm and yarn
  • Transpiling code with Babel
  • Watching for changes with nodemon
  • Linting our code with ESLint

What is Node.js?


As you learned in Chapter 2, The State of JavaScript, Node.js is "JavaScript on the server". Before we move forward, let's delve a little deeper into understanding what that means.

Traditionally, JavaScript is interpreted by a JavaScript engine that converts JavaScript code into more optimized, machine-executable code, which then gets executed. The engine interprets the JavaScript code at the time it is run. This is unlike compiled languages such as C#, which must first be compiled into an intermediate language (IL), where this IL is then executed by the common language runtime (CLR), software similar in function to the JavaScript engine.

 

Note

Technically, it is inaccurate to classify a language as interpreted or compiled—how a language is processed depends on the implementation. Someone can build a compiler that converts JavaScript into machine code and run it; in that instance, JavaScript would be a compiled language.However, since JavaScript is almost always interpreted...

Modules


As mentioned in Chapter 1The Importance of Good Code, clean code should be structured in a modular way. In the next few sections, we'll introduce you to the concept of modular design, before explaining the different module formats. Then, for the rest of the chapter, we will begin composing our project by incorporating existing Node modules.

 

But first, let's remind ourselves why modular design is important. Without it, the following apply:

  • Logic from one business domain can easily be interwoven with that of another
  • When debugging, it's hard to identify where the bug is
  • There'll likely be duplicate code

Instead, writing modular code means the following:

  • Modules are logical separations of domains—for example, for a simple social network, you might have a module for user accounts, one for user profiles, one for posts, one for comments, and so on. This ensures a clear separation of concerns.
  • Each module should have a very specific purpose—that is, it should be granular. This ensures that...

Installing Node


With that background on modules out of the way, let's begin the development of our application by installing Node.js on our local machine. Just like the saying "Many roads lead to Rome", there are many ways to install Node.js on your machine. You can do one of the following:

But the easiest way is to use Node Version Manager (nvm), which has the added benefit of allowing you to download and switch between different versions of Node. This is especially handy if you're working on different Node projects at the same time, each using a different version.

Note

There are several popular programs that manage the Node versions for you. nvm and nave manage Node versions per user/shell, which means different...

Starting projects with npm


For Node.js projects, the settings and configurations are stored inside a file named package.json, located at the root of the repository. The npm CLI tool provides a npm init command, which will initiate a mini-wizard that helps you compose your package.json file. So, inside our project directory, run npm init to initiate the wizard. 

The wizard will ask you a series of questions, but also provides sensible defaults. Let's go through each question one by one:

  1. package name: We are happy with the default name of hobnob (derived from the directory name), so we can just press the Return key to continue.
  2. version: We're going to follow semantic versioning (semver) here and use major version 0(0.y.z) to indicate that our code base is under initial development, and that the API is not stable. Semver also recommends that our initial release be 0.1.0.
  1. description: A brief description of your project; if we make our application public on npmjs.com, this description will appear...

Using yarn instead of npm


npm is the default package manager, but Facebook, in collaboration with Exponent, Google, and Tilde, has since developed a better alternative, called yarn, which we will use instead.

yarn (https://yarnpkg.com/en/) uses the same https://www.npmjs.com/ registry as the npm CLI. Since they both just install packages inside node_modules directories and write to package.json, you can use npm and yarn interchangeably. The differences are in their methods for resolving and downloading dependencies.

Package version locking

When we specify our dependencies inside our package.json file, we can use symbols to indicate a range of acceptable versions. For example, >version means the installed version must be greater than a certain version, ~version means approximately equivalent (which means it can be up to the next minor version), and ^version means compatible (which usually means the highest version without a change in the major version). This means that given the same package...

Creating an HTTP server


Next, we need to set up our project so that it can run ES6 code, specifically the ES6 modules feature. To demonstrate this, and also to show you how to debug your code, we're just going to create a simple HTTP server that always returns the string Hello, World!.

Note

Normally, when we follow a TDD workflow, we should be writing our tests before we write our application code. However, for the purpose of demonstrating these tools, we will make a small exception here.

Node.js provides the HTTP module, which contains a createServer() method (https://nodejs.org/api/http.html#http_http_createserver_requestlistener)that allows you to provision HTTP servers. At the root of your project directory, create an index.js file and add the following:

const http = require('http');
const requestHandler = function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello, World!');
}
const server = http.createServer(requestHandler);
server.listen(8080);

Note

We are...

Transpiling ES6 with Babel


We've been using the CommonJS require syntax for modules; let's change it to use the ES6 module syntax (using import).

In your code, update the first line to use import:

const http = require('http'); // CommonJS syntax
import http from 'http'; // ES6 syntax

When we try to run our server by executing node index.js, it will throw a SyntaxError: Unexpected token import error. This is because Node.js support for modules is still experimental, and not likely to be supported without the --experimental-modules flag until late 2018.

This means that for us to write our source code using ES6 modules, we need to add an extra step that will transpile the unsupported syntax into supported syntax. There are a few compilers/transpilers available for us to choose from:

  • Babel: The most popular and de facto standard for JavaScript compilers/transpilers.
  • Traceur: Another compiler by Google.
  • The TypeScript compiler: TypeScript is a superset of JavaScript that provides static typing. Since...

Consolidating commands with npm scripts


It's troublesome to have to type rm -rf dist/ && npx babel src -d dist each time you want to build your project. Instead, we should use npm scripts to consolidate this command into a simpler one.

In your package.json file, add a new build sub-property to the scripts property, and set it to a string representing the command we want to run:

"scripts": {
 "build": "rm -rf dist/ && babel src -d dist",
 "test": "echo \"Error: no test specified\" && exit 1"
}

Now, instead of typing  rm -rf dist/ && npx babel src -d dist, you can just type yarn run build, or npm run build—much less cumbersome! By adding this script into package.json, it allows you to share this with other developers, so everyone can benefit from this convenience.

We can also create a serve script, which will build our application and then run it:

"scripts": {
  "build": "rm -rf dist/ && babel src -d dist",
  "serve": "yarn run build && node dist...

Automating development using nodemon


At the moment, to see the final product, we have to run the build script after each time we modify our source code. While this is fine, it can be annoying and a time-waster. nodemon is a tool that monitors for changes in our code and automatically restarts the node process when a change is detected. This can speed up development and testing, as we no longer need to run the build and serve scripts manually. Furthermore, the API served from our machine will always be the most up-to-date version.

First, let's install nodemon:

$ yarn add nodemon --dev

Next, add a watch script that uses nodemon instead of node:

"scripts": {
  "build": "rimraf dist && babel src -d dist",
  "serve": "yarn run build && node dist/index.js",
  "test": "echo \"Error: no test specified\" && exit 1",
  "watch": "nodemon -w src --exec yarn run serve"
},

This command instructs nodemon to watch for file changes in the src directory and, whenever one is detected, to...

Linting with ESLint


Finally, we should take care to maintain a consistent code style throughout our project. Code styles are subjective, stylistic choices that do not alter the function of the program, for example, whether to use spaces or tabs, or whether to use camelCase or underscore_case when naming variables.

Having a consistent code style is important for the following reasons:

  • It makes the code more readable.
  • When working with others, contributors may override each other's style changes. For instance, contributor A may change all string literals to using single-quotes, and contributor B may change it back to double-quotes in a subsequent commit. This is a problem because:
    • Time and effort are wasted
    • It can lead to ill-feelings because no one likes their work being overwriten
    • Changes become hard to review, and the pertinent changes may be submerged under the stylistic changes.

Once a set of code style rules is defined, a linter can be used to enforce those rules. A linter is a static analysis...

Committing our code into Git


We have finished bootstrapping our project by setting up an HTTP server and enabling ourselves to write in ES6. So, let's actually commit this block of code into Git.

Note

Note that we could have created a new commit each time we added a new script, or integrated with a new tool, but because the bootstrapping of a project can be considered as one logical unit, we're committing all of that into one commit. Also, note that we are not going to be creating a dev branch just yet, as bootstrapping a project is not considered to be a "feature." Remember that branches are here to help us separate our commits by business domains; if branching provides no benefit for us, then it's better to be pragmatic, rather than dogmatic.

 

Let's run git status to see which files we can track in our Git repository:

$ git status
Untracked files:
  .babelrc
  .eslintrc.json
  .nvmrc
  dist/
  node_modules/
  package.json
  src/
  yarn.lock

The list of files listed by the git status command...

Summary


At the start of this chapter, we looked at the difference between CommonJS and ES6 modules, and settled on using the new ES6 module syntax, which uses the import and export keywords.

Next, we installed Node on our machine using nvm, and got acquainted with the npm and yarn package managers. We then set up a simple HTTP server using the native http Node module. After that, we used Babel to transpile our ESNext code into a syntax supported by our local environment. We also set up nodemon to watch for changes in our code and restart the server whenever a change is detected. Lastly, we incorporated ESLint to spot problems in our code, and use a pre-commit Git hook to run the linter automatically before each commit.

 

 

In the next chapter, we will be following a test-driven development (TDD) approach to develop our API server, to provide functionalities for clients to create, read, update, and delete (CRUD) user objects on our database, using ElasticSearch as our data storage solution.

In...

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Building Enterprise JavaScript Applications
Published in: Sep 2018Publisher: PacktISBN-13: 9781788477321
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €14.99/month. Cancel anytime

Author (1)

author image
Daniel Li

Daniel Li is a full-stack JavaScript developer at Nexmo. Previously, he was also the Managing Director of Brew, a digital agency in Hong Kong that specializes in MeteorJS. A proponent of knowledge-sharing and open source, Daniel has written over 100 blog posts and in-depth tutorials, helping hundreds of thousands of readers navigate the world of JavaScript and the web.
Read more about Daniel Li