-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Files & Ignores
Most npm users tend to simply publish their modules, and expect the appropriate files to be included, but did you know npm allows more fine-grained control over what you end up pulling in?
This wiki page documents a lot of the details around these mechanisms, hopes to clarify its corner cases, and points to specific issues related to what users would expect, or we would want, from these cases.
There is also a detailed test suite covering most of the behavior discussed in this page.
The "files"
array in package.json
is an optional field. When present, it should be an array of entries to be included when publishing your package. It looks something like this:
// package.json
{
"files": [
"foo.js",
"lib/"
]
}
In this example, foo.js
in the root directory will be included when you do npm publish
. So will lib/
and all its contents (recursively).
If the files array is omitted, everything except automatically-excluded files will be included in your publish.
- Entries in
files
are minimatch globs. That means*.js
,lib/**/*.js
, etc, all work. - Entries in
files
are converted to include subdirectories, even ones intended as files. For example,foo.js
will be treated as bothfoo.js
andfoo.js/**
. It also meanslib
is all you need in order to include everything in that directory. - A trailing
/
infiles
does nothing. - npm automatically includes and excludes certain files, regardless of your settings. The entire list is in the npm documentation for
package.json
. -
node_modules/
gets special treatment. If you want to include dependencies in your publish, usebundledDependencies
. -
"The consequences are undefined" if you try to negate any of the
files
entries (that is,"!foo.js"
). Please don't. Use.npmignore
.
You can use ignore files, optionally in combination with a files
array, in order to get more fine-tuned control over what gets included or excluded. These are intended to have identical syntax to gitignore
, and will be used when deciding what to include in the published npm package.
# .npmignore
/test
.idea
There are various issues with inconsistent or unexpected behavior around ignores. See the Known Issues section below.
- If there is a
.gitignore
file, and.npmignore
is missing,.gitignore
's contents will be used instead: That means.npmignore
trumps.gitignore
: They are not merged. Furthermore,.gitignore
will be renamed to.npmignore
in the resulting tarball. - Entries matched by
files
will be included, regardless of.npmignore
settings. This is also a known issue. - You can have nested
.npmignore
files in your project. They will match starting from their current directory. - Lines prefixed with
/
will only match entries starting from the current location of that.npmignore
. For example,/foo
will matchfoo
and notlib/foo
, butfoo
will match both. -
./
is invalid syntax for bothgitignore
andnpmignore
if you're intending to match starting from the current directory. Use/
instead. -
npmignore
syntax is otherwise identical to thefiles
syntax, for ignoring: that means globs, automatic subdirs, etc, all work the same way.
-
#11669
-.npmignore
entries should trump entries in the files array -
#5673
- There is no user-level or globalnpmignore
. -
#8510
-main
file should be included automatically, regardless offiles
setting. -
#8791
- npm does not warn if files explicitly referenced infiles
do not exist. -
#3968
- npm doesn't respect .gitignore if ignored folder has an index.js in it.
Note: Several of the above already have partial fixes written. Wanna help? Check in on the issue, and you can help get them over the finish line! There's a Files and Ignores milestone to track these issues, which is the most up-to-date source of info.
Files and ignores are currently implemented with a stack of fstream
-based libraries. There is sometimes a bit of confusion between what is responsible for what, so here's an attempt to document the role different modules have. Note that the standard mechanism for extending fstream
is through subclassing and overriding, and all of these modules are (chained) subclasses of fstream.DirReader
.
-
lib/utils/tar.js
is the main npm-side entry point: This contains the tarball-generation code used bynpm pack
(and by extension,npm install
andnpm publish
). There is relatively little business logic here, but this is the right layer for things such as warnings, errors, and actual tarball packing/unpacking. It uses a subclass offstream-npm
. -
fstream-npm
contains most of the npm-specific business logic related to file inclusion and exclusion. This includes support for reading and handling thefiles
array,bundledDependencies
, reading.npmignore
as an ignore file, and automatic inclusions/exclusions likeREADME
andLICENSE
. It uses a subclass offstream-ignore
. -
fstream-ignore
is a generic directory reader that looks for.gitignore
-style ignore files and applies similar logic to the file stream thatgit
does. It includes no npm-specific business logic, and handles all the logic of reading the ignore files, parsing them, and recursively reading directories while looking for more ignore files and applying them. It is a subclass offstream.DirReader
. -
fstream
is a library with a suite of stream readers for handling various file I/O operations. TheDirReader
class included in this library is the base for all file inclusion in this stack.
Note that there are a few inconsistencies above: Most notably that a lot of business logic is divided between tar.js
and fstream-npm
with no obvious guidelines -- this happened for historical reasons. There was also a lot of duplication for practical purposes, which is removed by a PR (#11995) that fixes an issue related to unintentional dependency inclusion.