.npmignore
是一个可以给Node.js项目造成严重危害的文件,你应该立即停止使用该文件(除了下面所列的一种情况)。npm中已经永久内置了一个更好的替代文件,并且更易用更安全。
什么是 npmignore?
比如我下载了一个名为 cli-ux
的npm包,这是一组常见的 CLI UX 工具函数。该项目的根目录下有一个名为 /test
的文件夹,里面放的是测试脚本。为了使这个npm包更小,我们可以不要这些文件。我可以创建一个 npmignore 文件里面包含 /test
,这样在运行 npm publish
打包时,可以避免将该文件夹打包到项目中。
与此同时……
在该项目中,我在本地使用了 direnv
,使用这个工具我可以在打开某个含有 .envrc
文件的文件夹时设置环境变量。并且,我将该文件写入了全局的 gitignore
文件,所以我不需要担心它被提交到我的项目中。另外,在该项目中,我放了一些用于S3连接测试的AWS证书。
我也在项目中使用了 nyc 来进行代码覆盖率检测。这会将一些本地文件放到项目根目录下的 .nyc_output
文件夹中。该文件夹写进了项目的 .gitignore
文件中,所以无论是我还是其他开发人员都不会意外地提交该文件夹。
现在,我最不想做的事情就是在我发布的包里找到 .envrc
(出于安全原因)或者 .nyc_output
(出于整洁原因)。值得庆幸的是,npm 已经提前考虑到这一点,它不会发布已经写入 .gitignore 中的文件。
隐藏的问题
但是,你可能不知道的是,我添加 npmignore 文件的小操作实际上会导致 npm 现在读取的是该文件,而不是 gitignore 文件。这是个重大问题——仅仅因为我添加了这个 .npmignore
文件来隐藏我的测试文件夹,却导致我所有的 AWS 证书泄露给公众了。
更糟糕的是,我可能并不知道发生了什么。npm publish
不显示打包的文件,我也看不到 npm registry 上的文件。 查看文件唯一真正的方法就是将包添加到一个项目中,然后手动查看里面的 node_modules
。可能有一天我出于好奇会这么做,然后发现我的 AWS 证书已经公开好几个月了。
注意:在写了这篇文章后:在 npm@6 中,他们已经开始显示哪些文件将被打包,这样问题就少了一些。
任何时候,只要你在做一个项目并发布到npm上,如果这个讨厌的 npmignore 文件存在,你就处于危险之中。你也不会知道它是不是上传了你本地的 dotfiles。现在,npm 已经足够智能,不会上传 .npmrc
文件, 但是你使用的任何其它工具都必须在 .npmignore
中手动列入黑名单。
顺便说一句,如果你想知道什么文件 npm 将发布到 tarball 而不是实际发布,我喜欢使用下行代码:
npm pack && tar -xvzf *.tgz && rm -rf package *.tgz
白名单
列黑名单通常是错误的方向。几乎所有我看到的依赖于 gitignore
或 npmignore
的项目都会上传实际上不需要的文件(比如 测试,日志文件,有时是整个 sqlite 数据库)。每发生一次这种情况,你就设法去添加一个排除项,就像在玩”打地鼠”的游戏一样。(即使你查看了包里有什么文件,还是可能发生上面的情况)。
不过,npm 支持白名单,你只需将所有你想添加到项目中的文件和目录添加到 packge.json
的 files
属性上。现在,只有在 files
中指定的文件才会被打包到项目中,并且你的 dotfiles 会被忽略。如果你想添加一个 dotfile 或一个测试目录(这很奇怪),你需要在 files
中明确地指定。npm 会默认包含 README
,package.json
和一些其他文件,因此你不需要特意指定它们。
我喜欢将所有的 JavaScript 文件都放在 /lib
中,并在项目中使用 /lib/index.js
。我的 package.json
如下所示:
{
"name": "cli-ux",
"main": "./lib/index.js",
"files": [ "/lib" ]
}
注意,要在文件的所有元素前加上前缀 “/” 。否则,如果你有一个类似 "test/lib"的目录,它也将被包含在内。这算不上一个安全问题,但是能保持代码整洁。
这对于我按 /src
里放 .ts
文件以及 /lib
里放编译的 .js
文件模式建立的 typescript 项目(以及 babel )尤其适用。
/lib
只进入 npm
包中,而 /src 只放在在源码管理中。
唯一一次 npmignore 可以使用的情况
只要你已经在 files
中添加了白名单,那么使用 .npmignore
就真的没有问题。比如,Jest 鼓励开发者在源码树中建立 _test_
目录(或者 .test.js
但该解决方案可以与之一起使用)。在 files 配置中定义 /lib
是有意义的,在 npmignore 中添加 _test_
同样有意义,这样最终打包的文件不会包括 /lib/_test_
但会包括 /lib/index.js
。
npm and yarn:请补上这个
几个月前,npm 在他们的博客上发表了一篇文章,描述了我刚才所描述的内容。我远不是第一个处理这个问题的人。这种行为令人困惑且毫无理由。我觉得 npm 和 yarn 的下一个主要版本应该在这里设置一些安全措施。
我认为正确的解决方案是,如果用户试图在不指定 files
的情况下使用 .npmignore
,那么npm 和 yarn 将运行失败(或者至少进行警告并发出正在打包的精确文件)
我还有一些其他的想法,比如如果提交了 .env
或 .aws_credentials
这样的文件就发出警告,但是我真的觉得黑名单是一种解决这个问题的糟糕方式。尤其是在 .npmignore
如何与 .gitignore
关联的令人惊讶的行为中。最不济,npm init
和 yarn init
应该默认包含 files
。