详解如何发布TypeScript编写的npm包

目录
  • 前言
  • 项目
  • 初始化项目
  • 构建库
  • 添加测试
  • 发布
  • 测试一下
  • 总结

前言

在这篇文章中,我们将使用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
  }
}

最重要的设置是这些:

库的主文件会位于src文件夹下,因此需要这么设置"files": ["src/index.ts"]

"target": "es2015" 确保我们的库支持现代平台,并且不会携带不必要的垫片。

"module": "es2015"。我们的模块将是一个标准的ES模块(默认是CommonJS)。ES模式在现代浏览器下没有任何问题;甚至Node从13版本开始就支持ES模式。

"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中拥有正确的元数据。

  • 确保main属性设置为打包的文件"main": "dist/index.js"
  • 为TypeScript用户添加"types": "dist/index.d.ts"
  • 因为我们的库会作为ES Module被使用,因此需要指定"type": "module"
  • 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]"))

结果非常棒!

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

总结

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

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

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

原文链接:www.strictmode.io/articles/bu…

以上就是详解如何发布TypeScript编写的npm包的详细内容,更多关于TypeScript npm包发布的资料请关注我们其它相关文章!

(0)

相关推荐

  • npm start运行项目过程package.json字段详解

    目录 正文 项目名称 项目版本号 项目介绍 执行命令 1 包配置安装npm install(npm i) 2 打包项目 npm run build 3 运行项目 npm run dev 存储库 关键词 bugs homepage 正文 在js项目运行时,通常输入npm start,即可运行,其运行过程如下: npm start首先会安装一系列的必要程序,这些程序依赖package.json中的内容, package.json里默认定义了项目名称.项目版本号.项目介绍.项目作者.执行命令.生产环境

  • 详解unplugin vue components不能识别组件自动导入类型pnpm

    目录 引言 效果 发现问题 问题效果 解决问题 刨根问底 解决方案 引言 unplugin-vue-components 是一款能帮助组件自动导入的库,简单点的说,你不需要使用import xx from 'xxx.vue' 这行语句也能实现导入的效果. <script setup lang="ts"> import ScreenAdpter from '@compontents/ScreenAdpter/index.vue' import Play from '@comp

  • 详解Vue3.0 + TypeScript + Vite初体验

    项目创建 npm: $ npm init vite-app <project-name> $ cd <project-name> $ npm install $ npm run dev or yarn: $ yarn create vite-app <project-name> $ cd <project-name> $ yarn $ yarn dev 项目结构 main.js 在个人想法上,我觉得createApp()是vue应用的实例,createApp

  • 详解如何用JavaScript编写一个单元测试

    目录 为什么要进行单元测试? 范围界定和编写单元测试 保持单元测试简短而简单 考虑正面和负面的测试用例 分解长而复杂的函数 避免网络和数据库连接 如何编写单元测试 创建一个新项目 实现一个类 配置和添加我们的第一个单元测试 添加更多单元测试 修复错误 最后 测试代码是确保代码稳定的第一步.能做到这一点的最佳方法之一就是使用单元测试,确保应用程序中的每个较小的功能都按应有的方式运行——尤其是当应用程序接收到极端或无效输入,甚至可能有害的输入时. 为什么要进行单元测试? 进行单元测试有许多不同的方法

  • 详解linux pwm驱动编写

    pwm方波可以用来控制很多的设备,比如它可以被用来控制电机.简单来说,就是单位时间内的方波越多,那么电机的转速就会越快:反之就越慢.通过这个特性,soc就可以轻松地利用pwm对外设进行自动控制.所以,今天的主题就是pwm驱动. 1.驱动目录 drivers/pwm 2.查看对应目录下的Kconfig config PWM_SAMSUNG tristate "Samsung PWM support" depends on PLAT_SAMSUNG || ARCH_EXYNOS help

  • 详解linux lcd驱动编写

    有些嵌入式设备是不需要lcd的,比如路由器.但是,还有些设备是需要lcd显示内容的,比如游戏机.测试仪.智能手表等等.所以,今天我们就看看lcd驱动在linux上是怎么进行的. 1.代码目录 drivers/video 2.查看video下的Makefile文件 # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_VGASTATE) += vgastate.o obj-$(CONFIG_HDMI) += hdmi.o obj-$(CONFIG_VT)

  • 详解linux dma驱动编写

    linux下面的驱动虽然什么样的情形都有,但是dma驱动却并不少见.dma可以有很多的好处,其中最重要的功能就是能够帮助我们将数据搬来搬去,这个时候cpu就由时间去做别的事情了,提高了设备效率. 1.dma驱动在什么地方 drivers/dma 2.如何看s3c的dma驱动,先看Kconfig config S3C24XX_DMAC bool "Samsung S3C24XX DMA support" depends on ARCH_S3C24XX || COMPILE_TEST se

  • 详解linux 摄像头驱动编写

    对于现代嵌入式设备,特别是手机来说,摄像头是很重要的一个设备.很多同学买手机,一看颜值,第二就看摄像头拍照如何.所以,从某个角度来说,摄像头是各个厂家主打的应用功能.那么,linux是如何支持摄像头的,我们可以来看一下? 1.代码目录地址 drivers/media 2.v4l2框架 目前linux上的camera都是按照v4l2框架来设计,它的地址位于drivers/media/v4l2-core 3.查看三星soc是如何支持camera的,可以查看drviers/media/platform

  • 详解在Vue.js编写更好的v-for循环的6种技巧

    在VueJS中,v-for循环是每个项目都会使用的东西,它允许您在模板代码中编写for循环. 在最基本的用法中,它们的用法如下. <ul> <li v-for='product in products'> {{ product.name }} </li> </ul> 但是,在本文中,我将介绍六种方法来使你的 v-for 代码更加精确,可预测和强大. 让我们开始吧. 1.始终在v-for循环中使用key 首先,我们将讨论大多数Vue开发人员已经知道的常见最佳做

  • 详解docker部署SpringBoot及替换jar包的方法

    关于docker的安装和使用,可以看看之前这两篇文章.docker kubernetes dashboard安装部署详细介绍和Docker如何使用link建立容器之间的连接.这篇文章主要介绍如何在docker上部署springboot项目.关于如何创建springboot项目可以看看这篇文章IDEA上面搭建一个SpringBoot的web-mvc项目遇到的问题 本文主要介绍docker部署springboot的三种方式,分别是:入门方式.jar包替换部署的方式和脚本部署方式,一步步来手把手教程.

  • 详解如何用typescript开发koa2的二三事

    前言 最近在写一个博客的项目,前端用的 vue+typescript+element-ui ,后台则选择了 koa2+typescript+mongoDB 的组合.写这篇博客的目的也是在写后台的过程遇到一些问题,查了很多资料才解决.于是权当总结,亦是记录,可以给别人做一个完整的参考. 基本信息 这里列出来的是会用到的一些配置信息,毕竟一直都在更新,可能这里说的以后某个版本就不支持了. "nodemon" : "^1.18.3", "ts-node"

  • 详解使用webpack打包编写一个vue-toast插件

    本文介绍了使用webpack打包编写一个vue插件,分享给大家.具体如下: 一.说明: 需求:创建一个toast插件 思路:利用vue组件创建模板,使用webpack打包生成插件再全局使用. # 项目目录: |_ package.json |_ webpack.config.js |_ .babelrc |_ dist |_ src |_ index.html |_ lib |_ index.js |_ vue-toast.vue 1.1 webpack基础 1.基础插件 - html-webp

随机推荐