npm / npm/cli

[BUG] "files" and root ".npmignore" don't work as expected.

Open
#6,221 3 comments 5 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Bug Needs Triage Release 9.x
Dominant language
JavaScript
Stars
10.1k
Forks
4.7k
Avg merge
2d 2h
Merged PRs (30d)
19

Description

Is there an existing issue for this?
  • I have searched the existing issues
This issue exists in the latest npm version
  • I am using the latest npm
Current Behavior

This seems related to https://github.com/npm/npm/pull/11669 which was closed a while ago with no action. Could we re-evaluate .npmignore behavior? It is confusing, and either the wiki is wrong or there is a bug.

  1. if files in package.json specifies "lib", lib content is included in the published pack
  2. if .npmignore says to ignore "lib/**/*.test.*, they still are included. (unexpected)
  3. even if .npmignore is added to the files list, it's still including the test files

The only way we've found to easily exclude test code from the lib folder is to include the .npmignore file in a subfolder (lib), rather then at root. Apparently that has precedence over the files list and works as expected. If we want it located at the root with all the other config files, we have to have a hacky copy step run pre-publishing.

Expected Behavior

At minimum, I expected .npmignore at root to pick off the matches resulting from the the files allow list. It does not. There's a wiki reference here which states:

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.

But that only seems to be true with nested non-root .npmignore files. So that's a bug, or the wiki is wrong.

But taking a step back, one way to improve the design to be more obvious while being backwards compatible:

  • deprecate .npmignore. (backwards compatible)
  • files can continue being an allow-list array (backwards compatible)
  • files can also be an object with explicit include and exclude arrays
"files": {
    "include":  [ "lib" ],
    "exclude": [ "*.test.*"]
}

(and include would have precedence over exclude.)

This makes things far more obvious, you don't have to muck with .npmignore being yet another config file that needs to live in a specific place, everything is contained in one package.json definition, tooling can recommend this usage, package lint tooling could even auto fix it.

The default behavior here is also desirable - having an allow list really should be the default recommended thing devs use to define what gets published. What we see in practice with .npmignore usage only is that over time tools are added without adding ignore exclusions, and things like config, logfiles, cache folders and unused build artifacts show up in the package undetected. So consumers end up downloading these things which at best ends up taking more disk space and network traffic, and at worst confuses their tooling (e.g. Typescript ends up parsing accidentally distributed source, which references dev dependencies that don't exist.)

Steps To Reproduce
  1. Create project with lib folder containing foo.js and foo.test.js
  2. Edit package.json to have a files list containing lib
  3. Edit .npmignore to have lib/**/*.test.* exclusion
  4. Run npm pack --dry-run

Expected: no test file in list
Resulted: test file in list

Environment
  • npm: 9.x
  • Node.js: 18
  • OS Name: Windows 11

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the behavior with a package.json files allow-list, a root .npmignore, and npm pack --dry-run as described. Start by tracing npm CLI package-file inclusion and ignore handling; done means matching test files are absent from the dry-run package listing without requiring a nested .npmignore.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, node.js
Domain
cli
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.