Lesson Weekend

We're now ready to start installing the packages we'll work with. We can install any npm package with the $ npm install [PACKAGE-NAME] command where [PACKAGE-NAME] is the package we want to install.

Version Pinning

Most of the packages we'll install specify a version of the package. This is called version pinning. When a package is updated, it won't necessarily play nicely with all the other packages in our environment. This is exactly what we were talking about in the last lesson! For that reason, it's more important to create a stable environment where all packages work together instead of a potentially chaotic environment where we are always installing the latest version of a package without fully testing whether it works with other packages we're using. The latter is a recipe for breaking our code - and a very frustrating debugging situation.

Version pinning is commonly used throughout the industry. As stated in the last lesson, companies generally do not automatically upgrade to latest releases, especially if the version they are already using is reliable and they don't need any new features that more recent versions offer.

While you are welcome to explore JavaScript packages further on your own, you are expected to use the pinned versions for independent projects. After all, if you were working at a tech company, you'd be expected to use the company's environment (which would likely be consistent across teams) instead of the other way around!

Installing an npm Package

Now we're ready to install our first package: webpack. We'll cover webpack itself further in the next lesson. For now, we are just learning how to install packages with npm.

$ npm install [email protected] --save-dev --save-exact

We specify a version with @. The version itself is 4.39.3. That's major version 4, minor version 39, and patch 3. We also have two flags --save-dev and --save-exact - which we will explain in more detail in just a moment.

When we run this command, three things will happen for us automatically:

  • npm will add the package to a directory named node_modules. If the directory doesn't exist yet, npm will create it for us. (We should never create or edit the node_modules directory ourselves.) Go ahead and look inside the directory. You'll see a lot of packages have been installed, not just webpack. These are all the packages that webpack itself depends on - and they've been added for us automatically.

  • npm will add the name and version number of the package to our package.json file. If we take a look at package.json, we'll see the following has been added automatically for us:

"devDependencies": {
    "webpack": "4.39.3"
}
  • Finally, npm will add our new dependencies to a file called package.lock.json. This file should never be edited either - that's why part of the file name is lock. If we open it up, we will see that it already has thousands of lines in it. This is the exact tree of our project's current dependencies. That's not just webpack - that's all the dependencies that webpack depends on. Generally, we will not worry about what's in this file. We really just need to worry about what is in our package.json file. While it's our job to make sure the packages we install work together, it's the job of the developers at webpack to make sure the dependencies webpack is using under the hood are good to go.

Now let's take a look at the flags we added to our $ npm install command.

  • --save-exact: This flag ensures that we save the exact version of webpack to our dependencies. This is very important and we'll discuss this further in a moment.

  • --save-dev: This flag specifies that we want the package to be a development dependency. It will be added to "devDependencies" in package.json. If we don't add this flag, it will automatically be added as a production dependency. While everything will still work correctly even if it's a production dependency, we don't need webpack in production - and having unnecessary dependencies would just bloat our production code.

We also need to install a package to have access to the CLI (command line interface) for webpack. This package will allow us to use webpack from the command line:

$ npm install [email protected] --save-dev

Let's take a look at package.json again to see how these commands have changed the contents of the file:

package.json
{
  "name": "shape-tracker",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "4.39.3",
    "webpack-cli": "^3.3.8"
  }
}

Note the difference in the package numbers between webpack and webpack-cli. The latter has a ^ before the number (known as the caret symbol). This symbol (along with the symbol ~ preceding the version number) can really mess us up. Here's why.

When we install a package that includes the ^, it will save the package we specify. However, let's say that we (or another developer) clones our project from Github. When they run npm install to install all of the packages in package.json, the ^ states that the version specified - or a later minor version - should be installed. However, if the latest minor version of a package isn't compatible with one of our other packages, it will cause errors. We see it happen all the time to students.

If the ~ symbol precedes the version number, this means that a later patch number can be used. While this is a bit less likely to cause issues than the ^, we've seen it happen before!

When we use the --save-exact flag, the ^ and ~ symbols will not precede the version number - so we won't have this issue.

If you do find yourself having version incompatibilities in your project, this is the first thing you should check - are there any ^ or ~ that result in slightly different packages being installed? (You may have forgotten to use the save-exact flag originally - or you may be working off a package.json file that didn't use them.) This is the most common issue students run into when packages that should be playing nicely together are not working correctly. If this happens, remove the ^ and ~ from version numbers and follow the steps in the next section of this lesson.

Removing Dependencies

Sometimes, you may want to remove a dependency from your project - or you may want to install a different version of the dependency. If so, you should first remove the reference to the dependency you aren't using from package.json. (For instance, if we wanted to remove webpack, we'd actually delete the line from the package.json file first. Don't do that now, though, since we want to keep webpack.) If you just want to change the version (or remove the ^ or ~) - you can do so manually. Of course, if you do so manually, make sure that you are actually changing it to the exact version you want.

Next, we can run the command $ npm prune. The command $ npm prune will ensure only dependencies listed in the manifest are actually installed (while others are removed).

We've found that npm prune doesn't always get the job done. Fortunately, there's a more foolproof way to reinstall dependencies. Trash the node_modules folder altogether. Then run npm install again. npm will automatically repopulate all the folder and its dependencies.

Whenever you are having a problem with your development environment and you are trying to reinstall dependencies, make sure you follow these troubleshooting steps!

Development and Production Dependencies

We can also have dependencies that are used for both development and production. When we install a package with npm, it's automatically added as a general dependency, which is for both dev and production. jQuery and Moment.js (which is used for adding time functionality to JavaScript) are examples of dependencies we'd add in this way.

However, most of the dependencies we'll add in upcoming lessons are development dependencies. That means they should always include the --save-dev flag like this:

npm install PACKAGE-NAME-HERE --save-dev

To make sure your projects run correctly (including code reviews), it's a good idea to clone the finished project and make sure it runs. This ensures the development environment has been set up correctly and that the package.json has all the correct dependencies.

Lesson 7 of 48
Last updated more than 3 months ago.