如何发布一个 TypeScript 编写的 npm 包

如何,发布,一个,typescript,编写,npm · 浏览次数 : 735

小编点评

**本文内容摘要** 本文介绍了如何创建和发布一个npm包。包括以下关键步骤: * 创建 package.json文件 *设置文件内容 *设置类型 *运行npm install命令 *运行npm publish命令 **主要内容** * package.json文件 *文件内容 *类型 *运行npm install命令 *运行npm publish命令 *创建dist目录下index.js和index.d.ts文件 *使用.npmignore列出所有我们不想发布的文件 *使用package.json中的files字段指定我们想要包含的文件 **其他内容** *本文介绍了如何创建和发布一个npm包。 *本文介绍了如何设置文件内容。 *本文介绍了如何设置类型。 *本文介绍了如何运行npm install命令。 *本文介绍了如何运行npm publish命令。 *本文介绍了如何创建dist目录下index.js和index.d.ts文件。 *本文介绍了如何使用.npmignore列出所有我们不想发布的文件。 *本文介绍了如何使用package.json中的files字段指定我们想要包含的文件。 *本文介绍了如何使用.npmignore列出所有我们不想发布的文件。 *本文介绍了如何使用package.json中的files字段指定我们想要包含的文件。

正文

前言

在这篇文章中,我们将使用TypeScript和Jest从头开始构建和发布一个NPM包。

我们将初始化一个项目,设置TypeScript,用Jest编写测试,并将其发布到NPM。

项目

我们的库称为digx。它允许从嵌套对象中根据路径找出值,类似于lodash中的get函数。

比如说:

const source = { my: { nested: [1, 2, 3] } }
digx(source, "my.nested[1]") //=> 2

就本文而言,只要它是简洁的和可测试的,它做什么并不那么重要。

npm包可以在这里找到。GitHub仓库地址在这里

初始化项目

让我们从创建空目录并初始化它开始。

mkdir digx
cd digx
npm init --yes

npm init --yes命令将为你创建package.json文件,并填充一些默认值。

让我们也在同一文件夹中设置一个git仓库。

git init
echo "node_modules" >> .gitignore
echo "dist" >> .gitignore
git add .
git commit -m "initial"

构建库

这里会用到TypeScript,我们来安装它。

npm i -D typescript

使用下面的配置创建tsconfig.json文件:

{
  "files": ["src/index.ts"],
  "compilerOptions": {
    "target": "es2015",
    "module": "es2015",
    "declaration": true,
    "outDir": "./dist",
    "noEmit": false,
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "alwaysStrict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitOverride": true,
    "noPropertyAccessFromIndexSignature": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true
  }
}

最重要的设置是这些:

  1. 库的主文件会位于src文件夹下,因此需要这么设置"files": ["src/index.ts"]
  2. "target": "es2015" 确保我们的库支持现代平台,并且不会携带不必要的垫片。
  3. "module": "es2015"。我们的模块将是一个标准的ES模块(默认是CommonJS)。ES模式在现代浏览器下没有任何问题;甚至Node从13版本开始就支持ES模式。
  4. "declaration": true - 因为我们想要自动生成d.ts声明文件。我们的TypeScript用户将需要这些声明文件。

其他大部分选项只是各种可选的TypeScript检查,我更喜欢开启这些检查。

打开package.json,更新scripts的内容:

"scripts": {
  "build": "tsc"
}

现在我们可以用npm run build来运行构建...这样会失败的,因为我们还没有任何可以构建的代码。

我们从另一端开始。

添加测试

作为一名负责任的开发,我们将从测试开始。我们将使用jest,因为它简单且好用。

npm i -D jest @types/jest ts-jest

ts-jest包是Jest理解TypeScript所需要的。另一个选择是使用babel,这将需要更多的配置和额外的模块。我们就保持简洁,采用ts-jest

使用如下命令初始化jest配置文件:

./node_modules/.bin/jest --init

一路狂按回车键就行,默认值就很好。

这会使用一些默认选项创建jest.config.js文件,并添加"test": "jest"脚本到package.json中。

打开jest.config.js,找到以preset开始的行,并更新为:

{
  // ...
  preset: "ts-jest",
  // ...
}

最后,创建src目录,以及测试文件src/digx.test.ts,填入如下代码:

import dg from "./index";

test("works with a shallow object", () => {
  expect(dg({ param: 1 }, "param")).toBe(1);
});

test("works with a shallow array", () => {
  expect(dg([1, 2, 3], "[2]")).toBe(3);
});

test("works with a shallow array when shouldThrow is true", () => {
  expect(dg([1, 2, 3], "[2]", true)).toBe(3);
});

test("works with a nested object", () => {
  const source = { param: [{}, { test: "A" }] };
  expect(dg(source, "param[1].test")).toBe("A");
});

test("returns undefined when source is null", () => {
  expect(dg(null, "param[1].test")).toBeUndefined();
});

test("returns undefined when path is wrong", () => {
  expect(dg({ param: [] }, "param[1].test")).toBeUndefined();
});

test("throws an exception when path is wrong and shouldThrow is true", () => {
  expect(() => dg({ param: [] }, "param[1].test", true)).toThrow();
});

test("works tranparently with Sets and Maps", () => {
  const source = new Map([
    ["param", new Set()],
    ["innerSet", new Set([new Map(), new Map([["innerKey", "value"]])])],
  ]);
  expect(dg(source, "innerSet[1].innerKey")).toBe("value");
});

这些单元测试让我们对正在构建的东西有一个直观的了解。

我们的模块导出一个单一函数,digx。它接收任意对象,字符串参数path,以及可选参数shouldThrow,该参数使得提供的路径在源对象的嵌套结构中不被允许时,抛出一个异常。

嵌套结构可以是对象和数组,也可以是Map和Set。

使用npm t运行测试,当然,不出意外会失败。

现在打开src/index.ts文件,并写入下面内容:

export default dig;

/**
 * A dig function that takes any object with a nested structure and a path,
 * and returns the value under that path or undefined when no value is found.
 *
 * @param {any}     source - A nested objects.
 * @param {string}  path - A path string, for example `my[1].test.field`
 * @param {boolean} [shouldThrow=false] - Optionally throw an exception when nothing found
 *
 */
function dig(source: any, path: string, shouldThrow: boolean = false) {
  if (source === null || source === undefined) {
    return undefined;
  }

  // split path: "param[3].test" => ["param", 3, "test"]
  const parts = splitPath(path);

  return parts.reduce((acc, el) => {
    if (acc === undefined) {
      if (shouldThrow) {
        throw new Error(`Could not dig the value using path: ${path}`);
      } else {
        return undefined;
      }
    }

    if (isNum(el)) {
      // array getter [3]
      const arrIndex = parseInt(el);
      if (acc instanceof Set) {
        return Array.from(acc)[arrIndex];
      } else {
        return acc[arrIndex];
      }
    } else {
      // object getter
      if (acc instanceof Map) {
        return acc.get(el);
      } else {
        return acc[el];
      }
    }
  }, source);
}

const ALL_DIGITS_REGEX = /^\d+$/;

function isNum(str: string) {
  return str.match(ALL_DIGITS_REGEX);
}

const PATH_SPLIT_REGEX = /\.|\]|\[/;

function splitPath(str: string) {
  return (
    str
      .split(PATH_SPLIT_REGEX)
      // remove empty strings
      .filter((x) => !!x)
  );
}

这个实现可以更好,但对我们来说重要的是,现在测试通过了。自己用npm t试试吧。

现在,如果运行npm run build,可以看到dist目录下会有两个文件,index.jsindex.d.ts

接下来就来发布吧。

发布

如果你还没有在npm上注册,就先注册

注册成功后,通过你的终端用npm login登录。

我们离发布我们的新包只有一步之遥。不过,还有几件事情需要处理。

首先,确保我们的package.json中拥有正确的元数据。

  1. 确保main属性设置为打包的文件"main": "dist/index.js"
  2. 为TypeScript用户添加"types": "dist/index.d.ts"
  3. 因为我们的库会作为ES Module被使用,因此需要指定"type": "module"
  4. namedescription也应填写。

接着,我们应该处理好我们希望发布的文件。我不觉得要发布任何配置文件,也不觉得要发布源文件和测试文件。

我们可以做的一件事是使用.npmignore,列出所有我们不想发布的文件。我更希望有一个"白名单",所以让我们使用package.json中的files字段来指定我们想要包含的文件。

{
  // ...
  "files": ["dist", "LICENSE", "README.md", "package.json"],
  // ...
}

终于,我们已经准备好发包了。

运行以下命令:

npm publish --dry-run

并确保只包括所需的文件。当一切准备就绪时,就可以运行:

npm publish

测试一下

让我们创建一个全新的项目并安装我们的模块。

npm install --save digx

现在,让我们写一个简单的程序来测试它。

import dg from "digx"

console.log(dg({ test: [1, 2, 3] }, "test[0]"))

结果非常棒!

digx_autocomplete.png

然后运行node index.js,你会看到屏幕上打印1

总结

我们从头开始创建并发布了一个简单的npm包。

我们的库提供了一个ESM模块,TypeScript的类型,使用jest覆盖测试用例。

你可能会认为,这其实一点都不难,的确如此。

以上就是本文的所有内容,如果对你有所帮助,欢迎收藏、点赞、转发~

与如何发布一个 TypeScript 编写的 npm 包相似的内容:

如何发布一个 TypeScript 编写的 npm 包

前言 在这篇文章中,我们将使用TypeScript和Jest从头开始构建和发布一个NPM包。 我们将初始化一个项目,设置TypeScript,用Jest编写测试,并将其发布到NPM。 项目 我们的库称为digx。它允许从嵌套对象中根据路径找出值,类似于lodash中的get函数。 比如说: cons

代码实例解读如何安全发布对象

摘要:在高并发环境下如何安全的发布对象实例。 本文分享自华为云社区《【高并发】如何安全的发布对象(含各种单例代码分析)》,作者:冰 河。 今天,为大家带来一篇有技术含量的文章,那就是在高并发环境下如何安全的发布对象实例。 发布对象:使一个对象能够被当前范围之外的代码所使用对象溢出:是一种错误的发布,

一键自动化博客发布工具,用过的人都说好(51cto篇)

51cto是一个优秀的博客平台,今天给大家讲解一下blog-auto-publishing-tools如何自动发布博客到51cto上。 当然在实现过程中有可能会遇到各种困难,不过不用担心,我们一个个来解决。 前提条件 前提条件当然是先下载 blog-auto-publishing-tools这个博客

Kafka为什么这么快?

Kafka 是一个基于发布-订阅模式的消息系统,它可以在多个生产者和消费者之间传递大量的数据。Kafka 的一个显著特点是它的高吞吐率,即每秒可以处理百万级别的消息。那么 Kafka 是如何实现这样高得性能呢?本文将从七个方面来分析 Kafka 的速度优势。 - 零拷贝技术 - 仅可追加日志结构 -

第131篇:如何上传一个npm包

好家伙, NPM的全称是Node Package Manager,是一个NodeJS包管理和分发工具,已经成为了非官方的发布Node模块(包)的标准。 NPM是世界上最大的软件注册表。 1.首先我们去npm官网注册一个账号 (证明你是人....) 2.在本地创建一个新文件夹 最好和你的包同名 3.改

如何编写一个健壮的 npm 包

比如老王我,用npm init新建一个包,改把改把,然后来个npm publish,so easy ✌️!Too young too naive, baby 👶!请容我讲述一些发布过程中踩过的坑。

吐血整理如何在Google Earth Engine上写循环 五个代码实例详细拆解

在这里同步一篇本人的原创文章。原文发布于2023年发布在知乎专栏,转移过来时略有修改。全文共计3万余字,希望帮助到GEE小白快速进阶。 引言 这篇文章主要解答GEE中.map()和.iterate()函数的用法。 首先解答一个疑问,为什么需要自己写循环?确实,GEE 为各种数据类型提供了无数常用的内

一键自动化博客发布工具,用过的人都说好(掘金篇)

终于要讲解我们亲爱的掘金了。掘金是一个非常不错的平台。所以很多朋友会把博客发布到掘金上。 发布到掘金要填写的内容也比较多。今天给大家介绍一下如何用blog-auto-publishing-tools这个工具自动把博客发布到掘金平台上去。 前提条件 前提条件当然是先下载 blog-auto-publi

DevOps |研发效能之环境、程序、配置、SQL变更管理

本文主要是讲如何建立有效的环境、程序、配置、SQL变更和管理平台。 ​几天前和一个朋友聊到环境、程序的配置变更,SQL变更和整个上线流程。之前我们在这块也做了很多,有做的好的也有做的一般的,借机都总结下来,希望对你有用。 通常情况下,我们最关注的也是最重要的部分是应用的变更,就是程序的部署上线发布这

抽丝剥茧:详述一次DevServer Proxy配置无效问题的细致排查过程

事情的起因是这样的,在一个已上线的项目中,其中一个包含登录和获取菜单的接口因响应时间较长,后端让我尝试未经服务转发的另一域名下的新接口,旧接口允许跨域请求,但新接口不允许本地访问(只允许发布测试/生产的域名访问)。 问题 那么问题来了,本地环境该如何成功访问到新的接口并验证业务功能是否生效呢? 尝试