使用 TypeScript 编写代码
既然我们需要写多份文件,然后再发布到 npm 包,不如只写一份 typescript 文件
然后其他的格式 (cjs/esm),还有 d.ts 产物都自动生成,这不是就非常方便吗?
改造项目
安装 typescript 以及完成初始化创建 tsconfig.json
npm i -D typescript # 安装 typescript
npx tsc --init # 创建 tsconfig.json添加 src 目录,在里面创建 index.ts 文件
export function sayHello() {
const message = 'hello world typescript'
console.log(message)
return message
}
console.log(`load package icebreaker-npm-basic-package`)调整 tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"rootDir": "./src",
"module": "ESNext",
"moduleResolution": "bundler",
"resolveJsonModule": true, // 支持 import json
"strict": true, // 严格模式
"declaration": true, // 生成 dts
"declarationMap": true, // dts 的 sourcemap
"outDir": "./dist", // 生成 dts 的目录
"sourceMap": true, // 生成 sourcemap
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true
},
"include": ["src"]
}更多的配置 https://www.typescriptlang.org/tsconfig/
创建 cjs 和 esm 各自格式的 tsconfig.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "ESNext",
"outDir": "./dist/esm"
}
}{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "node10",
"outDir": "./dist/cjs"
}
}开始编译
在 package.json 的 scripts 中添加脚本
{
"build:cjs": "tsc --project tsconfig.cjs.json && node rename-ext.js dist/cjs .js .cjs && node rename-ext.js dist/cjs .js.map .cjs.map",
"build:esm": "tsc --project tsconfig.esm.json",
"build": "npm run build:cjs && npm run build:esm"
}为什么这里还需要执行 rename-ext? 因为你安装使用一个 npm 包的时候,默认情况下会使用 package.json 中的 type 字段去决定这个包 js 代码模块加载器
通常 nodejs 中会存在 2 个模块加载器:
假如你声明了 "type": "module",那么 nodejs 会使用 ESM 模块加载器,去加载这个包下面的所有 .js
反之,则使用 CJS 模块加载器,去加载这个包下面的所有 .js
但是有 2 个后缀是特例,.cjs 和 .mjs , 他们在 js 前面加了 c 和 m 代表指定 cjs/esm 模块加载器,去加载这个 js 代码
而我们这个包,已经被声明了 "type": "module",所以是无法直接运行后缀是 .js 的 cjs 文件的,必须把后缀从 .js 转变为 .cjs
更改 package.json 中模块入口点
{
"name": "icebreaker-npm-basic-package",
"type": "module",
"exports": {
".": {
"import": {
"types": "./dist/esm/index.d.ts",
"default": "./dist/esm/index.js"
},
"require": {
"types": "./dist/cjs/index.d.ts",
"default": "./dist/cjs/index.cjs"
}
}
},
"files": [
"dist"
]
}给不同的引入方式,设置不同的模块入口,和不同的类型提示。
同时也要注意这里我们添加了 files 字段,因为此时 src 目录下的源代码是不需要发布到 npmjs 上去的
你也可以通过执行 npm pack --dry-run 查看当前哪些文件会在发布的时候,被上传到 npmjs 上去
调试项目
利用 sourcemap 调试项目
source map(源码映射) 是一种用来 把编译/打包/压缩后的代码映射回原始代码 的技术
它是用来解决 生成的代码和原始代码不一样, 无法直接调试源代码,这样一个问题。
使用方式,在打开 sourcemap 选项后,生成对应的 sourcemap 文件,然后就可以在 ts 代码中打上断点,直接调试源代码了。
直接运行 typescript 调试项目
过去我们使用 ts-node 来直接运行 ts,随着时代的发展,ts-node 已经逐渐被 tsx 所取代
当然市面上直接转译运行 typescript 的工具还是非常多的,比如 tsx 和 bundle-require 都是基于 esbuild
jiti 这种基于 babel 的,还有 swc-node 这种基于 swc 的, @oxc-node/core 这种基于 oxc 的
当然,在不使用 emitDecoratorMetadata 这种 typescript 的装饰器的高级用法的情况下,使用 tsx 是比较好的选择
