在这篇文章中,我们将研究如何使用Vite bundler创建打字稿实用程序库。
为什么?
可能有很多理由构建库
- 在您的组织内共享代码
- 通过创建NPM软件包为开源社区做出贡献
- 要在monorepo中提取常用代码,以便多个应用可以重复使用MonorePo内的相同逻辑。
使用的技术/功能
我们要构建的库将具有以下功能。同样,这是我的一组工具,可以根据您的喜好随意更改它。
功能 | 使用的技术 |
---|---|
软件包管理器 | pnpm |
软件包bundler | Vite |
编程语言 | 打字稿 |
基本鳞片 | ES Lint |
代码格式 | 漂亮 |
预加入挂钩验证器 | 沙哑 |
linting仅上演文件 | 绒毛阶段 |
lint git commit主题 | commitlint |
先决条件
工具
您需要在计算机上正确安装以下内容。
PNPM安装
- 如果您在系统中安装了最新的v16.x或更大的节点版本,则使用以下CMD启用PNPM
corepack enable
corepack prepare pnpm@latest --activate
- 如果您在本地系统中使用较低版本的节点,请选中此页面以获取其他安装方法https://pnpm.io/installation
应用创建
- 让我们通过运行这些命令创建应用程序。
pnpm create vite <app-name> --template vanilla-ts
cd <app-name>
pnpm install && pnpm update
运行pnpm dev
并查看应用程序。
- 初始git(如果需要),并在readme.md中使用一些信息执行节点版本。
git init
npm pkg set engines.node=">=18.16.1" // Use the same node version you installed
echo "#Typescript utility library" > README.md
代码格式
我要使用Prettier格式化代码。格式化有助于我们为每个开发人员保持代码统一。
安装
让我们安装插件并设置一些默认值。在这里,我将单个报价设置为真,请根据您的喜好进行更新。
pnpm add -D prettier
echo '{\n "singleQuote": true\n}' > .prettierrc.json
echo -e ".husky\n.vscode\n.git\ncoverage\ndist\nnode_modules\npublic\npackage.json\npnpm-lock.yaml" > .prettierignore
我还获得了一些自由,包括我们将稍后将安装和使用的一些忽略文件中的一些包裹路径。
VS代码插件
- 如果使用VS代码,请导航到
Extensions
并搜索Prettier - Code formatter
并安装扩展名。
扩展链接:https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode
-
让我们更新工作空间以使用漂亮的默认格式格式,并在保存上自动格式化文件。
-
创建工作区设置JSON并使用以下内容进行更新。
mkdir .vscode && touch .vscode/settings.json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
}
- 现在打开VSCODE编辑器中的
src/main.ts
并保存。如果分号是自动创建的,则确认我们的自动格式正常。
覆盖
linter静态分析您的代码以快速发现问题。 ES Lint是覆盖JavaScript代码的最喜欢的工具。
埃什特
pnpm create @eslint/config
- ESLINT会要求您根据您的需求设置一组问题来设置Linter。 这是我为此项目选择的配置。
? How would you like to use ESLint? …
To check syntax only
❯ To check syntax and find problems
To check syntax, find problems, and enforce code style
? What type of modules does your project use? …
❯ JavaScript modules (import/export)
CommonJS (require/exports)
None of these
? Which framework does your project use? …
React
Vue.js
❯ None of these
Does your project use TypeScript? › No / Yes
- Yes
Where does your code run?
✔ Browser
Node
? What format do you want your config file to be in? …
❯ JavaScript
YAML
JSON
The config that you`ve selected requires the following dependencies:
@typescript-eslint/eslint-plugin@latest @typescript-eslint/parser@latest
? Would you like to install them now? › No / Yes
- Yes
? Which package manager do you want to use? …
npm
yarn
❯ pnpm
- 创建Eslintignore文件,以让Eslint知道要不格式的文件。
touch .eslintignore
echo -e ".husky\n.vscode\n.git\ncoverage\ndist\nnode_modules\n*.config.ts\n.eslintrc.cjs\npackage.json\npnpm-lock.yaml" > .eslintignore
将更漂亮的Eslint整合
衬里通常不仅包含代码质量规则,还包含风格规则。使用更漂亮时,大多数风格规则都是不必要的,但是更糟糕的是 - 它们可能与更漂亮的相冲突!
我们将使用更漂亮的代码格式问题,以及用于代码质量问题的Linter。
- 安装必要的插件
pnpm add -D eslint-config-prettier eslint-plugin-prettier
- 将
plugin:prettier/recommended
添加为的最后元素在Eslintrc.js中的扩展属性中
module.exports = {
extends: [..., 'plugin:prettier/recommended'],
}
有关此信息的更多信息:https://prettier.io/docs/en/integrating-with-linters.html
- 让我们创建用于在package.json文件中运行linter和更漂亮的脚本。
npm pkg set scripts.lint="eslint ."
npm pkg set scripts.format="prettier --write ."
- 运行
pnpm lint
cmd以运行ESLINT。如果抛出的话,则像下面一样的错误,那么我们的linter更漂亮的集成正在按预期工作。
要修复它,只需运行pnpm format
cmd并再次运行pnpm lint --fix
cmd即可。现在错误应该消失了。
预加入挂钩验证
即使我们添加了所有这些衬里和格式化机制来维护代码质量,我们也不能期望所有开发人员在每次推动代码时每次使用相同的编辑器并执行lint
和format
命令。
自动化我们需要某种预加入挂钩验证。那就是husky和lint-staged插件派上用场的地方,让我们安装并设置它们。
- 安装沙哑,commitlint和lint阶段的NPM软件包,并将其初始化,如下所示,
pnpm add -D @commitlint/cli @commitlint/config-conventional
echo -e "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.cjs
pnpm add -D husky lint-staged
npx husky install
npx husky add .husky/pre-commit "pnpm lint-staged"
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit ${1}'
npm pkg set scripts.prepare="husky install"
- 更新package.json文件并包括以下属性。这将在所有脚本文件上运行ESLINT,并在其他文件上更漂亮。
"lint-staged": {
"**/*.{js,ts,tsx}": [
"eslint --fix"
],
"**/*": "prettier --write --ignore-unknown"
},
绝对路径导入支持
我们经常在文件中移动以使其更有意义,当我们这样做时,如果我们不必更新导入语句,那就太好了。为此,
- 安装 @types/node npm软件包
pnpm add -D @types/node
- 创建vite.config.ts文件并像这样更新
touch vite.config.ts
import { defineConfig } from 'vite';
import { resolve } from 'path';
// https://vitejs.dev/config/
export default defineConfig({
resolve: { alias: { src: resolve('src/') } },
});
resolve
属性可帮助我们使用绝对导入路径而不是相对。
for ex:
import { add } from 'src/utils/arithmetic'
应用程序代码清理:
- 使用以下内容更新
main.ts
文件,
export const add = (a: number, b: number) => a + b;
export const sub = (a: number, b: number) => a - b;
- 删除示例文件
rm -rf src/style.css src/counter.ts
Vite库模式
vite默认情况下,用index.html作为条目文件以应用程序模式构建资产。但是我们希望我们的应用程序将我们的main.ts文件公开为输入文件,所以让我们更新vite配置以支持。
import { defineConfig } from 'vite';
import { resolve } from 'path';
// https://vitejs.dev/config/
export default defineConfig({
build: { lib: { entry: resolve(__dirname, 'src/main.ts'), formats: ['es'] } },
resolve: { alias: { src: resolve('src/') } },
});
本地开发服务器更新
我们可以利用本地开发服务器来验证我们的公用事业库。为此,让我们更新index.html文件,请注意,它不会暴露于外界。
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + TS</title>
</head>
<body>
<script type="module" src="/src/main.ts"></script>
<script type="module">
import { add, sub } from './src/main';
const addOutput = document.getElementById('addOutput');
const subOutput = document.getElementById('subOutput');
const input1 = document.getElementById('input1');
const input2 = document.getElementById('input2');
const getNumber = (element) => parseInt(element?.value);
const eventHandler = () => {
const firstVal = getNumber(input1);
const secondVal = getNumber(input2);
if (addOutput && subOutput) {
addOutput.innerText = add(firstVal, secondVal).toString();
subOutput.innerText = sub(firstVal, secondVal).toString();
}
};
eventHandler();
input1?.addEventListener('change', eventHandler);
input2?.addEventListener('change', eventHandler);
</script>
<input id="input1" type="number" value="4" />
<input id="input2" type="number" value="3" />
<p>Sum of two numbers = <span id="addOutput"></span></p>
<p>Diff of two numbers = <span id="subOutput"></span></p>
</body>
</html>
运行开发服务器,您应该能够看到行动中的库方法。
单位测试
我们将使用最流行的单元测试框架Jest来编写我们的单元测试。
- 安装必要的软件包
pnpm add -D jest @types/jest ts-jest ts-node
软件包 | 目的 |
---|---|
是 td> | 测试跑步者 |
TS-IS | 用于在打字稿支持的应用程序中开玩笑。 |
TS节点 | 用于在TS扩展中创建开玩笑的配置文件 |
@types/jest | 开玩笑的类型库 |
- 创建
src/setupTests.ts
文件并使用以下内容更新。
touch src/setupTests.ts
beforeAll(() => {
// Add your global beforeAll logics
});
beforeEach(() => {
// Add your globalbeforeEach logics
});
afterAll(() => {
// Add your global afterAll logics
});
afterEach(() => {
// Add your global afterEach logics
});
- 创建jest.config.ts文件,并使用下面的配置更新。
touch jest.config.ts
export default {
preset: 'ts-jest',
testEnvironment: 'node',
moduleNameMapper: {
'^src/(.*)$': '<rootDir>/src/$1',
},
setupFilesAfterEnv: ['<rootDir>/src/setupTests.ts'],
modulePathIgnorePatterns: ['./dist/'],
coveragePathIgnorePatterns: [],
collectCoverageFrom: ['./src/**/*.ts', '!./src/**/*.test.ts'],
coverageThreshold: {
global: {
branches: 100,
functions: 100,
lines: 100,
statements: 100,
},
},
};
- 创建jest.ci-config.ts文件,并使用下面的配置更新。
touch jest.ci-config.ts
import config from './jest.config';
export default {
...config,
coverageThreshold: {},
};
- 为主组件创建一个测试文件,然后像以下
touch src/main.test.ts
import { add, sub } from './main';
describe('Utility | Main', () => {
it('add - should add the given two numbers', async () => {
expect(add(4, 2)).toEqual(6);
});
it('sub - should subtract the given two numbers', async () => {
expect(sub(4, 2)).toEqual(2);
});
});
- 更新用于运行测试的软件包脚本
npm pkg set scripts.test="jest"
npm pkg set scripts.test:coverage="jest --coverage"
npm pkg set scripts.test:ci="jest --coverage --config='./jest.ci-config.ts'"
- 运行测试
pnpm test
- 运行特定的测试使用-t param。
pnpm test -- -t "add"
样品回购
该系列的代码托管在github here中。
请看一下GitHub回购,让我知道您的反馈,在评论部分中查询。