npm for Beginners: A Guide for Front-end Developers

Unless you’ve been under a transpiler-sized rock for the past five years or you’re an absolute beginner to front-end coding, then you’ve probably heard of npm.

Maybe you’ve clicked through to the GitHub repo of a tool of some kind, and you noticed the installation instructions had a couple of different possibilities, including something like this:

npm install some-tool

In addition to that, there’s usually something like “download the script and include it at the bottom of your page using <script> tags”. Many of you probably go for that latter option.

There are tons of developers that have incorporated npm in some way into their workflow. But I’m guessing there are just as many developers and new front-end folks who are confused about what npm is, and why you’d want to use it.

I’ve been doing some extra reading and research on this subject, and I thought I would walk through most of what I’ve learned in this tutorial. While I don’t consider myself a super-expert in all the subtleties related to npm, I do think this npm tutorial should serve as a good starting point for those who have little or no knowledge of the subject and its benefits for front-end projects.

What is npm?

In brief, npm (stylized in lowercase, so it’s not correct to write it as “NPM”) is a package manager for JavaScript. It stands for Node Package Manager. The official documentation explains that npm is three different things:

  1. The website
  2. The npm registry
  3. The npm client

The website is a place where you can browse packages, read the docs, and find general info on npm.

The registry is a database that holds the information and the code for the packages.

The npm client is a tool installed on a developer’s machine that allows you to publish packages, install packages, and update packages.

Note: A “package” is just another way of saying “JavaScript plugin” or “module”. It’s a bit of a buzzword, but it’s an appropriate term because often packages consist of multiple files.

The rest of this article will go into more detail on the npm registry and using the npm client, but the video below is a good starting point too:

Installing Node.js and the npm Client

One of the things that’s somewhat intimidating to designers and those who don’t come from a strong programming background is the fact that npm is used via the command line. But it’s really not that big a deal for the purposes of just doing some basic package installing and updating.

To start using npm, you have to do two things:

  1. Install Node.js
  2. Install the npm client

Fortunately, when you install Node, the default installation settings will install the client too, so you can do both these steps in one shot. You may have Node installed on your machine already. To find out if this is the case, type the following in the command prompt, which spits out the version number for your Node installation:

node --version

In my case, when I started writing this article, I was at version 0.10.29, which was released in June of 2014. Seeing as the latest version is at 7.x, it was clearly time for an upgrade. If you do a clean install, you’ll have the option to install either the “recommended for most users” version (currently 6.9.4 LTS) or the version with the latest features (which I assume is similar to a nightly build).

For the purposes of just getting up and running to learn how to use npm for front-end development, I’d say install the recommended version. As mentioned, when you install Node.js, the installer will automatically install the npm client.

As pointed out in the above video, after you install node along with the npm client, it’s possible that the npm client will be out of date. To ensure you have the latest npm client, do the following (as weird as this looks):

npm install npm --global

That command says “use the npm client to install npm”. The --global part is a flag that tells the client that you want to install it globally (more on flags later). When that’s done, you can check the version number of your npm client:

npm --version

In my case, after updating my client, I was at version 4.0.5. To confirm that your version is the latest, you can view the releases on GitHub. The last version with a green “Latest Release” label on it is the one your system will update to if all goes well.

Using npm to Install Packages

The above instructions need to be followed only once, of course, and then you’ll be ready to use npm on your machine for all projects. But it’s somewhat annoying to have to do all that when it’s simple enough to just download a script or plugin manually or include it using a CDN link. In a way, front-end development feels like a Rube Goldberg machine – we’re jumping through all these hoops to do simple tasks. But, as I’ll discuss later in this article, npm has some significant advantages over the traditional way of using scripts. So it’s not as bad as it might seem at first glance.

In the meantime, let’s look at how you can use npm to add JavaScript modules and other packages to your projects.

As I mentioned at the beginning of this post, even if you’ve never used npm, you’ve probably seen it when you look up some kind of tool on GitHub, or on that tool’s documentation site. For example, let’s say you’re interested in trying out Modaal, the popular accessibile modal window plugin. In addition to the usual way to install it (download the script, include the CSS manually, etc.) developers have the option to install it via the command line using npm:

npm install modaal

This option is available for any tool in the npm registry. So this might be where many front-end folks, designers learning to code, and web development beginners might have some trouble. For example, when I first saw one of those npm install commands, my first reaction was twofold:

  1. Where do I run this command (i.e. which directory)?
  2. Specifically what does this do?

To answer that first question, remember that earlier when I installed npm, I used the --global flag. If you’re installing something globally on your system, then you don’t need to worry about what directory you’re in. But in the case of something like Modaal, you want to install it in the directory of the project that’s going to use it.

So let’s say you have a project called “Photo Gallery”, which might be a photo gallery app you’re building. That project might live in a directory called photo-gallery. Using the command line, you’ll navigate to the photo-gallery folder and exucute the command I showed you above to install the Modaal plugin (or any other package you want to install).

This alone is a nice time-saver. You don’t have to download the files yourself, you don’t have to figure out if the files need to be combined, you don’t have to worry about any missing CSS files – the whole thing gets pulled down from the npm registry using a single command.

Now here’s where things get a little sticky for front-end developers.

What Does npm install Do?

From the perspective of a front-end developer or designer who wants to drop a script into a project and start writing code, the way npm installs packages is a little strange and not as plug-and-play as you’d like.

In the case of my fictional photo-gallery app, what happens when I use npm to install Modaal? Here’s the resulting folder structure:

├── photo-gallery/
└───── node_modules/
        └───── modaal/
                ├───── demo/
                │       ├───── css/
                │       ├───── img/
                │       └───── js/
                ├───── dist/
                │       ├───── css/
                │       └───── js/
                └───── source/
                        ├───── css/
                        └───── js/
                               └───── lib/

In this example I left out the files inside the directories, so this is only the folders. As you can tell, this is a little confusing. You might wonder:

  • Why is everything inside a node_modules folder?
  • What’s the difference between dist and source? What is lib?
  • Can I just point to the files inside node_modules? Or do I have to manually move them up to the root of my project folder? If I have to move them, then why even bother using npm to install the whole thing?

These are legitimate concerns, and these are actually questions I’ve asked and that I’ve researched to help me understand why npm works like this. So I’m going to try to explain things as best I can, based on my research, testing, and experimenting.

dist/, src/, and lib/

First of all, the difference between the dist/ and src/ directories, as explained in this Stack Overflow thread, is:

  • src/ (or source/), is the raw code that you would read and/or edit, before any minification, concatenation, or other compilation tasks.
  • dist/ means “distribution”, and is the minified and/or concatenated version of the code that would be deployed to your production sites.

For the most part, these are matters outside the scope of npm in general. This is more about code and project architecture. Modaal has chosen to follow this pattern. Not all packages installed via npm are going to have this structure, but it might be good to be familiar with these concepts if you’re just getting started with managing front-end dependencies.

As for the lib/ folder, “lib” stands for “libraries”. That’s where Modaal has chosen to put its own dependencies. In this case, the only dependency is jQuery. Again, you might see a slightly different structure in other cases.

If you install Modaal yourself, you’ll notice that installing it via npm brings down these folders and a whole bunch of other stuff too, not just the files you plan to include in your project.

What’s With the node_modules Folder?

In order to understand why npm throws everything into a directory called node_modules, you have to first understand that npm is, first and foremost, a package manager for developers who write JavaScript on the server. That is, Node.js developers.

When a Node.js developer wants to use a package in their project, it’s more or less a two-step process. First, they install the package via npm, then they include it in their project with a line like this in their JavaScript:

let examplePackage = require('example-package');

Using the require() function makes their script look inside the node_modules folder for that specific package, or module. You could think of this like an include file in PHP, if you’re familiar with that. Or, closer to home, like a function reference in client-side JavaScript (which is more or less what this is). The above example will expose the examplePackage variable as an API that uses the functionality of the example-package module, whatever that is.

And please note that Node.js (i.e. server-side JavaScript) is not my area of expertise. This is my attempt at a basic overview of what is happening, to help you understand why front-end packages installed via node work the way they do. Feel free to correct me if I’ve misstated anything here.

If you want to read up a little more about npm, folders, and the node_modules directory you can do so in the npm docs.

How Does the node_modules Folder Work on the Front-end?

Here’s where things get a little complex if you’re using npm to install and use stuff exclusively for client-side scripting, or even for CSS. Yes, npm can be used to install basically anything that you use on the front-end, including CSS-only packages. Let’s use a popular example.

In the fictional photo-gallery project, if I decide I want to include Normalize.css, the ubiquitous CSS reset alternative, I would do this:

npm install normalize.css

Now I’ll have the following additional resources in my app’s directory structure:

├── photo-gallery/
└───── node_modules/
        └───── normalize.css/
                 ├───── CHANGELOG.md
                 ├───── LICENSE.md
                 ├───── normalize.css
                 ├───── package.json
                 └───── README.md

These would be in addition to the Modaal resources previously installed, but I’ve left those out for brevity. As you can see, a folder called normalize.css has been created, and inside that folder are five different files. The one I’m most interested in is normalize.css.

So how exactly do I use this file? If I leave it where it is, then I’m going to have to do the following with my <link> element in my HTML:

<link rel="stylesheet" href="node_modules/normalize.css/normalize.css">

That’s ugly and not great to work with. And that’s besides the fact that I commonly put all my CSS files in a css folder at the root of my project. Also, I don’t care about all that other stuff that’s installed; I want only the CSS.

At this point, unless I know any better, the only option is to copy the CSS file from inside node_modules/normalize.css/ and paste it into my css folder. From there, I might have a build process in place that combines and minifies my CSS (more on this later).

Here would be a good place to discuss why using npm is better than just grabbing stuff directly from repos and whatnot. But before I do that, there’s something else I’ve omitted so far that I should explain.

Installing Packages with Optional Flags

When I installed Modaal and Normalize.css, in both cases I just did a clean npm install [package] with no other commands. What I should have done is this:

npm install [package-name] --save

The difference being the addition of the --save flag. In order for this to be useful, I need to create a package.json file at the root of my project folder. The easiest way to do this is using the following command, which I would execute in the terminal inside my project folder:

npm init

This command will initialize a package.json file for me, creating it in the root of my project folder, and ask me to add some info to the file. Assuming I had not yet installed any packages, my package.json file should look something like this after I answer all the questions prompted by the init command:

{
  "name": "photo-gallery",
  "version": "1.0.0",
  "description": "My photo gallery app.",
  "main": "index.js",
  "dependencies": {},
  "devDependencies": {},
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Louis Lazaris <my@email.address> (https://www.impressivewebs.com/)",
  "license": "MIT"
}

Now I’ll add the two packages, this time installing them along with the --save flag:

npm install modaal normalize.css --save

As a shortcut, I’ve installed them both using a single command. Because I added the --save flag, this will update my package.json file. Here’s what it looks like now:

{
  "name": "photo-gallery",
  "version": "1.0.0",
  "description": "My photo gallery app.",
  "main": "index.js",
  "dependencies": {
    "modaal": "^0.3.1",
    "normalize.css": "^5.0.0"
  },
  "devDependencies": {},
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Louis Lazaris <my@email.address> (https://www.impressivewebs.com/)",
  "license": "MIT"
}

Notice the “dependencies” section has been updated to include the two packages I just installed. If I didn’t use the --save flag, then the packages would be installed without listing them as dependencies.

Another flag commonly used when installing packages is --save-dev. This adds the package to the “devDependencies” section of package.json. The difference, as explained in this Stack Overflow thread, is that --save is used for packages that are required for your app to run, while --save-dev is for packages used for development purposes (linting, unit tests, and so forth).

Another thing I should mention here is that all the flags I’ve used in the examples in this post have abbreviated versions. So:

  • --version can be written as -v
  • --global as -g
  • --save as -S
  • --save-dev as -D

Note that the “s” and “d” for “–save” and “–save-dev” are uppercase. There are other flags that use lowercase “s” and “d”. You can see a full list of flag shortcuts here.

Benefits of npm: Replicating Builds

As I mentioned earlier, there are benefits to using npm to install packages as opposed to just grabbing the files manually.

First of all, when packages are identified as dependencies in my package.json file (i.e. by installing them using the --save flag), this means I can share my project with another developer and that developer will be able to reproduce the full project, with dependencies, using a single command:

npm install

So if someone has a copy of photo-gallery, but doesn’t have the dependencies installed, all they have to do is navigate to the photo-gallery directory and run the above command. As long as package.json lists the dependencies, they will be installed automatically. This could mean dozens, or maybe even hundreds of packages can be installed with a single command.

As an example, if you used Git to grab a copy of UglifyJS2, it wouldn’t work unless you first used npm to install the dependencies (in this case, there are currently 4 listed in its package.json file). The dependencies don’t live in the GitHub repo for that project but npm allows you to grab them all using that single command (npm install).

You could mimic this behavior locally by deleting the node_modules folder in any project and then doing npm install in the root of that project. All that’s required is that you have the dependencies listed inside package.json, and they’ll be pulled in automatically.

Benefits of npm: Updating Packages

Another benefit of using npm is that it allows you to update any package to a newer version with a single command.

For demonstration purposes, let’s say I was using Normalize.css version 4.0.0. If I want to update Normalize.css, I simply have to run:

npm update normalize.css --save

But hold on! In this case, I didn’t get the latest version of Normalize.css (which, as of this writing, is 5.0.0); I got version 4.2.0.

When you update a package with npm, you’re not updating to the latest version; you’re updating to the latest version that will not have potentially breaking changes. This is recognized by the npm client by means of the version number, which uses Semantic Versioning, or SemVer. A detailed discussion of Semantic Versioning is beyond the scope of this article, but developers are encouraged to use this method of versioning for this reason. Hugo’s article on the subject might be a good place to start if you’re not familiar with SemVer.

If I want to view version details on all my project’s out-of-date dependencies, I can use the outdated command:

npm outdated

Running that command inside a project directory will output something like this in my terminal:

Package        Current  Wanted  Latest  Location
normalize.css    4.0.0   4.2.0   5.0.0  photo-gallery

For full details on what all that means, see npm-outdated in the npm docs. But in a nutshell, the “Current” column tells me what version is installed as a dependency; the “Wanted” column tells me what version I’ll be able to update to safely (using npm update); and the “Latest” column tells me the most up to date version that lives in the npm registry. If I had other out-of-date dependencies, those too would be listed. But in this case, I had only Normalize.css. My Modaal installation was the most up to date version as of this writing.

As a side point here, what if I want to be able to update to the latest version of a package, even if it’s a major version update with potentially breaking changes? I do this by changing my package.json file’s dependencies to look like this:

"dependencies": {
  "modaal": "^0.3.1",
  "normalize.css": "*"
},

Notice instead of a version number for Normalize.css, I’ve included an asterisk symbol. This tells the npm client that I’m willing to accept major version upgrades, regardless of breaking changes. For Modaal, I’ve kept it the same, so it won’t install a major release if I update later. Now if I run npm outdated I get the following:

Package        Current  Wanted  Latest  Location
normalize.css    4.0.0   5.0.0   5.0.0  photo-gallery

There’s a lot more to discuss when it comes to version numbers and npm, and it’s certainly something I’m getting more familiar with. In the meantime there’s more info, including a screencast on this subject, in the npm docs.

Benefits of npm: Productivity for Teams

As explained in the npm docs:

[npm] makes it possible for your team to draw on expertise outside of your organization by bringing in packages from people who have focused on particular problem areas. But even if you don’t reuse code from people outside of your organization, using this kind of module based approach can actually help your team work together better, and can also make it possible to reuse code across projects.

This sort of thing is still possible using manual copy-and-include methods, but that’s just not practical for a growing code base and across a team of developers.

So npm will allow you to not only use other people’s code available on the npm registry, but it’s an easy way to track dependencies and reuse code across different projects.

In short, npm encourages modular code. Wes Bos explained the benefits of modules nicely:

JavaScript modules allow us to chunk our code into separate files inside our project or to use open source modules that we can install via npm. Writing your code in modules helps with organization, maintenance, testing, and most importantly, dependency management.

Although he was specifically writing about ES6 Modules, the same basic principle applies: It’s easier to deal with code that’s separated into pieces, like building blocks. And the npm ecosystem encourages this type of coding.

Getting Back to the node_modules directory

Earlier I discussed the node_modules folder and the fact that every package gets installed in that location. It’s clear that from a front-end perspective, this isn’t the most practical setup. And the folks at npm have acknowledged as much:

This is a pretty obvious problem. The node_modules folder is where npm puts packages by default, to take advantage of the Node.js module loading semantics. Depending what packages you install, packages end up in different places in the tree. This works great for Node, but HTML and CSS, for better or worse, generally expect things to be in one location, like /static/mypackage. There are workarounds for this to be sure, but no first-class solution yet.

Ideally, I’d like to have a solution that allows my build process to use the stuff inside node_modules to create my production build. This would mean my CSS dependencies get combined and minified inside a css/ folder inside my project root, while JavaScript dependencies get bundled inside js/. Meanwhile, node_modules should be completely invisible from a production perspective.

From what I’ve researched, there are some solutions that you can consider, many of which require an extra tool or two.

Using Tools like Browserify and webpack

Kyle Robinson Young wrote about this subject back in 2013. He said:

In order to use node modules on the browser you will need a build tool. This might bother you. If this is a deal breaker then by all means continue wasting your life copying and pasting code and arranging your script tags.

Kyle then goes on to recommend Browserify for this purpose. I had seen lots of things about Browserify before but until I started researching this subject I didn’t know exactly how it would be beneficial. Remember earlier when I mentioned that the node_modules folder makes sense for Node.js development (that is, server-side JavaScript)? Well, the Browserify website describes the tool as follows:

Browserify lets you require(‘modules’) in the browser by bundling up all of your dependencies.

So the idea is that you get the exact same benefit but you don’t have to worry about having to move stuff out of node_modules manually. The only problem here is that this doesn’t seem to be a good solution for bundling up CSS. Maybe someone with experience using Browserify can chime in and explain their process.

Another potential solution is to try webpack, another module bundler originally designed for bundling JavaScript modules. The getting started guide in their documentation has a section on adding CSS to your app. There it’s recommended to use the css-loader and style-loader webpack plugins to help with this.

Using Grunt for Simple Bundling

If something like Browserify or webpack is a little too much for you, then you could consider a simple Grunt task that bundles up your JavaScript and/or CSS modules and dependencies by means of some manual configuration.

For example, you could do something like what’s described in this Stack Overflow thread, which uses the grunt-contrib-copy plugin.

This is a pretty common solution, but I don’t think there’s an easy way to use Grunt to automatically bundle up your CSS files from installed packages, without either copying the packages from the node_modules folder or manually finding each one to configure what gets copied, concatenated, and minified for production.

More on Bundling Modules and Dependencies

Installing and maintaining CSS dependencies via npm might require more work than it’s worth, but you’ll have to decide based on looking into some of the above technologies.

I might write more about this in a future post, but in the meantime here are some further resources and tools that could help:

The tl;dr Summary…

I covered a lot in this article, but a bullet list of the main ideas might help a little:

  • npm is used to install and manage packages, usually JavaScript modules and sometimes even CSS
  • Creating a package.json file (initialized with npm init) in a project’s root will allow you to manage your dependencies and keep them up to date
  • The --save flag helps keep package.json updated when you add, remove, or update a dependency
  • Using npm to install and manage dependencies is far superior to the manual download-and-include method
  • A tool like Browserify or webpack can help when dealing with packages strictly for front-end builds
  • Bundling CSS files in packages is challenging

Final Words from a Non-expert

I’ve been meaning to research and brush up on my knowledge in these areas for some time, so I thought it would be good to document everything I’ve learned so other front-end developers can benefit from it too. The extensive post above is what I’ve come up with.

If you have some experience in dealing with npm and how it relates to front-end development, feel free to comment and let me know if anything I’ve said needs to be corrected or improved. And more importantly, if you’ve managed to find a hassle-free solution to bundling front-end dependencies that includes CSS (maybe using Browserify or webpack?) I’d love to hear how you’re currently solving that problem.

15 Responses

  1. AgedLace:

    Very helpful article. Thank you!

  2. Great guide for beginners. Thanks for sharing.

  3. What exactly are you having trouble with re CSS? I’ve don’t recall ever finding it problematic. I look in the package to see which CSS files I need, then concat/minify using gulp (similar to grunt).

    For Bootstrap I could use `gulp-sass` to bring in the entire lot of CSS. But for efficiency, I manually copy the bootstrap.scss file (the one containing all the @imports) to my project, rename the paths to ‘node_modules/…’ and comment out the parts I don’t need.

    • I agree, that’s basically what I expect most people do.

      But, ultimately, it would be much more efficient if you didn’t have to “look” inside the packages. Packages should just work, and you shouldn’t need to find out where the CSS files are located to point to them. npm should install them in a source folder for you automatically, or else your Grunt/Gulp task should be able to find everything without needing to tell it where they’re located.

      For a small or medium project, I don’t think it’s a big deal to do some of the manual configuration to make sure you point to the right files. But for much larger projects, I think it would help if the whole thing was more automated.

      • Scott:

        I understand what you’re saying but I’m not sure that’s really possible. I mean, how is a package supposed to know which of its files you want to use? What if you have multiple packages in which you want to concatenate/minify one file from each? Maybe this is what bower does (or did – most people appear not to recommend it nowadays).

        • To be honest, from what I’ve seen, it’s somewhat of a flaw in npm itself in terms of the front-end. npm really isn’t built strictly for front-end development, which (as I quoted in the article) is acknowledged in the npm docs.

          It seems like there should be a better solution, a package manager just for client side JS and CSS or something like that.

        • Ameya Koshti:

          This is exactly the problem OP is trying to state. Now you are tightly couples with the node_modules. Webpack imports does help. I think Webpack is a necessity now.

    • lennym:

      If you are using sass, then you might find the `npm-sass` (npmjs.com/npm-sass) package useful. It allows you to seamlessly import sass from npm modules.

      Disclaimer: I wrote it.

  4. Fraser:

    Thanks so much for this article. I’ve been using npm (specifically for gulp) for around a year, and while I’m able to get things to hang together, I’ve always felt like a lot of things never really made sense from a front end perspective. This has cleared up *a lot* of the silly questions that were always niggling at me.

    Thanks again!

    PS – I’ve just tried to post this comment like 3 times and it keeps saying “your comment appears to be spam” – what’s that all about? If it’s because I included my website in the box title “website” then that’s really silly.

  5. Thank you very much!

  6. Shubham Waghe:

    Exactly my thought about the CSS, there should be something like @include(‘css’) :p Of course this looks silly but something over these lines to include CSS painlessly,..
    Good one :)

  7. Pelly:

    Thanks for the article!
    Though a huge question remains in my head: how do I go from development to production? I mean, let’s say I develop the whole site on my machine using npm and node.
    I’m done with development and the site is now ready to go live.
    My client has a hosting which they manage themselves so I can’t install node and npm on their server, how am I supposed to make node.js work with the website I built? Shouldn’t I then go and include all the files manually anyway? Isn’t there a way to ‘compile’ npm before going live so that it converts its code to normal script src tags?

    Also isn’t node.js pushing the front end dev into something that should be more back-end related?

    Sorry if these questions might be silly to you, but I’m really confused :)
    Thanks!

    • Hi Pelly,

      If you’re developing a website that uses Node.js on the back-end (like using PHP), then that’s a completely different story. I’m not sure if that’s what you meant though. My article is dealing with front-end code that uses npm as a package manager, which will not affect anything about pushing to production.

      When you push to production, you’re just uploading the files that make the site work. So you might have a bunch of .html pages, along with CSS and JS files. The node_modules folder is just for packaging things up, for updating the packages you use, and for separating your JS into modules. But when you push to production, you’re first going to use something like Grunt to concatenate and minify those files, then you’re going to upload a single JS file and CSS file.

      But like I said, if you’re talking about developing the backend with Node.js, then that’s something completely different that this article won’t help you with.

  8. Great article. It’s true that npm is mainly used for the server side. If you want to have something like that you can use a package manager for the front-end which is bower (https://bower.io/), the commands for this tool are very similar to npm so the learning curve will be minimal.

    Regards

Leave a Reply

Comment Rules: Please use a real name or alias. Keywords are not allowed in the "name" field. If you use keywords, your comment will be deleted, or your name will be replaced with the alias from your email address. No foul language, please. Thank you for cooperating.

Instructions for code snippets: Wrap inline code in <code> tags; wrap blocks of code in <pre> and <code> tags. When you want your HTML to display on the page in a code snippet inside of <code> tags, make sure you use &lt; and &gt; instead of < and >, otherwise your code will be eaten by pink unicorns.