JavaScript, like any other language, contains many ready-made functions and modules that facilitate development. Together, they make up the standard language library. In Node.js, for example, there are modules for cryptography (encryption), HTTP, file systems, and more. In browsers, this set is much smaller, but still present.
// Example of a built-in function
Math.round(5.34); // 5
// Node.js built-in module for working with files
import fs from "fs";
// Reads the contents of the file
const data = fs.readFileSync("path/to/file");
No matter how good a standard library is, it cannot cover all the issues that arise during development. Of course, you can implement all the missing components yourself, but then the development of any project will turn into an endless marathon. There are too many typical tasks to solve in any non-trivial project.
Commercial projects use millions of lines of third-party code written by programmers around the world. Such code is stored in libraries, which you can plug into your project. In the JavaScript world, they are commonly referred to as packages.
What issues do such packages solve? All sorts. From small useful functions for working with strings or dates to frameworks and software systems that shape code architecture. For example, the lodash library is incredibly popular in JavaScript. It provides about a hundred useful functions that solve typical issues with arrays, strings, and other data types. A couple of examples:
// By convention, lodash is imported as _ character
import _ from "lodash";
// Array Intersection
_.intersection([2, 1], [2, 3]); // => [2]
// capitalize makes the first letter capital
_.capitalize("hello"); // Hello
Each of these functions individually may look small. However, the larger the project, the more such features are required, and all together they become quite a large codebase. And it would also be nice to have good documentation.
Note how code is imported from external libraries. In this case, the package name is specified without the ./
path. This way, JavaScript understands that it's a package you're looking for, and does not need to look for a file named lodash.js.
// This will search for the file lodash.js in the current directory
import _ from "./lodash";
// This is how the code from the package is imported
import _ from "lodash";
Installing
If you just import lodash in the code and then run it, the program will crash with an error: "lodash not found". In order to use a third-party package, it must be added to the project as a dependency. There is an installation command in the npm for this purpose:
# Must be executed at the project root
# only then will lodash be in the right place
npm install lodash
This command performs three actions. First, it downloads a package into the node_modules directory at the root of the project. If this directory didn't exist before, it is automatically created. Then it adds an entry in package.json that the lodash package has become a dependency. Finally, it creates or updates the package-lock.json file.
tree -L 1
.
├── node_modules
├── package.json
├── package-lock.json
└── index.js
Dependencies are added to package.json under the dependencies
key. All packages used in the project and not included in the standard library are listed here.
"dependencies": {
"lodash": "^4.17.15"
}
The name of the package in the dependencies is specified as a key. This is the name used when importing the package. The value is the last available version at the time of download.
Now, when Node.js meets this kind of import:
import React from "react";
It makes an attempt to import a module from node_modules/react/...
All that's left is to deal with the package-lock.json file. Its purpose is rather complicated for beginners. So, here we won't go into detail, we'll just describe the general concept. The rest is better to learn in practice when working with real projects.
Briefly, the dependencies of our project have their own dependencies, and they, in turn, have their own dependencies (dependencies of dependencies are called transitive dependencies). Such a chain can be quite long, and the same packages can appear in different parts of it, but with different versions. package-lock.json contains a description of all the packages that will be installed, including all their dependencies and specific versions. This makes it possible to guarantee you have all the same versions of dependencies for all project developers. This file is created by the npm install
command and then used when installing dependencies. If there is a package-lock.json in the project, it is recommended to install the dependencies with the command npm ci
# If we want exactly the same versions of all the packages
# that the other developers on this project had
npm ci
Linking to git
Programmers don't often do projects from scratch. More often than not, they work with ready-made projects. Projects, in turn, are stored in git repositories. What needs to be stored in the repository and what doesn't when we talk about dependencies?
The code of the dependencies themselves is not part of the source code. It's always added to .gitignore. But the package.json and package-lock.json files are part of the source code and it's through them that Node.js learns which packages to put on the system.
Imagine that you clone a finished project from GitHub to your computer and immediately try to run it. It'll fail and show an error because the code of the dependencies themselves in node_modules (as well as the directory itself) is missing. To make it appear there, you have to run the command to install the already added dependencies:
# Executed at the project root
# Installing all the required dependencies
npm ci
This command does not change anything in the project. It only downloads dependencies into the node_modules directory, based on the contents of package.json and versions from package-lock.json.
Warnings
During the installation of the dependencies, npm displays many different messages. Among them are the following:
npm WARN deprecated minimatch@2.0.10: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue
Most of these messages do not affect the operation of the application. All they say is that some versions are out of date or the package is no longer in use.
Do it yourself
- Install the lodash in the hexlet-js project
- Add to the index.js file the import functions from the lodash package, as in the examples above
- Write
console.log(_.last(['one', 'two']));
to the index.js file - Run the code, make sure that
"two"
is the output - Add the changes to GitHub. Make sure that node_modules is ignored
- Examine the structure of the node_modules directory
- Find the source code of the lodash package on GitHub and compare it with the contents of node_modules
Recommended materials
- Search packages here
- Using a Library or Writing Your Own Code
- The difference between npm ci and npm install
For full access to the course you need a professional subscription.
A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.