1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
|
.TH "NPM\-SHRINKWRAP" "1" "April 2016" "" ""
.SH "NAME"
\fBnpm-shrinkwrap\fR \- Lock down dependency versions
.SH SYNOPSIS
.P
.RS 2
.nf
npm shrinkwrap
.fi
.RE
.SH DESCRIPTION
.P
This command locks down the versions of a package's dependencies so
that you can control exactly which versions of each dependency will be
used when your package is installed\. The \fBpackage\.json\fP file is still
required if you want to use \fBnpm install\fP\|\.
.P
By default, \fBnpm install\fP recursively installs the target's
dependencies (as specified in \fBpackage\.json\fP), choosing the latest
available version that satisfies the dependency's semver pattern\. In
some situations, particularly when shipping software where each change
is tightly managed, it's desirable to fully specify each version of
each dependency recursively so that subsequent builds and deploys do
not inadvertently pick up newer versions of a dependency that satisfy
the semver pattern\. Specifying specific semver patterns in each
dependency's \fBpackage\.json\fP would facilitate this, but that's not always
possible or desirable, as when another author owns the npm package\.
It's also possible to check dependencies directly into source control,
but that may be undesirable for other reasons\.
.P
As an example, consider package A:
.P
.RS 2
.nf
{
"name": "A",
"version": "0\.1\.0",
"dependencies": {
"B": "<0\.1\.0"
}
}
.fi
.RE
.P
package B:
.P
.RS 2
.nf
{
"name": "B",
"version": "0\.0\.1",
"dependencies": {
"C": "<0\.1\.0"
}
}
.fi
.RE
.P
and package C:
.P
.RS 2
.nf
{
"name": "C",
"version": "0\.0\.1"
}
.fi
.RE
.P
If these are the only versions of A, B, and C available in the
registry, then a normal \fBnpm install A\fP will install:
.P
.RS 2
.nf
A@0\.1\.0
`\-\- B@0\.0\.1
`\-\- C@0\.0\.1
.fi
.RE
.P
However, if B@0\.0\.2 is published, then a fresh \fBnpm install A\fP will
install:
.P
.RS 2
.nf
A@0\.1\.0
`\-\- B@0\.0\.2
`\-\- C@0\.0\.1
.fi
.RE
.P
assuming the new version did not modify B's dependencies\. Of course,
the new version of B could include a new version of C and any number
of new dependencies\. If such changes are undesirable, the author of A
could specify a dependency on B@0\.0\.1\. However, if A's author and B's
author are not the same person, there's no way for A's author to say
that he or she does not want to pull in newly published versions of C
when B hasn't changed at all\.
.P
In this case, A's author can run
.P
.RS 2
.nf
npm shrinkwrap
.fi
.RE
.P
This generates \fBnpm\-shrinkwrap\.json\fP, which will look something like this:
.P
.RS 2
.nf
{
"name": "A",
"version": "0\.1\.0",
"dependencies": {
"B": {
"version": "0\.0\.1",
"from": "B@^0\.0\.1",
"resolved": "https://registry\.npmjs\.org/B/\-/B\-0\.0\.1\.tgz",
"dependencies": {
"C": {
"version": "0\.0\.1",
"from": "org/C#v0\.0\.1",
"resolved": "git://github\.com/org/C\.git#5c380ae319fc4efe9e7f2d9c78b0faa588fd99b4"
}
}
}
}
}
.fi
.RE
.P
The shrinkwrap command has locked down the dependencies based on what's
currently installed in \fBnode_modules\fP\|\. The installation behavior is changed to:
.RS 0
.IP 1. 3
The module tree described by the shrinkwrap is reproduced\. This means
reproducing the structure described in the file, using the specific files
referenced in "resolved" if available, falling back to normal package
resolution using "version" if one isn't\.
.IP 2. 3
The tree is walked and any missing dependencies are installed in the usual fashion\.
.RE
.SS Using shrinkwrapped packages
.P
Using a shrinkwrapped package is no different than using any other
package: you can \fBnpm install\fP it by hand, or add a dependency to your
\fBpackage\.json\fP file and \fBnpm install\fP it\.
.SS Building shrinkwrapped packages
.P
To shrinkwrap an existing package:
.RS 0
.IP 1. 3
Run \fBnpm install\fP in the package root to install the current
versions of all dependencies\.
.IP 2. 3
Validate that the package works as expected with these versions\.
.IP 3. 3
Run \fBnpm shrinkwrap\fP, add \fBnpm\-shrinkwrap\.json\fP to git, and publish
your package\.
.RE
.P
To add or update a dependency in a shrinkwrapped package:
.RS 0
.IP 1. 3
Run \fBnpm install\fP in the package root to install the current
versions of all dependencies\.
.IP 2. 3
Add or update dependencies\. \fBnpm install \-\-save\fP each new or updated
package individually to update the \fBpackage\.json\fP and the shrinkwrap\.
Note that they must be explicitly named in order to be installed: running
\fBnpm install\fP with no arguments will merely reproduce the existing
shrinkwrap\.
.IP 3. 3
Validate that the package works as expected with the new
dependencies\.
.IP 4. 3
Commit the new \fBnpm\-shrinkwrap\.json\fP, and publish your package\.
.RE
.P
You can use npm help outdated to view dependencies with newer versions
available\.
.SS Other Notes
.P
A shrinkwrap file must be consistent with the package's \fBpackage\.json\fP
file\. \fBnpm shrinkwrap\fP will fail if required dependencies are not
already installed, since that would result in a shrinkwrap that
wouldn't actually work\. Similarly, the command will fail if there are
extraneous packages (not referenced by \fBpackage\.json\fP), since that would
indicate that \fBpackage\.json\fP is not correct\.
.P
Since \fBnpm shrinkwrap\fP is intended to lock down your dependencies for
production use, \fBdevDependencies\fP will not be included unless you
explicitly set the \fB\-\-dev\fP flag when you run \fBnpm shrinkwrap\fP\|\. If
installed \fBdevDependencies\fP are excluded, then npm will print a
warning\. If you want them to be installed with your module by
default, please consider adding them to \fBdependencies\fP instead\.
.P
If shrinkwrapped package A depends on shrinkwrapped package B, B's
shrinkwrap will not be used as part of the installation of A\. However,
because A's shrinkwrap is constructed from a valid installation of B
and recursively specifies all dependencies, the contents of B's
shrinkwrap will implicitly be included in A's shrinkwrap\.
.SS Caveats
.P
If you wish to lock down the specific bytes included in a package, for
example to have 100% confidence in being able to reproduce a
deployment or build, then you ought to check your dependencies into
source control, or pursue some other mechanism that can verify
contents rather than versions\.
.SH SEE ALSO
.RS 0
.IP \(bu 2
npm help install
.IP \(bu 2
npm help 5 package\.json
.IP \(bu 2
npm help ls
.RE
|