Getting Organized with NPM and Bower

John Moore

October 2016

In this article by Philip Klauzinski and John Moore, the authors of the book Mastering JavaScript Single Page Application Development, we will learn about the basics of NMP and Bower. JavaScript was the bane of the web development industry during the early days of the browser-rendered Internet. Now, powers hugely impactful libraries such as jQuery, and JavaScript-rendered content (as opposed to server-side-rendered content) is even indexed by many search engines. What was once largely considered an annoying language used primarily to generate popup windows and alert boxes has now become, arguably, the most popular programming language in the world.

(For more resources related to this topic, see here.)

Not only is JavaScript now more prevalent than ever in frontend architecture, but it has become a server-side language as well, thanks to the Node.js runtime. We have also now seen the proliferation of document-oriented databases, such as MongoDB, which store and return JSON data. With JavaScript present throughout the development stack, the door is now open for JavaScript developers to become full-stack developers without the need to learn a traditional server-side language. Given the right tools and know-how, any JavaScript developer can create single page applications (SPAs) comprising entirely the language they know best, and they can do so using an architecture such as MEAN (MongoDB, Express, AngularJS, and Node.js).

Organization is key to the development of any complex single page application. If you don't get organized from the beginning, you are sure to introduce an inordinate number of regressions to your app. The Node.js ecosystem will help you do this with a full suite of indispensable and open source tools, three of which we will discuss here.

In this article, you will learn about:

  • Node Package Manager
  • The Bower front-end package manager

What is Node Package Manager?

Within any full-stack JavaScript environment, Node Package Manager (NPM) will be your go-to tool for setting up your development environment and managing server-side libraries. NPM can be used within both global and isolated environment contexts. We will first explore the use of NPM globally.

Installing Node.js and NPM

NPM is a component of Node.js, so before you can use it, you must install Node.js. You can find installers for both Mac and Windows at nodejs.org. Once you have Node.js installed, using NPM is incredibly easy and is done from the command-line interface (CLI). Start by ensuring you have the latest version of NPM installed, as it is updated more often than Node.js itself:

$ npm install -g npm

When using NPM, the -g option will apply your changes to your global environment. In this case, you want your version of NPM to apply globally. As stated previously, NPM can be used to manage packages both globally and within isolated environments. Therefore, we want essential development tools to be applied globally so that you can use them in multiple projects on the same system.

On Mac and some Unix-based systems, you may have to run the npm command as the superuser (prefix the command with sudo) in order to install packages globally, depending on how NPM was installed. If you run into this issue and wish to remove the need to prefix npm with sudo, see docs.npmjs.com/getting-started/fixing-npm-permissions.

Configuring your package.json file

For any project you develop, you will keep a local package.json file to manage your Node.js dependencies. This file should be stored at the root of your project directory, and it will only pertain to that isolated environment. This allows you to have multiple Node.js projects with different dependency chains on the same system.

When beginning a new project, you can automate the creation of the package.json file from the command line:

$ npm init

Running npm init will take you through a series of JSON property names to define through command-line prompts, including your app's name, version number, description, and more. The name and version properties are required, and your Node.js package will not install without them being defined. Several of the properties will have a default value given within parentheses in the prompt so that you may simply hit Enter to continue. Other properties will simply allow you to hit Enter with a blank entry and will not be saved to the package.json file or be saved with a blank value:

name: (my-app)
version: (1.0.0)
description:
entry point: (index.js)

The entry point prompt will be defined as the main property in package.json and is not necessary unless you are developing a Node.js application. In our case, we can forgo this field. The npm init command may in fact force you to save the main property, so you will have to edit package.json afterward to remove it; however, that field will have no effect on your web app.

You may also choose to create the package.json file manually using a text editor if you know the appropriate structure to employ. Whichever method you choose, your initial version of the package.json file should look similar to the following example:

{
  "name": "my-app",
  "version": "1.0.0",
  "author": "Philip Klauzinski",
  "license": "MIT",
  "description": "My JavaScript single page application."
}

If you want your project to be private and want to ensure that it does not accidently get published to the NPM registry, you may want to add the private property to your package.json file and set it to true. Additionally, you may remove some properties that only apply to a registered package:

{
  "name": "my-app",
  "author": "Philip Klauzinski",
  "description": "My JavaScript single page application.",
  "private": true
}

Once you have your package.json file set up the way you like it, you can begin installing Node.js packages locally for your app. This is where the importance of dependencies begins to surface.

NPM dependencies

There are three types of dependencies that can be defined for any Node.js project in your package.json file: dependencies, devDependencies, and peerDependencies. For the purpose of building a web-based SPA, you will only need to use the devDependencies declaration.

The devDependencies ones are those that are required for developing your application, but not required for its production environment or for simply running it. If other developers want to contribute to your Node.js application, they will need to run npm install from the command line to set up the proper development environment. For information on the other types of dependencies, see docs.npmjs.com.

When adding devDependencies to your package.json file, the command line again comes to the rescue. Let's use the installation of Browserify as an example:

$ npm install browserify --save-dev

This will install Browserify locally and save it along with its version range to the devDependencies object in your package.json file. Once installed, your package.json file should look similar to the following example:

{
  "name": "my-app",
  "version": "1.0.0",
  "author": "Philip Klauzinski",
  "license": "MIT",
  "devDependencies": {
    "browserify": "^12.0.1"
  }
}

The devDependencies object will store each package as key-value pairs, in which the key is the package name and the value is the version number or version range. Node.js uses semantic versioning, where the three digits of the version number represent MAJOR.MINOR.PATCH. For more information on semantic version formatting, see semver.org.

Updating your development dependencies

You will notice that the version number of the installed package is preceded by a caret (^) symbol by default. This means that package updates will only allow patch and minor updates for versions above 1.0.0. This is meant to prevent major version changes from breaking your dependency chain when updating your packages to the latest versions.

To update your devDependencies and save the new version numbers, you will enter the following from the command line.

$ npm update --save-dev

Alternatively, you can use the -D option as a shortcut for --save-dev:

$ npm update -D 

To update all globally installed NPM packages to their latest versions, run npm update with the -g option:

$ npm update -g

For more information on semantic versioning within NPM, see docs.npmjs.com/misc/semver.

Now that you have NPM set up and you know how to install your development dependencies, you can move on to installing Bower.

Bower

Bower is a package manager for frontend web assets and libraries. You will use it to maintain your frontend stack and control version chains for libraries such as jQuery, AngularJS, and any other components necessary to your app's web interface.

Installing Bower

Bower is also a Node.js package, so you will install it using NPM, much like you did with the Browserify example installation in the previous section, but this time you will be installing the package globally. This will allow you to run bower from the command line anywhere on your system without having to install it locally for each project.

$ npm install -g bower

You can alternatively install Bower locally as a development dependency so that you may maintain different versions of it for different projects on the same system, but this is generally not necessary.

$ npm install bower --save-dev

Next, check that Bower is properly installed by querying the version from the command line.

$ bower -v

Bower also requires the Git version control system (VCS) to be installed on your system in order to work with packages. This is because Bower communicates directly with GitHub for package management data. If you do not have Git installed on your system, you can find instructions for Linux, Mac, and Windows at git-scm.com.

Configuring your bower.json file

The process of setting up your bower.json file is comparable to that of the package.json file for NPM. It uses the same JSON format, has both dependencies and devDependencies, and can also be automatically created.

$ bower init

Once you type bower init from the command line, you will be prompted to define several properties with some defaults given within parentheses:

? name: my-app
? version: 0.0.0
? description: My app description.
? main file: index.html
? what types of modules does this package expose? (Press <space> to? what types of modules does this package expose? globals
? keywords: my, app, keywords
? authors: Philip Klauzinski
? license: MIT
? homepage: http://gui.ninja
? set currently installed components as dependencies? No
? add commonly ignored files to ignore list? Yes
? would you like to mark this package as private which prevents it from being accidentally published to the registry? Yes

These questions may vary depending on the version of Bower you install.

Most properties in the bower.json file are not necessary unless you are publishing your project to the Bower registry, indicated in the final prompt. You will most likely want to mark your package as private unless you plan to register it and allow others to download it as a Bower package.

Once you have created the bower.json file, you can open it in a text editor and change or remove any properties you wish. It should look something like the following example:

{
  "name": "my-app",
  "version": "0.0.0",
  "authors": [
    "Philip Klauzinski"
  ],
  "description": "My app description.",
  "main": "index.html",
  "moduleType": [
    "globals"
  ],
  "keywords": [
    "my",
    "app",
    "keywords"
  ],
  "license": "MIT",
  "homepage": "http://gui.ninja",
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "private": true
}

If you wish to keep your project private, you can reduce your bower.json file to two properties before continuing:

{
  "name": "my-app",
  "private": true
}

Once you have the initial version of your bower.json file set up the way you like it, you can begin installing components for your app.

Bower components location and the .bowerrc file

Bower will install components into a directory named bower_components by default. This directory will be located directly under the root of your project. If you wish to install your Bower components under a different directory name, you must create a local system file named .bowerrc and define the custom directory name there:

{
  "directory": "path/to/my_components"
}

An object with only a single directory property name is all that is necessary to define a custom location for your Bower components. There are many other properties that can be configured within a .bowerrc file. For more information on configuring Bower, see bower.io/docs/config/.

Bower dependencies

Bower also allows you to define both the dependencies and devDependencies objects like NPM. The distinction with Bower, however, is that the dependencies object will contain the components necessary for running your app, while the devDependencies object is reserved for components that you might use for testing, transpiling, or anything that does not need to be included in your frontend stack.

Bower packages are managed using the bower command from the CLI. This is a user command, so it does not require super user (sudo) permissions. Let's begin by installing jQuery as a frontend dependency for your app:

$ bower install jquery --save

The --save option on the command line will save the package and version number to the dependencies object in bower.json. Alternatively, you can use the -S option as a shortcut for --save:

$ bower install jquery -S

Next, let's install the Mocha JavaScript testing framework as a development dependency:

$ bower install mocha --save-dev

In this case, we will use --save-dev on the command line to save the package to the devDependencies object instead. Your bower.json file should now look similar to the following example:

{
  "name": "my-app",
  "private": true,
  "dependencies": {
    "jquery": "~2.1.4"
  },
  "devDependencies": {
    "mocha": "~2.3.4"
  }
}

Alternatively, you can use the -D option as a shortcut for --save-dev:

$ bower install mocha –D

You will notice that the package version numbers are preceded by the tilde (~) symbol by default, in contrast to the caret (^) symbol, as is the case with NPM. The tilde serves as a more stringent guard against package version updates. With a MAJOR.MINOR.PATCH version number, running bower update will only update to the latest patch version. If a version number is composed of only the major and minor versions, bower update will update the package to the latest minor version.

Searching the Bower registry

All registered Bower components are indexed and searchable through the command line. If you don't know the exact package name of a component you wish to install, you can perform a search to retrieve a list of matching names.

Most components will have a list of keywords within their bower.json file so that you can more easily find the package without knowing the exact name. For example, you may want to install PhantomJS for headless browser testing:

$ bower search phantomjs

The list returned will include any package with phantomjs in the package name or within its keywords list:

    phantom git://github.com/ariya/phantomjs.git
    dt-phantomjs git://github.com/keesey/dt-phantomjs
    qunit-phantomjs-runner git://github.com/jonkemp/...
    parse-cookie-phantomjs git://github.com/sindresorhus/...
    highcharts-phantomjs git://github.com/pesla/highcharts-phantomjs.git
    mocha-phantomjs git://github.com/metaskills/mocha-phantomjs.git
    purescript-phantomjs git://github.com/cxfreeio/purescript-phantomjs.git

You can see from the returned list that the correct package name for PhantomJS is in fact phantom and not phantomjs. You can then proceed to install the package now that you know the correct name:

$ bower install phantom --save-dev

Now, you have Bower installed and know how to manage your frontend web components and development tools, but how do you integrate them into your SPA? This is where Grunt comes in.

Summary

Now that you have learned to set up an optimal development environment with NPM and supply it with frontend dependencies using Bower, it's time to start learning more about building a real app.

Resources for Article:


Further resources on this subject:


You've been reading an excerpt of:

Mastering JavaScript Single Page Application Development

Explore Title