Lesson Weekend

Goals

In this lesson we're going to start using the Node Package Manager or npm to install tools from the command line for use in our project. When we installed Node.js, npm was also installed automatically. The tools we will install will help us create our asset pipeline.

Initializing npm

Whenever we start a new project we need to run the following command from the top level of our project directory to begin using npm:

$ npm init

This creates a manifest file which is where npm stores a list of packages needed for the project, along with which versions we need. Think of this file as a grocery store list for your project - it keeps track of all the third party packages that it needs to run.

We'll be prompted to enter some information as we create this file. For name we can type ping-pong and then press enter. Other than that, we can press enter at each prompt to leave all the defaults. You can always edit this file later. It should look like this:

package.json
{
  "name": "ping-pong",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "directories": {
    "test": "test"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

A note here on naming conventions: Node does not allow spaces in the package.json project name. This means that "ping-pong" is a valid name, but "ping pong" is not.

Installing npm Packages

Now, let's install our first package: gulp. Gulp is a JavaScript package that runs development tasks for us.

$ npm install gulp --save-dev

One command is all we need to download a package using npm.

What is gulp? How is it related to npm?

Gulp will be in charge of optimizing our code and packaging it up in a format that the browser can understand. While it is an npm package itself, it will also be in charge of using all the other npm packages that we will download later.

When we run the above command, npm will create a node_modules folder in our project, and install the gulp package in it. The --save-dev flag will save the gulp package to the "shopping list" in our manifest file, which is called package.json. It should now look like this:

{
  "name": "ping-pong",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "gulp": "^3.9.1"
  }
}

We can see that gulp has been added under "devDependencies". This stands for development dependency, which means it will be used in app development, not in production in the browser. When we downloaded gulp we used the --save-dev flag, because gulp isn't actually a part of our app. It is only used in the build process. By separating out dependencies that are used in the final production app for users from dependencies that are just used in developing the app (such as gulp), the production app can be smaller and faster.

Npm also keeps track of which version of each package we need - we can see it is listed as version 3.9.1 (at the time of this writing).

More Packages: Browserify

Let's download another package with npm! This one is called browserify. Again, in the command line we want to make sure we are in the top level of our project directory, and then enter the following command:

$ npm install browserify --save-dev

If we look inside of package.json again, we will see that "browserify" is also listed under "devDependencies".

Why browserify?

If we run index.html in the browser again at this point, it will complain about two things before we even submit our form:

Uncaught ReferenceError: exports is not defined
Uncaught ReferenceError: require is not defined

This is because both the require keyword and the exports keyword are provided by Node and aren't available in the browser. The browserify package is responsible for using these keywords to translate the code into JavaScript our browser does understand. It follows each file path used by require like a treasure map and collects all the code into some less readable code that will make sense to our browser.

We will learn how to actually use gulp to run browserify in the next lesson.

Ignoring Packages in Git

Next, we'll add a .gitignore file to the top level of our project directory. If you haven't used one before, a .gitignore file is a list of folders and files inside your project directory which won't be committed to your Git repository. We should do whatever we can to keep our repositories as lean and clean as possible, and that means keeping libraries and other code out of our repo if they are better off being downloaded from their other providers.

Let's add node_modules/ to our .gitignore file. Because these packages of code are available for anyone to download, we don't need to push them to our Github repositories. Our manifest will declare which packages our projects require. Anyone who wants to download and run our project will run $ npm install to gather their own copies of these packages. This keeps our project from getting unnecessarily large and always ensures users are receiving up-to-date packages.

We'll practice this process more later. But basically:

  • When we start a new project, we run the $ npm init command.
  • Then, we download each package that our project needs using either the --save-dev flag for development dependencies or the --save flag for dependencies that are used in production. We actually won't be using npm for production dependencies in this class, but it's good to know what the flag means.
  • Make sure the node_modules/ folder is included in your .gitignore file before you commit the package.json file with the project.
  • When we clone a project to continue working on it, we simply run $ npm install and all packages saved to the manifest file will be downloaded into a new node_modules/ folder.

Here is an example .gitignore file. This should go in the top level of your project folder.

.gitignore
node_modules/
.DS_Store

.DS_Store is a Mac-specific file that doesn't need to be committed with your repository. It's unnecessary for your project, and your repo looks cleaner without one. If you haven't done so already, you can also configure your global .gitignore file to always ignore these, as instructed in the Git Configurations lesson from Intro to Programming.