深入学习 TypeScript
请支持本书:购买捐赠
(广告,请勿屏蔽。)

8 通过 TypeScript 创建基于 CommonJS 的 npm 包



本章介绍如何使用 TypeScript 为 npm 包管理器创建基于 CommonJS 模块格式的包。

  GitHub 仓库:ts-demo-npm-cjs

在本章中,我们将探索 代码仓库 ts-demo-npm-cjs,它可以在 GitHub 上下载。(我特意没有将其作为包发布到 npm。)

8.1 所需知识

您应该大致熟悉

8.2 限制

在本章中,我们使用 TypeScript 当前最支持的内容

特别是在 Node.js 上,TypeScript 当前并不真正支持 ECMAScript 模块和 .js 以外的文件扩展名。

8.3 代码仓库 ts-demo-npm-cjs

这就是代码仓库 ts-demo-npm-cjs 的结构

ts-demo-npm-cjs/
  .gitignore
  .npmignore
  dist/   (created on demand)
  package.json
  ts/
    src/
      index.ts
    test/
      index_test.ts
  tsconfig.json

除了包的 package.json 之外,该仓库还包含

package.json 包含用于编译的脚本

这是放置两个 TypeScript 文件的编译结果的地方

ts/src/index.ts       --> dist/src/index.js
ts/test/index_test.ts --> dist/test/index_test.js

8.4 .gitignore

此文件列出了我们不想提交到 git 的目录

node_modules/
dist/

说明

8.5 .npmignore

当涉及到哪些文件应该和不应该上传到 npm 注册表时,我们与 git 的需求不同。因此,除了 .gitignore 之外,我们还需要文件 .npmignore

ts/

这两个区别是

请注意,npm 默认忽略目录 node_modules/

8.6 package.json

package.json 如下所示

{
  ···
  "type": "commonjs",
  "main": "./dist/src/index.js",
  "types": "./dist/src/index.d.ts",
  "scripts": {
    "clean": "shx rm -rf dist/*",
    "build": "tsc",
    "watch": "tsc --watch",
    "test": "mocha --ui qunit",
    "testall": "mocha --ui qunit dist/test",
    "prepack": "npm run clean && npm run build"
  },
  "// devDependencies": {
    "@types/node": "Needed for unit test assertions (assert.equal() etc.)",
    "shx": "Needed for development-time package.json scripts"
  },
  "devDependencies": {
    "@types/lodash": "···",
    "@types/mocha": "···",
    "@types/node": "···",
    "mocha": "···",
    "shx": "···"
  },
  "dependencies": {
    "lodash": "···"
  }
}

让我们来看看这些属性

接下来的两个小节涵盖了其余的属性。

8.6.1 脚本

属性 scripts 定义了可以通过 npm run 调用的各种命令。例如,脚本 clean 通过 npm run clean 调用。之前的 package.json 包含以下脚本

请注意,当我们使用 IDE 时,我们不需要脚本 buildwatch,因为我们可以让 IDE 构建工件。但是脚本 prepack 需要它们。

8.6.2 dependenciesdevDependencies

dependencies 应该只包含导入包时需要的包。这排除了用于运行测试等的包。

名称以 @types/ 开头的包为没有类型定义的包提供 TypeScript 类型定义。没有前者,我们就不能使用后者。这些是正常的依赖项还是开发依赖项?这取决于

8.6.3 关于 package.json 的更多信息

8.7 tsconfig.json

{
  "compilerOptions": {
    "rootDir": "ts",
    "outDir": "dist",
    "target": "es2019",
    "lib": [
      "es2019"
    ],
    "module": "commonjs",
    "esModuleInterop": true,
    "strict": true,
    "declaration": true,
    "sourceMap": true
  }
}

其余选项由 tsconfig.json 的官方文档 解释。

8.8 TypeScript 代码

8.8.1 index.ts

此文件提供了包的实际功能

import endsWith from 'lodash/endsWith';

export function removeSuffix(str: string, suffix: string) {
  if (!endsWith(str, suffix)) {
    throw new Error(JSON.stringify(suffix)} + ' is not a suffix of ' +
      JSON.stringify(str));
  }
  return str.slice(0, -suffix.length);
}

它使用 库 Lodash 的函数 endsWith()。这就是为什么 Lodash 是一个正常的依赖项——它在运行时是必需的。

8.8.2 index_test.ts

此文件包含 index.ts 的单元测试

import { strict as assert } from 'assert';
import { removeSuffix } from '../src/index';

test('removeSuffix()', () => {
  assert.equal(
    removeSuffix('myfile.txt', '.txt'),
    'myfile');
  assert.throws(() => removeSuffix('myfile.txt', 'abc'));
});

我们可以像这样运行测试

npm t dist/test/index_test.js

如您所见,我们正在运行测试的编译版本(在目录 dist/ 中),而不是 TypeScript 代码。

有关单元测试框架 Mocha 的更多信息,请参阅 其主页