Quick summary
If you develop programs like web servers, lock file is very useful. But if you publish a library or CLI to npm, you should never publish a lock file. Because if you use it, it means you and your users may be using different versions of dependencies.
What is a Lock File?
The lock file describes the entire dependency tree, which is parsed at creation, including nested dependencies with a specific version. In npm it is named , in yarn it is named . In these two npm and yarn they are placed next to yours.
The content should be like this:
{ "name": "lockfile-demo", "version": "1.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { "ansi-styles": { "version": "3.2.1", "resolved": "/ansi-styles/-/ansi-styles-3.2.", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { "color-convert": "^1.9.0" } }, "chalk": { "version": "2.4.2", "resolved": "/chalk/-/chalk-2.4.", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } } } }
The format is different, but also contains similar information:
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. # yarn lockfile v1 ansi-styles@^3.2.1: version "3.2.1" resolved "/ansi-styles/-/ansi-styles-3.2.#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" chalk@^2.4.2: version "2.4.2" resolved "/chalk/-/chalk-2.4.#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" supports-color "^5.3.0"
Both contain some important information:
- The actual version of each dependency installed
- Dependencies for each dependency
- Verify the integrity of the package with a checksum in the resolved package
Since all dependencies are listed in the lock file, why do you still write them in? Why do we need two files?
vs. Lock File
The dependencies field shows the dependencies that your project should install, but does not show the dependencies for those dependencies. Dependencies can specify exact versions or semver ranges. For the semver range, npm or yarn will h choose the most suitable version.
This means that if you run npm install multiple times when you release a new version, you may get the same version of dependencies. For example, if you use npm install twilio to install a dependency like twilio, then the dependencies in the twilio may have an entry similar to this:
{ "dependencies": { "twilio": "^3.30.3" } }
If you consult the semver documentation on the npm website, you will see that ^ means that any version greater than 3.30.3 and less than 4.0.0 are valid versions. Therefore, if you do not lock the file when you release a new version, npm install or yarn install will automatically install one and yours will not be updated. But the content of lock file will be different.
If npm or yarn finds their respective lock files, they will be used instead of module installation. This is especially useful for situations such as continuous integration (CI). For this scenario, you can use special commands or flags for the corresponding package manager:
npm ci # will install exactly what's in the yarn install --frozen-lock-file # will install exactly what's in without updating it
This is very useful when you are building applications like web programs or servers because we want to simulate user behavior in a CI environment. Therefore, if we keep track of our lock file in source control (such as git), we can ensure that every developer, as well as the server or build system and CI system, can use the same version of dependencies.
So why can't we do the same when we write libraries to publish to npm? To answer this question, we must first discuss how publishing works.
How to publish modules
Contrary to what some people think, the content you post to npm is not always exactly the same as what you are on GitHub or in your project. The way the module is published is that npm will determine which file should be published by checking the files keys in the .npmignore file or if there is no ``. gitignore file. There are some files that are always included, and some will be excluded forever. You can find a complete list of these files on [npm page](/files/#files). For example, the .git` directory is always ignored.
After that npm will get the file list and use npm pack to package them together into a tarball. If you want to view the packaged files, you can run npm pack --dry-run in the project to see the output containing all files.
That tarball will be uploaded to the npm registry. When you run this command you may notice that you have joined you already have a , which is not actually bundled. This is because it will always be ignored.
This means that if another developer installs the package you posted, they will never download yours, so it will be completely ignored during the installation process.
This can lead to the "workable on my machine" surprise, as your CI and development environment may choose different dependency versions. So what can we do?
Disable lock file and shrink wrapping
First, we should stop tracking our lock file. If you are using git, add the following to the .gitignore file in your project:
Yarn's documentation says you should check in even if you create a library, but if you want to make sure you can guarantee the same experience as your users, I recommend adding it to .gitignore.
You can close the generation of the file by adding the following to the .npmrc file in the project:
package-lock=false
For yarn, you can ensure that lock file is not generated by adding the yarn install --no-lockfile flag.
Getting rid of does not mean that we cannot fix the dependencies and sub-dependencies we have. We can use another file called .
It is basically the same as , and is generated by npm shrinkwrap and actually packaged and published into the npm registry.
So by adding npm shrinkwrap to the npm script as a prepack script or even a git commit hook, you can ensure that in your development environment, the same version of dependencies are used in your users and CI.
**One important tip: ** By using shrinkwrap files, you can determine the exact version, but it will also prevent people from getting critical patches that are automatically installed. npm strongly opposes the use case of shrinkwrap for the library.
Learn more
Unfortunately, while there is a lot of relevant content in npm docs, it can sometimes be hard to find what you want. If you want to better understand what is installed or packaged, a common sign for you is --dry-run. Run the command without affecting your system.
For example, npm install --dry-run does not install the dependencies to your file system, or npm publish --dry-run does not actually publish the package.
The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.