utquidem
Version:
The meta-framework suite designed from scratch for frontend-focused modern web development.
402 lines (292 loc) • 10.5 kB
Markdown
---
sidebar_position: 9
---
# 开发工具库
本章将介绍如何使用 Modern.js,进行工具库项目的开发。本章对应的代码仓库地址:[独立项目场景](https://github.com/modern-js-dev/modern-js-examples/tree/main/quick-start/library-project) 、[Monorepo 场景](https://github.com/modern-js-dev/modern-js-examples/tree/main/quick-start/monorepo-library)。
:::info 注
工具库项目是指开发类似 [Lodash](https://lodash.com/)、JavaScript SDK 等可复用模块的项目。
:::
通过本章你可以了解到:
- 如何创建一个工具库项目。
- 如何在工具库项目中进行测试。
- 如何为工具库项目开启 Storybook 功能并使用它进行调试。
- 如何发布工具库项目。
- 如何将工具库项目迁移到 Monorepo 中。
## 环境准备
import EnvPrepare from '@site/docs/components/env-prepare.md';
<EnvPrepare />
## 创建项目
使用 `@modern-js/create` 创建新项目,运行命令如下:
```bash
npx @modern-js/create library-project
```
:::info 注
library-project 为创建的项目名。
:::
按照如下选择,生成项目:
```bash
? 请选择你想创建的工程类型 模块
? 请填写项目名称 library
? 请选择开发语言 TS
? 请选择包管理工具 pnpm
? 是否需要调整默认配置? 否
```
:::info 注
项目名称为 package.json 中的 `name` 字段值。
:::
### 编写工具函数逻辑
修改 `src/index.ts` 文件,增加工具库函数(以将字符串字母都转为大写为例):
```ts
export const upperCase = (s: string) => s.toUpperCase();
```
## 测试
修改默认测试文件 `tests/index.test.ts`:
```ts
import { upperCase } from '@/index';
describe('upperCase cases', () => {
test('upperCase', () => {
expect(upperCase('abc')).toBe('ABC');
});
});
```
执行 `test` 命令对工具函数进行测试,命令如下:
```bash
pnpm run test
```
## IDE 支持
import DevIDE from '@site/docs/components/dev-ide.md'
<DevIDE/>
## 启用 Storybook 调试
在项目根目录下,执行 `pnpm run new`,可以开启 Storybook 功能。
```bash
? 请选择你想要的操作 启用可选功能
? 启用可选功能 启用「Storybook」
```
启用成功后,会自动创建 `stories/` 目录,修改 `stories/index.stories.tsx` 文件内容:
```ts
import { useState } from 'react';
import { upperCase } from '@/index';
const Component = () => {
const [value, setValue] = useState('');
return (
<div>
<input value={value} onChange={e => setValue(e.target.value)} />
<div>result: {upperCase(value)}</div>
</div>
);
};
export const YourStory = () => <Component />;
export default {
title: 'Your Stories',
};
```
执行 `pnpm run dev` 调试运行结果,如下图所示:

## 产物模式
工具库项目支持配置不同的产物模式来满足不同的开发需求,产物模式通过 `output.packageMode` 配置进行。
该配置支持如下值:
- universal-js
- universal-js-lite
- browser-js
- browser-js-lite
- node-js
具体每个值对应的产物结构详见 [`output.packageMode`](/docs/apis/config/output/package-mode)。
对于当前场景,如果开发的工具库只支持 Node.js 环境,可以在项目 `modern.config.js` 中增加如下配置:
```js title="modern.config.js"
export default defineConfig({
output: {
packageMode: 'node-js',
},
});
```
执行 `pnpm run build` 之后,查看 `dist/` 目录产物,可以看到只生成 `node` 和 `modern` 两种类型的产物。
## 发布
开发完成后,可以对工具库进行发布。
发布分以下四个步骤:
1. 添加 changeset
执行 `pnpm run change`,根据提示选择升级的版本,并填写变更信息。

2. 升级对应版本号,并生成 changelog
执行 `pnpm run bump`,该命令会根据上述生成的 changeset 自动更新版本号和 CHANGELOG 信息,检查信息无误后提交。
3. 发布
执行 `pnpm run release`, 发布该工具包。
4. 推送 tags
发布完成之后执行 `git push --follow-tags`,推送当前发布对应生成的 git tag。
## 迁移到 Monorepo
在团队协作开发中,也会存在使用 Monorepo 进行项目开发的情况。接下来介绍如何将工具库项目迁移到 Monorepo 中。
### 创建 Monorepo
使用 `@modern-js/create` 创建 Monorepo 项目,运行命令如下:
```bash
npx @modern-js/create library-monorepo
```
:::info 注
library-monorepo 既是创建的 Monorepo 目录名称,又是项目的名称。
:::
按照如下选择,生成项目:
```bash
? 请选择你想创建的工程类型 Monorepo
? 请选择包管理工具 pnpm
```
生成的项目目录结构如下:
```bash
.
├── .changeset
│ └── config.json
├── .editorconfig
├── .gitignore
├── .npmrc
├── .nvmrc
├── .pnpmfile.cjs
├── .vscode
│ ├── extensions.json
│ └── settings.json
├── README.md
├── apps
│ └── .gitkeep
├── features
│ └── .gitkeep
├── monorepo.code-workspace
├── package.json
├── packages
│ └── .gitkeep
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
└── tsconfig.json
```
### 迁移工具库项目
这里只需要将之前创建的工具库项目复制到 `packages/` 目录下面,并删除 `.change`、`.vscode`、`.git` 目录及 `.editorconfig`、`.gitignore`、`.nvmrc`、`.npmrc` 文件。
```md
.
├── packages/
│ └── library-project
├── CHANGELOG.md
├── README.md
├── modern.config.js
├── package.json
├── src
│ ├── index.ts
│ └── modern-app-env.d.ts
├── stories
│ ├── index.stories.tsx
│ └── tsconfig.json
├── tests
│ ├── index.test.ts
│ ├── modern-app-env.d.ts
│ └── tsconfig.json
└── tsconfig.json
| ...
```
### 创建子项目
Modern.js 支持 Monorepo 工程方案的管理,我们可以在 Monorepo 项目下通过 `new` 命令创建不同类型的子项目。例如在刚刚创建的 Monorepo 项目根目录下执行 `pnpm run new`:
然后分别选择创建**应用**,**模块(内部)**项目。
```bash
? 请选择你想创建的工程类型 应用
? 请填写子项目名称 app
? 请填写子项目目录名称 app
? 请选择开发语言 TS
? 是否需要支持以下类型应用 不需要
? 是否需要调整默认配置? 否
```
```bash
? 请选择你想创建的工程类型 模块(内部)
? 请填写子项目名称 internal-lib
? 请填写子项目目录名称 internal-lib
? 请选择开发语言 TS
? 是否需要调整默认配置? 否
```
### 在应用项目中使用组件以及内部模块
接下来在 app 项目中通过以下方式把工具库项目加到依赖中:
```bash
cd ./apps/app
pnpm add library
```
此时可以观察到 app 项目的 `package.json` 内容更新如下:
```json
{
"dependencies": {
"@modern-js/runtime": "^1",
++ "library": "workspace:^0.1.1",
"react": "^17.0.1",
"react-dom": "^17.0.1"
}
}
```
接下来导入内部模块 `internal-lib`,由于内部模块并不需要进行发布,因此通过如下方式添加到项目中:
:::info 注
内部模块是指不需要发布到 npm 上的 package,它们只提供源码给应用项目使用,应用项目会将它们打包到构建产物中。
:::
```bash
cd ./apps/app
pnpm add internal-lib -D
```
此时可以观察到 app 项目的 `package.json` 内容更新如下:
```json
{
"devDependencies": {
"@modern-js/app-tools": "^1",
"@modern-js/plugin-jarvis": "^1",
"@types/jest": "^26.0.9",
"@types/node": "^14",
"@types/react": "^17",
"@types/react-dom": "^17",
++ "internal-lib": "workspace:^0.1.0",
"typescript": "^4"
},
}
```
此时在 app 项目下的 `src/App.tsx` 文件引用 `library` 的 `upperCase` 函数以及 `internal-lib` 模块,并使用它们:
```tsx title="App.tsx"
import { Switch, Route } from '@modern-js/runtime/router';
import { upperCase } from 'library';
import sayHelloWorld from 'internal-lib';
import './App.css';
const App = () => (
<Switch>
<Route exact={true} path="/">
<div className="container">
<main>{/* //... */}</main>
<div>{upperCase('abc')}</div>
<div>{sayHelloWorld()}</div>
<footer className="footer">
<a href="#" target="_blank" rel="noopener noreferrer">
Powered by Modern.JS
</a>
</footer>
</div>
</Route>
<Route path="*">
<div>404</div>
</Route>
</Switch>
);
export default App;
```
然后我们在 `apps/app` 目录下执行 `pnpm run dev` 命令,可以看到页面渲染效果如下:

### 批量发布
我们可以在 Monorepo 中再创建一个工具库项目(以将字符串字母都转为小写为例):
在 Monorepo 项目根目录下执行:
```bash
pnpm run new
```
```bash
? 请选择你想创建的工程类型 模块
? 请填写子项目名称 library2
? 请填写子项目目录名称 library2
? 请选择开发语言 TS
? 是否需要调整默认配置? 否
```
修改 `packages/library2/src/index.ts` 文件,增加工具库函数:
```ts
export const lowerCase = (s: string) => s.toLowerCase();
```
开发完成后可以在 Monorepo 的场景下对所有工具库做批量发布:
1. 添加 changeset
在 Monorepo 根目录执行 pnpm run change,根据提示选择发布的包(注意这里只选择工具库包名)和升级的版本,并填写变更信息。

2. 升级发布包对应版本号,并生成 changelog
执行 `pnpm run bump`,该命令会根据上述生成的 changeset 自动更新版本号和 CHANGELOG 信息,检查信息无误后提交。
3. 发布
执行 `pnpm run release`, 发布对应的多个工具包。
4. 推送 tags
发布完成之后执行 `git push --follow-tags`,推送当前发布对应生成的 git tag。