Skip to content

Commit

Permalink
Finished up the npm installation section
Browse files Browse the repository at this point in the history
  • Loading branch information
croach committed Jul 11, 2012
1 parent 0ed8c6b commit a6b1773
Showing 1 changed file with 21 additions and 11 deletions.
32 changes: 21 additions & 11 deletions 02.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,33 +155,43 @@ Well, I think that wraps up search and info, and I really can't think of any oth

### Installing packages

Alright we've covered quite a bit of ground with npm, but so far we haven't installed a single library. Well get ready to do that now, but first, we need to discuss installing locally vs globally.
Alright we've covered quite a bit of ground with npm today, but so far we haven't installed a single library. We'll get to that in a moment, but first, we need to discuss installing locally vs globally.

#### Local vs Global Installs

Whenever you install a package using npm you have a choice as to how you want to install it. The default way is to install the package locally, but just what does that mean? Well, to understand this, you'll first need to understand how node's `require` function works.
Whenever you install a package using npm you have a choice as to how you want to install it. The default is to install the package locally, but just what does that mean? Well, to understand this, you'll first need to understand how node's `require` function works.

Whenever `require` is called from within a node file, if argument passed in isn't a native module or a filepath, node will attempt to look up the module starting at the current directory, or the directory in which the file resides, and checking for the module in a directory called `node_modules`. If it's not found there, it goes on to the parent directory and does the same thing and so on until the root directory is reached. So, for example, since I'm in my home directory, if I had a file that called `require` and I passed in the name `foo`, node would look for `/Users/croach/node_modules/foo.js`. Since it doesn't exist, it would then look for `/Users/node_modules/foo.js` and finally `/node_modules/foo.js`.
Whenever `require` is called from within a node file, if the argument passed isn't a native module or a filepath, node will attempt to look up the module starting in the current directory, or the directory in which the calling file resides, and checking for the module in a directory called `node_modules`. If it doesn't find the module there, it goes on to the parent directory and does the same thing, and so on until the root directory is reached.

What all this means is that whenever npm installs a package locally, it will first check for a node_modules directory in the current directory and install there if it exists, and create it if id doesn't. Let's see how this works, but first let me just create a sandbox directory for me to play around in. Now, try calling `npm install express`. If you're curious, Express is a web development framework for node based on ideas from Ruby's Sinatra that we'll use later in this tutorial.
So, for example, as you can see, I'm in my home directory, and if I had a file that called `require` and I passed in the name `foo`, node would first look for `/Users/croach/node_modules/foo.js`. Since it doesn't exist, it would then go up a directory and look for `/Users/node_modules/foo.js` and finally it would check for `foo.js` in the node modules folder in the root directory.

There, the package was installed, now let's do an `ls` to see that the node_modules directory was created and do an `ls node_modules` to see that the express framework has been installed within it. You can also do an `npm ls` to list all of the packages installed locally.
What all this means is that whenever npm installs a package locally, it will first check for a node modules directory in the current directory and install it there if it exists, and create the directory if it doesn't. I want to show you how this works now, but let me first just create a sandbox directory for me to play around in. Now, try calling `npm install express`.

Notice that express is listed at the top of what looks like some type of tree. This is the dependency tree for express, so it's safe to assume that all of these packages were installed along with express. But, when we did an `ls` on the node_modules directory we didn't see any of these other packages, so where were they installed?
> If you're curious, Express is a web development framework based on ideas from Ruby's Sinatra framework and we'll use it later in this tutorial.
Well, that's part of the beauty of the way that node's `require` function works. Remember I said that it looks first inside of a node_modules folder in the same directory as the file that is requiring the module. Well that would mean that the modules required by express would be found within a node_modules folder inside of the express folder, right?
Ok, the package was installed, now let's do an `ls` to see that the node_modules directory was created and do an `ls node_modules` to see that the express framework has been installed within it. You can also do an `npm ls` to list all of the packages installed locally.

Try doing an `ls` on the express folder. Aha, so there's another node_modules in there. Now do an `ls` on that folder. Now we're seeing the four direct dependencies of express. The beauty of this mechanism is that it allows each program to install whatever dependencies it needs locally preventing any sort of version clashing that typically comes with shared dependencies.
Notice that express is listed at the top of what looks like some type of tree structure. This is the dependency tree for express, so it's safe to assume that all of these packages were installed along with express. But, when we did an `ls` on the node modules directory we didn't see any of these other packages, so where are they installed?

So local installs look like the way to go for your package installation needs, so what are global installs for? Well, some packages have executables that come along with them, essentially commands that you can run that perform tasks for you. For those, you might want to install them globally. Express is one such package that comes with a command line program that you can use to create application skeletons much like the rails program for Ruby on Rails does. To install the Express package globally, you simply need to add the `-g` option to the install command. Try it out now, by typing `npm install express -g`.
Well, that's part of the beauty of the way that node's `require` function works. Remember I said that it looks first inside of a node modules folder in the same directory as the file that's requiring the module. Well that would mean that the modules required by express would be found within a node modules folder inside of the express folder, right?

Try doing an `ls` on the express folder. Aha, so there's another node modules folder in there. Now do an `ls` on that folder. Now we're seeing the four direct dependencies of express that we in the dependency tree printed out by `npm ls` earlier.

The beauty of this mechanism is that it allows each module to install whatever dependencies it needs locally preventing any sort of version clashing that typically shows up with the use of shared dependencies.

So local installs look like the way to go for your package installation needs, so then what are global installs for? Well, some packages have executables that come along with them, essentially commands that you can run that perform tasks for you. For those, you might want to install them globally. Express is one such package that comes with a command line program that you can use to create application skeletons much like the rails program for Ruby on Rails does. To install the Express package globally, you simply need to add the `-g` option to the install command. Try it out now, by typing `npm install express -g`.

Now we can call `express -h` to see the help output for the `express` program. If you'd like to see what all you have installed globally, just type `npm ls -g`. Pretty much anything that you can do with npm you can do globally by adding the `-g` option. Now let's go ahead and remove the express package globally by calling `npm uninstall express -g`. If we call `express -h` again, this time we should get back a "command not found" error.

So, installing packages with executables globally works, but what if we want don't want to muddy our global space with a bunch of packages that we only need for specific projects. I do a lot of programming in python and I love the virtualenv library for creating virtual environments, essentially like little gated communities where I can install whatever I want and never have to worry about polluting the main environment.

Well, with just a little code added to our .bashrc file we can create something pretty similar, and I'm going to show you how you can do that now.

#### Virtual Environments

So, installing packages with executables globally works, but what if we want don't want to muddy our global space with a bunch of packages that we only need for specific projects. I do a lot of programming in python and I love the virtualenv library for creating virtual environments, essentially like little gated communities, where I can install whatever I want and never have to worry about polluting the main environment.
Before we add the bash functions that will create our virtual environments, I want you to understand just what it is that these functions will be doing. So, let's first take another look in the local node modules directory, this time with the `-a` option. Notice a hidden file in there that we didn't see before called `.bin`. If you take a look inside of there, you'll see a symbolic link that points right to the express command in the locally installed package. This `.bin` folder is where npm links all of the executables that each package provides. So, if we can just get that folder added to our PATH environment variable whenever we `cd` into a node application's directory, we would gain access to each package's command line programs without the need to install them globally and I've created a few bash functions to do just that.

Well, with just a little code added to our .bashrc file we can create something pretty similar. First, take another look in the local node_modules directory, this time with the `-a` option. Notice a hidden file in there that we didn't see before called `.bin`. If you take a look inside of there, you'll see a symbolic link that points right to the express command in the locally installed package. This `.bin` folder is where npm links all of the executables that each package provides. So, if we can just get that folder added to our PATH environment variable whenever we `cd` into a node application's directory, we would gain access to each package's command line programs without the need to install them globally. I've created a few bash functions to do just that. I'm not going to go over what they do here---if you're trully intersted, just ask in the comments and I'll post some notes on what the code does---but, for now, let's just head on over to the github repository that I've setup for the scripts for these screencasts. If we go to 02.md (and, yes, of course, I number them starting from 00) we can scroll down to very near the bottom of this script and copy the code. Then jump back to the terminal and open up your .bashrc file and paste the code right below the tab completion code for npm. Then, exit back out and source the .bashrc file and that should do it.
I'm not going to go over what the functions do here---if you're trully intersted, just ask in the comments and I'll post some notes on what the code does---but, for now, let's just head on over to the github repository that I've setup for the scripts for these screencasts. If we go to 02.md (and, yes, of course, I number them starting from 00) we can scroll down to very near the bottom of this script and copy the code. Then jump back to the terminal and open up your .bashrc file and paste the code right below the tab completion code for npm. Then, exit back out and source the .bashrc file and that should do it.

Now if you cd out of the current directory and then back into it, the virtual environment should have been created. You can check by calling `echo $PATH` and making sure that the current directory has been added to the PATH variable, but you can also just call `express -h` again to make sure that we can call it. To further make sure, call `which express` to see that it is, in fact, calling the one stored in the local `node_modules/.bin`. The nice thing about the virtual environment code is that when you leave the node application's directory, it will reset your environment. So, if we cd back out of this directory and try to call `express -h` again, you'll notice we get the "command not found" error once again.

Expand Down

0 comments on commit a6b1773

Please sign in to comment.