Lara

看在上帝的份上,不要使用 .npmignore

原文链接: medium.com

.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

白名单

列黑名单通常是错误的方向。几乎所有我看到的依赖于 gitignorenpmignore 的项目都会上传实际上不需要的文件(比如 测试,日志文件,有时是整个 sqlite 数据库)。每发生一次这种情况,你就设法去添加一个排除项,就像在玩”打地鼠”的游戏一样。(即使你查看了包里有什么文件,还是可能发生上面的情况)。

不过,npm 支持白名单,你只需将所有你想添加到项目中的文件和目录添加到 packge.jsonfiles 属性上。现在,只有在 files 中指定的文件才会被打包到项目中,并且你的 dotfiles 会被忽略。如果你想添加一个 dotfile 或一个测试目录(这很奇怪),你需要在 files 中明确地指定。npm 会默认包含 READMEpackage.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 inityarn init 应该默认包含 files