无论我尝试什么,npm 都不会忽略我的 TypeScript 源代码文件

npm will not ignore my TypeScript source code file no matter what I try

我有一个用 TypeScript 编写的开源项目,编译为 JavaScript,然后通过 npm publish 作为 CLI 工具发布。

我已经无法 排除 npm包中的TypeScript源代码,还有其他*.ts似乎随机包含的文件(但我们将在此处重点介绍一个文件)。

我没有问题,包括 TypeScript 源文件,但这只是为用户永远不需要的东西向包添加额外的字节。

我可以用非常小的设置重现问题

package.json

{
    "name": "example",
    "version": "1.0.0",
    "main": "readme.js"
}

我尝试了一个非常激进的忽略列表:

.npmignore

**/*
*.ts
**
*
*.*
readme.ts

创建一些源代码文件

touch readme.ts
touch readme.js

现在,如果我尝试生成 npm 包,它将包含 readme.ts 文件。

$ npm pack
npm notice
npm notice package: example@1.0.0
npm notice === Tarball Contents ===
npm notice 0   readme.js
npm notice 76B package.json
npm notice 0   readme.ts
npm notice === Tarball Details ===
npm notice name:          example
npm notice version:       1.0.0
npm notice filename:      example-1.0.0.tgz
npm notice package size:  195 B
npm notice unpacked size: 76 B
npm notice shasum:        a1ee7cc6b7b0d1e2eccf870e95d7df38c5dcb609
npm notice integrity:     sha512-ppNEfKEvT9DEP[...]+d16IWbrj7OdA==
npm notice total files:   3
npm notice
example-1.0.0.tgz

那么为什么要包含 readme.ts

我排除了所有文件,package.json 文件中只引用了 readme.js

$ npm --version
6.13.1

简短回答: 名为 readme.* 的文件(例如 readme.fooreadme.quux 等)将被 npm 包含,无论您如何尝试在你的 .npmignore 文件中否定它。


NPM 的测试文件:

npm-cli titled "certain files included unconditionally" starting at line #511 they include a test for a file named readme.randomext.

的 npm 测试之一中

通过观察这个测试我们可以得出结论,任何名为 readme.* 的文件都将包含在 tarball (.tgz) 文件中,即使它可能在 .npmignore 文件。

以下是上述名为 pack-files-and-ignores.js

的 NPM 测试文件的摘录
test('certain files included unconditionally', function (t) {
  var fixture = new Tacks(
    Dir({
      'package.json': File({
        name: 'npm-test-files',
        version: '1.2.5'
      }),
      '.npmignore': File(
        'package.json',
        'README',
        'Readme',
        'readme.md',
        'readme.randomext',   // <----
        'changelog',
        'CHAngelog',
        'ChangeLOG.txt',
        'history',
        'HistorY',
        'HistorY.md',
        'license',
        'licence',
        'LICENSE',
        'LICENCE'
      ),
      'README': File(''),
      'Readme': File(''),
      'readme.md': File(''),
      'readme.randomext': File(''),     // <----
      'changelog': File(''),
      'CHAngelog': File(''),
      'ChangeLOG.txt': File(''),
      'history': File(''),
      'HistorY': File(''),
      'HistorY.md': File(''),
      'license': File(''),
      'licence': File(''),
      'LICENSE': File(''),
      'LICENCE': File('')
    })
  )
  withFixture(t, fixture, function (done) {
    t.ok(fileExists('package.json'), 'package.json included')
    t.ok(fileExists('README'), 'README included')
    t.ok(fileExists('Readme'), 'Readme included')
    t.ok(fileExists('readme.md'), 'readme.md included')
    t.ok(fileExists('readme.randomext'), 'readme.randomext included')    // <----
    t.ok(fileExists('changelog'), 'changelog included')
    t.ok(fileExists('CHAngelog'), 'CHAngelog included')
    t.ok(fileExists('ChangeLOG.txt'), 'ChangeLOG.txt included')
    t.ok(fileExists('license'), 'license included')
    t.ok(fileExists('licence'), 'licence included')
    t.ok(fileExists('LICENSE'), 'LICENSE included')
    t.ok(fileExists('LICENCE'), 'LICENCE included')
    done()
  })
})

解决方法:

您可以考虑一些解决方法,例如:

  1. 最简单的方法是将文件重命名为例如read-me.ts 然后在 .npmignore 文件中指定 read-me.ts。但是,由于您当前在 .npmignore 中指定了 *.ts,因此实际上您也没有必要另外指定 read-me.ts

  2. 或者,如果那不可能考虑:

    • postpack 脚本添加到 package.json 的脚本部分。例如:

      "scripts": {
        "postpack": "node ./fix-it.js",
        ...
      },
      
    • 然后在fix-it.js中利用node-tar包来:

      1. 解压缩压缩包 (.tgz)。
      2. 删除不需要的文件,即 readme.ts
      3. 重新打包以创建新的 tarball (.tgz)。
    • 发布包的步骤变为:

      1. 运行 npm pack

        postpack 脚本随后会自动生成不含不需要文件的新 .tgz 文件。

      2. 运行 npm publish ./path/to/mypackage.tgz