
Master npm with Hugo: an introduction to npm
In a series of three posts I will introduce you to npm, show you how to manage dependencies, and show you how to customize build scripts. This is the first post of the series.
npm
npm is the default dependency manager for Node.js used by millions of developers. Your first question is most likely “what is a dependency manager and why do I need one?".
Almost any code you write probably ends up depending on 3rd party libraries. All of these libraries (projects, frameworks, files, etc) become dependencies of your project. npm lets you declare the dependencies for a project and it will install and manage them.
If you’ve used Composer for PHP, Bundler for Ruby, or pip for Python, then you’ve already used a dependency manager.
All these tools deal with packages. Every dependency is also a package. What constitutes a package? It can be a local file, local folder, remote zip, local Git repository, remote Git repository, GitHub repository, etc.
Most dependency managers also include a global registry of available packages. For npm, this is the npm Registry. To get an idea of what kind of packages are available, just browse through the most depended upon packages.
I’ll do my best to explain some npm concepts throughout the series, but the official npm Docs are quite accessible as well. It’s recommended to read them to get a full understanding of npm.
Installation
Installing npm is pretty simple. Download and install Node.js (it includes npm) for your platform. I recommend installing the current release.
Usage
Seeing npm in action usually solves most of the confusion you might have after reading about dependencies and packages. Let’s go through the most basic example of installing a single dependency to an empty project.
In this case our project is just an empty folder to start with:
mkdir npm-hugo && cd npm-hugo
For npm, you declare your dependencies in a package.json
file. Create one without having npm ask any questions:
npm init -y
For this example we’re only installing one dependency: Bootstrap, the popular HTML, CSS, and JS library:
npm install bootstrap@next --save-dev
You’ll then get the following output:
added 2 packages, and audited 2 packages in 2s
2 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
And your package.json
will look like:
{
"name": "npm-hugo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"bootstrap": "^5.0.0-beta1"
}
}
Let’s list out some folders to see what actually happened:
$ ls
Directory: .\npm-hugo
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 1/14/2021 7:44 PM node_modules
-a--- 1/14/2021 7:44 PM 1693 package-lock.json
-a--- 1/14/2021 7:44 PM 281 package.json
$ ls node_modules
Directory: .\npm-hugo\node_modules
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 1/14/2021 7:44 PM @popperjs
d---- 1/14/2021 7:44 PM bootstrap
-a--- 1/14/2021 7:44 PM 977 .package-lock.json
We can see that npm created a node_modules
directory that contains the bootstrap
and @popperjs
packages.
You might be wondering about the new package-lock.json
file that was generated. The official npm docs explain it nicely:
package-lock.json
is automatically generated for any operations where npm modifies either thenode_modules
tree, orpackage.json
. It describes the exact tree that was generated, such that subsequent installs are able to generate identical trees, regardless of intermediate dependency updates.
Advantages
You might still be wondering what’s the point in using npm and going through all the work above. npm (and any dependency manager for that matter) has many advantages:
- your dependencies are explicitly declared in a single place
- installing and updating is handled by the tool
- your project is locked onto specific versions
- you don’t need to include the actual 3rd party code in your version control repository
The last one is huge. Without a dependency manager, you’re stuck doing one of two things:
- adding the entirety of a 3rd party library into your VCS repo
- using something like Git submodules
This means that when you’re using npm, you check the following files into your repository:
package.json
package-lock.json
That’s it. Add node_modules
to your .gitignore
and let npm handle it. Now whoever wants to setup your project, they just run the standard git clone
followed by npm install
.
Wrapping up
You’re now familiar with the basic concepts of npm. We also went through the most basic example of installing a single dependency to an empty project. You can find the example in the npm-hugo repo I’ve set up.
In the next post we’re going to talk about how to manage dependencies.
Series posts
- Master npm with Hugo: an introduction to npm
- Master npm with Hugo: managing dependencies
- Master npm with Hugo: customizing build scripts