如何在发布npm包时排除一些不需要发布的文件?
当发布一个 npm 包时,有时候我们希望忽略一些不需要发布的文件,比如测试文件、配置文件或者其他临时文件。这样可以减小包的大小,避免发布不必要的文件。
最近我就遇到这种需求。在我维护的包中,有一系列的包在同一个仓库,采用的monorepo形式管理,发布使用的lerna。这个过程中踩到了以下这些坑,觉得需要记录下来,并分享以供参考。
踩坑1
起初根据npm文档,我在仓库根目录创建了.npmignore
文件。并在文件内配置了需要排除的文件夹。发版之后,发现未生效。查阅lerna的资料,看到维护者的解释:
I actually prefer forcing people to duplicate all of these types configs. I prefer when every single package inside a Lerna repo is a fully working npm package. Meaning you could cd into the package and run npm install, npm publish, npm run [script] and all the rest and have everything still work.
整体表达的意思是lerna只作为协调所管理的包的工具,不想因为引入了lerna导致npm包有所不同,这些包仍然能够独立的作为根目录单独publish
和执行其他所定义的scrpit
。
于是,我把.npmignore
复制了很多遍并分发到各个npm包自己的目录中。再次发版,然并卵!
踩坑2
于是我开始怀疑.npmignore
的glob规则是不是没有匹配到对应的文件。npm文档上说明了.npmignore
和.gitignore
的规则是一致的,并且.gitignore
视为没有.npmignore
文件的回退方案。
翻阅了glob规则,尝试了不同形式的配置,依然不生效!于是开始怀疑是npm cli
的issue。查阅github找到了相关讨论。其中一个贡献者的观点我很认同:
I guess I’ll be in the minority, but we rely on this behavior to help us elegantly exclude dist from our git repository, but include it in our published tarballs. To achieve this, all we need to do is have a .gitignore that includes dist (along with many other things), and then a files block that includes dist and whatever else we explicitly need.
If this issue was resolved, we would need to create a .npmignore file that is a duplicate of .gitingore, minus dist. Maintaining that accurately would get pretty messy.
.gitignore
作为.npmignore
的回退配置,常常包含dist
等文件目录不需要提交到git仓库。但如果.npmignore
(换言之对.gitignore
也同样)的配置优先级高于files
配置,那么dist
这类目录将会非常尴尬!因为它们明确需要被发布到npm仓库,但又不需要被提交到git仓库。所以尽管这是npm cli
的issue,但修复它带来的影响确实算breaking change。维护者们对于这个修复保持谨慎态度可以理解。
结论
至此,得出了解决方案。可以混合使用files
和.npmignore
配置来进行npm包内容的细粒度控制,但要注意.npmignore
不要放到npm包的根目录。将.npmignore
放到具体的需要忽略文件所在的下层(相对于根目录)目录,可以是任意层级的,只要目录内包含想要忽略的文件即可。
另外,在解决这个问题的过程中盲目自信,直接发包导致了版本号快速提高了几个版本…这个过程可以通过npm pack --dry-run
参数避免,能够看到哪些文件将被发布到仓库。详细说明参看这里。完!