-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
filesare minimatch globs. That means*.js,lib/**/*.js, etc, all work. - Entries in
filesare converted to include subdirectories, even ones intended as files. For example,foo.jswill be treated as bothfoo.jsandfoo.js/**. It also meanslibis all you need in order to include everything in that directory. - A trailing
/infilesdoes 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
filesentries (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
.gitignorefile, and.npmignoreis missing,.gitignore's contents will be used instead: That means.npmignoretrumps.gitignore: They are not merged. Furthermore,.gitignorewill be renamed to.npmignorein the resulting tarball. - Entries matched by
fileswill be included, regardless of.npmignoresettings. This is also a known issue. - You can have nested
.npmignorefiles 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,/foowill matchfooand notlib/foo, butfoowill match both. -
./is invalid syntax for bothgitignoreandnpmignoreif you're intending to match starting from the current directory. Use/instead. -
npmignoresyntax is otherwise identical to thefilessyntax, for ignoring: that means globs, automatic subdirs, etc, all work the same way.
-
#11669-.npmignoreentries should trump entries in the files array -
#5673- There is no user-level or globalnpmignore. -
#8510-mainfile should be included automatically, regardless offilessetting. -
#8791- npm does not warn if files explicitly referenced infilesdo 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.jsis the main npm-side entry point: This contains the tarball-generation code used bynpm pack(and by extension,npm installandnpm 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-npmcontains most of the npm-specific business logic related to file inclusion and exclusion. This includes support for reading and handling thefilesarray,bundledDependencies, reading.npmignoreas an ignore file, and automatic inclusions/exclusions likeREADMEandLICENSE. It uses a subclass offstream-ignore. -
fstream-ignoreis a generic directory reader that looks for.gitignore-style ignore files and applies similar logic to the file stream thatgitdoes. 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. -
fstreamis a library with a suite of stream readers for handling various file I/O operations. TheDirReaderclass 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.