在本文中,我们将详细探讨如何从零开始搭建一个使用 TypeScript 的 JavaScript 包,涵盖从环境配置到发布的整个过程。通过这一系列的步骤,你将能够理解并实践如何构建一个现代化的前端库或应用。
一、初始准备和技术选型
在开始项目之前,我们首先需要明确包的功能目的和技术选型。此外,选择合适的工具也是成功的关键。本项目中,我们将使用 TypeScript 作为开发语言,配合 Rollup 作为构建工具来处理模块打包。
二. 开发环境详解
首先需要明确此包的作用,以及技术栈,然后需要哪些工具。通常一个包的简单全生命周期是这样的。
2.1 快速版
-
初始化项目:使用
pnpm
进行初始化,生成基本的package.json
文件。 -
配置构建工具:选择 Rollup,并安装必要的插件如
@rollup/plugin-typescript
和@rollup/plugin-node-resolve
等,确保 TypeScript 文件能被正确处理。 -
多格式支持:配置 Rollup 以输出 CommonJS、ES Module 和 UMD 格式,满足不同使用场景的需求。
-
性能优化:引入
@rollup/plugin-terser
和@rollup/plugin-swc
以优化输出结果,提高编译效率。 -
Prettier:配置代码格式化和校验工具,保持代码风格一致性。
-
Commit 规范:通过
commitlint
和husky
强制执行提交信息规范,以便自动生成 changelog。
2.2 详细版
2.2.1 初始化
首先这是一个纯js的包,这里选择rollup作为一个构建工具,技术栈为typescript,lint工具使用prettier来格式化和规范代码格式,首先初始化一个包,这里我选择用pnpm来作为包管理工具
pnpm init
然后生成一个默认的 package.json
{
"name": "npm",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
这是一个默认的配置,然后我们用rollup作为构建工具,所以此处我们需要配置rollup和ts开发环境
pnpm install -D @rollup/plugin-node-resolve @rollup/plugin-commonjs rollup @rollup/plugin-terser @rollup/plugin-typescript typescript @types/node
相关依赖完成以后需要配置一下tsconfig,如果全局安装过ts的话,可以直接执行下面的命令,就可以生成默认配置,详细配置可以参考官方文档。
tsc --init 如果没就 npx tsc --init
由于我们需要对现代js代码进行编译,所以需要安装类似babel的插件,这里我们使用swc来编译,据说很快,试一试。
pnpm install @rollup/plugin-swc -D
2.2.2 构建配置
在package.json
中配置不同规范下相关导入的声明
"main": "./dist/index.js",
"module": "./dist/index.esm.js",
"umd": "./dist/index.umd.js",
"types": "./dist/types/index.d.ts",
"type": "module",
然后配置rollup的配置文件
// rollup.config.js
import typescript from "@rollup/plugin-typescript"; // 解析ts的插件
import commonjs from "@rollup/plugin-commonjs"; // 转换cjs为esm,因为rollup默认只支持esm
import resolvejs from "@rollup/plugin-node-resolve"; // 让rollup找到外部模块
import teser from "@rollup/plugin-terser"; // 压缩,格式化,优化
import pkg from "./package.json" assert { type: "json" };
import swc from "@rollup/plugin-swc"; // 类似babel编译现代js代码,兼容低版本
import os from "os";
const env = process.env.NODE_ENV; // 当前运行环境,可通过 cross-env 命令行设置
const { name } = pkg;
const config = {
input: "src/main.ts",
// 输出三种格式commonjs,esmodule,umd
output: [
{
file: pkg.main,
format: "cjs",
},
{
file: pkg.module,
format: "es",
},
{
// umd 导出文件的全局变量
name,
file: pkg.umd,
format: "umd",
},
],
plugins: [typescript(), commonjs(), resolvejs()],
};
// 如果是生产环境就增加压缩和混淆,使用多线程打包
if (env === "production") {
config.plugins.push(
...[
teser({
compress: true,
maxWorkers: os.cpus().length,
mangle: {
toplevel: true,
},
}),
// 此处使用swc编译,比babel快的多,据说大型项目有bug,不过我这个小项目可以用
swc({
include: ['src/*.ts'],
exclude: ['node_modules'],
swc: {
jsc: {
parser: {
syntax: 'typescript'
},
target: 'es3'
}
}
}),
]
);
}
export default config;
在package.json
中配置build和dev命令,用于生产和开发环境,这里还需要安装两个包
pnpm install rimraf crosss-env -D
"build": "rimraf dist && cross-env NODE_ENV=production rollup -c rollup.config.js",
"dev": "rimraf dist && rollup -c -w",
2.2.3 配置代码规范和提交规范
prettier: 规范代码格式 commitlint: 规范提交信息,第二为了自动生成changelog
pnpm add prettier -D
然后创建一个.pretterrc文件
{
"semi": false, // 是否要分号
"tabWidth": 2, //缩进长度
"singleQuote": true, // 单引号
"printWidth": 80, // 单行长度
"trailingComma": "none", // 多行时不打印尾随逗号
"arrowParens": "always" // 箭头函数的括号
}
然后在package.json中新增几个scripts
"lint": "prettier ./src ./__tests__ --check ",
"fix": "prettier ./src ./__tests__ --write "
然后我们希望在提交的时候能够对提交的自动统一格式化,我们配置一个 lint-staged
pnpm add lint-staged -D
在package.json中加入,并且增加一条script, "lint-staged": "lint-staged"
"lint-staged": {
"*.{ts,js}": [
"prettier --write"
]
}
这里我们用到githooks来在特定阶段触发一些事件,所以我们就用到 husky
pnpm install husky -D
并且增加一条script, "prepare": "husky"
,然后npm run prepare会在.git目录下生成一个.husky的文件,此时我们添加一个勾子脚本.
echo "npm run lint-staged > .husky/pre-commit" // mac上是这样的,window我不知道咋创建,我手动创建的
此时就会看到在 .husky
中会有同一个文件 pre-commit
文件,到此就已经完成了prettier和提交的时候自动prettier.
接下来配置一下,commitlint和自动生成changelog.
pnpm install @commitlint/cli @commitlint/config-conventional -D
然后新增一个githook和一个commitlint.config.js
echo "npx --no -- commitlint --edit $1 > .husky/commit-msg"
echo "module.exports = { extends: ['@commitlint/config-conventional'] } > commitlint.config.cjs"
到这里,我们应该完成了开发阶段的一些配置。
这时候我们可以测试一下提交可以看到只能按照规范来填写commit信息。
除此以外,我们还可以借助commitizen
这个工具来提交代码。
pnpm install commitizen cz-conventional-changelog -D
然后在package.json
中配置一下path信息和增加一条命令。
"commit": " git add . && git-cz"
"config": {
"commitizen": {
"path": "cz-conventional-changelog"
}
},
然后我们就可以通过npm run commit
的命令来提交了。
2.2.4 开发启动
新建一个src
目录新建一个入口文件main.ts,和index.html, 执行npm run dev
,这时候就启动成功了。
// main.ts
class A {
name: string
constructor(name: string) {
this.name = name
}
}
class B extends A {
age: number
constructor(age: number, name: string) {
super(name)
this.age = age
}
}
export default B
HTML内容,打开html就看了一看到i的内容是一个对象{age: 12, name: '小明'}
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script ></script>
</head>
<body>
</body>
<script type="module">
import B from './dist/index.esm.js'
const i = new B(12, '小明')
console.log(i)
</script>
</html>
看编译后的代码,已经被转换成es3了。
三. 测试和验证
由于测试是纯js函数,这里我采用Jest来做测试框架,因为我用过,当然你也可以选择其他的。
安装相关的包
pnpm install --save-dev jest ts-jest @types/jest
编写jest.config.js
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node'
}
增加命令"test": "jest -c jest.config.cjs --no-cache"
然后在root目录下新增一个tests文件夹。
通过npx jest config:init
, 来初始化生成jest.config.js
, 需要把js改成cjs。
默认配置中新增一个配置rootDir
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
rootDir: 'tests'
}
这时候我们添加一个测试脚本,index.spec.ts
.
import { numberPlus } from '../src/main'
test('adds 1 + 2 to equal 3', () => {
expect(numberPlus(1, 2)).toBe(3)
})
然后执行脚本npm run test
就可以看到测试用例执行成功了,到此我们的测试就配置完成了。
四. 发布和维护
4.1 版本管理和发布
主要分为以下几个步骤。
- 测试
- 编译build
- 版本管理
- changeLog的生成
- npm发布
changeLog和版本管理,我们用standard-version
来完成, standard-version
可以自动管理版本和生成changeLog并且提交。
pnpm install standard-version -D
然后新增2个script命令.
"release": "npm run test && npm run build && standard-version",
"publishnpm": "npm publish && git push --follow-tags origin main"
4.2 npm 发布/持续集成
首先需要一个npm的账号,然后npm adduser
通过网页端的授权,授权完成后执行npm run publishnpm
即可以发布到npm
顺便打上tag
.
看我这里已经发布成功了。
tag也有了。
到此就完成了一个ts包的发布了,然后还有些工作还可以补充,比如库的声明文件没有生成,这个可以去看看ts的文档学习一下,我这里就不写了,还有可以通过gitaction来完成项目的build和publish,有兴趣的可以自行学习添加一下。
仓库地址,如果学到了点个star