如何用 TypeScript 来开发 npm 包

首先问一下自己,为什么要用 TypeScript 来开发 npm 包?

用 TypeScript 开发npm包,需要配置一堆东西,比如开发过程中需要使用ts-node或者esno这样的工具把 TS 转化为 JS后再执行,开发完成后也需要构建等等。

如果我的包比较简单,我直接用 JavaScript 不香吗?

之所以,建议使用 TypeScript 来开发 npm 包,首先最重要的一点,一定是对开发者与使用者的类型提示

无论你的包里是只有一个函数的导出,还是有零零总总大几十个函数,类型的存在都能让这个包的使用更加友好。如果你是包的使用者,你是更想"哦,这里类型报错了,我的入参类型不太对",还是"为什么这个地方一直报错呢...可恶啊,查了一通,原来是我的变量到这里的时候类型不对了"?

即使你是在 JavaScript 工程中引用 TypeScript 编写的包,只要配置了 TypeScript 开发环境,也一样能够享受到这些基于类型的辅助能力。

另外一个重要的原因则是,如果你使用了高阶的语法,此时你需要引入 Babel / Rollup 这样的编译工具来做一次语法降级,Babel 的配置略显繁琐,简单场景上 Rollup 又像高射炮打蚊子。

这个时候 TypeScript 自带的语法降级能力就香起来了:只需要简单的几行配置就够用,还带类型,还带简单的 Lint 能力...何乐而不为?

因此,本文将会从头演示如何基于 TypeScript 来编写 + 发布一个 npm 包,包括环境搭建、本地调试、编译配置以及发布等等。

本文内容分为开发阶段和打包阶段。

本地开发阶段

由于 NodeJs 不能直接执行 TS 文件,我们需要 esno 的帮助,它是一个基于 ESBuild 的执行工具,借助 ESBuild 闪电般的速度,首先编译 TS 文件然后再使用 Node 执行。

你可能会想,ESBuild 不支持类型检查吧?不用担心,VS Code 本地有类型检查,加上发布前仍然会使用 tsc 进行编译。

js 复制代码
$ npm i esno -D
$ npx esno ./src/index.ts

在日常开发时,往往会需要频繁地修改然后执行,不断查看代码的输出和表现。

在日常的网页开发中,Webpack Dev Server 已经帮我们很好地处理了这个需要,使用 JavaScript 开发 NodeJs 应用时你可能也习惯了 nodemon,那么 TypeScript 下应该怎么做?

首先,这里也是使用 nodemon,一般习惯的 nodemon index.js 只是它最基本的用法,你其实可以自由地配置文件的执行程序,以及监听哪些文件等等,在 package.json 中进行配置:

js 复制代码
{
  "nodemonConfig": {
    "delay": 500,
    "env": {
      "NODE_ENV": "development"
    },
    "execMap": {
      "ts": "esno",
      "js": "node"
    },
    "ignore": ["node_modules"],
    "verbose": true
  },
}

这样一来,在执行 nodemon index.ts 时,就能够自动使用 esno 来执行 ts 文件了。

编译配置方面,可以参考优雅的配置你的 tsconfig.json这篇文章,以模板中的配置文件为例:

js 复制代码
{
  "compilerOptions": {
    "target": "ES2018",
    "module": "ES2015",
    "types": [],
    "outDir": "dist", // 输出到 dist 目录下
    "skipLibCheck": true,
    "moduleResolution": "node",
    "strictNullChecks": true, // 开启严格检查
    "declaration": true, // 输出声明文件
    "declarationDir": "dist/type", // 声明文件放置位置
    "strict": true,
    "noImplicitAny": true,
    "noImplicitReturns": true,
    "noUnusedParameters": false,
    "noUnusedLocals": false,
    "esModuleInterop": true, // ESM 与 CJS 相关,推荐开启来解决大部分问题
    "allowSyntheticDefaultImports": true, // ESM 与 CJS 相关,推荐开启来解决大部分问题
    "baseUrl": "."
  }
}

由于 npm 包需要手动指定入口,请确保 outDir 与 package.json 中的 main 指向是一致的

js 复制代码
// commonjs格式时入口文件
"main": "dist/index.umd.js",
// es格式时入口文件
"module": "dist/index.es.js",
// 声明文件入口
"types": "dist/types/index.d.ts",
// 这个参数是表面该包是es格式,这里的目的是为了引入rollup.config.js必须要加的
"type": "module"

rollup 打包

首先看一下rollup.config.js配置:

js 复制代码
import { nodeResolve } from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import typescript from 'rollup-plugin-typescript2'
import json from '@rollup/plugin-json'

export default {
  input: 'src/index.ts',
  output: [
    {
      file: './dist/index.umd.js',
      name: 'CrowllerTs',
      format: 'umd'
    },
    {
      file: './dist/index.es.js',
      format: 'es'
    }
  ],
  plugins: [
    json(),
    typescript({ useTsconfigDeclarationDir: true }),
    commonjs(),
    nodeResolve()
  ]
}
  • @rollup/plugin-node-resolve: 将编写的源码与源码依赖的第三方库进行合并,作为一个完整的包对外输出,不需要用户再去下载第三方库。
  • @rollup/plugin-commonjs:rollup 主要是用来打包es格式书写的模块,如果要打包commonjs格式书写的模块,需要使用这个插件。
  • rollup-plugin-typescript2: rollup-plugin-typescript2 插件在编译时底层也是调用typescript 把 ts 编译成 js,它也会使用tsconfig.json的配置。
  • @rollup/plugin-json: 对于json文件,比如 package.json,我们无法直接引用需要安装json插件。

最后在package.json中加上打包命令:

js 复制代码
"scripts": {
    "build": "rollup -c"
}

这里最重要的是使用rollup-plugin-typescript2来让rollup能够打包TypeScript代码。

另外,tsconfig.json中的"target": "ES5"可以帮我们将代码打包为ES5的语法,所以这里不用再使用babel来进行语法转换了。

关于 rollup 这一部分可以参考网上的资料,这里就不做详细介绍了。

相关推荐
王解20 小时前
Jest项目实战(2): 项目开发与测试
前端·javascript·react.js·arcgis·typescript·单元测试
鸿蒙开天组●1 天前
鸿蒙进阶篇-网格布局 Grid/GridItem(二)
前端·华为·typescript·harmonyos·grid·mate70
zhizhiqiuya1 天前
第二章 TypeScript 函数详解
前端·javascript·typescript
初遇你时动了情2 天前
react 18 react-router-dom V6 路由传参的几种方式
react.js·typescript·react-router
王解2 天前
Jest进阶知识:深入测试 React Hooks-确保自定义逻辑的可靠性
前端·javascript·react.js·typescript·单元测试·前端框架
_jiang2 天前
nestjs 入门实战最强篇
redis·typescript·nestjs
清清ww2 天前
【TS】九天学会TS语法---计划篇
前端·typescript
努力变厉害的小超超3 天前
TypeScript中的类型注解、Interface接口、泛型
javascript·typescript
王解3 天前
Jest进阶知识:整合 TypeScript - 提升单元测试的类型安全与可靠性
前端·javascript·typescript·单元测试
Vesper634 天前
【TS】TypeScript 类型定义之联合类型(union types)和交叉类型(intersection types)
linux·ubuntu·typescript