本章篇幅较长,尬不多说,造轮子开始~~
1. 初始化项目 create-react-app + TS
npx create-react-app my-component-library --template typescript
参考:create-react-app.dev/docs/adding…
2. 支持编译 Sass
CRA 默认不支持 Sass 预处理器,需要安装 node-sass,
npm install node-sass --save
支持 sass 之后,接下来可以为组件库添加一些样式管理,比如定义基础组件库色板变量,
// 基础色板
$blue: #0d6efd !default;
$indigo: #6610f2 !default;
$purple: #6f42c1 !default;
$pink: #d63384 !default;
$red: #dc3545 !default;
$orange: #fd7e14 !default;
$yellow: #fadb14 !default;
$green: #52c41a !default;
$teal: #20c997 !default;
$cyan: #17a2b8 !default;
添加 reset 全局样式,可参考 normalize.css 库,它提供了跨浏览器的高度一致性。
3. 编写 Button 组件
下面简单列举开发组件几个常用的点,至于怎么开发出一个合格好用的组件,还需要日积月累、慢慢摸索~
- 组件
className属性一般支持btn, btn-lg, btn-primary等不同样式管理,推荐使用classnames插件进行样式名管理, 配置 classNames :
npm i classnames --save
npm install --save @types/classnames
-
通过
Button.defaultProps为添加props赋默认值 -
ButtonHTMLAttributes是button所有原生属性类型,可以通过定义自定义属性类型和button所有原生属性类型,让用户使用组件时获得更好的属性类型提示。
Button 组件参考实现 ⬇️
// Button.tsx
import React, { FC, ButtonHTMLAttributes, AnchorHTMLAttributes } from "react";
import classNames from "classnames";
export type ButtonSize = "lg" | "sm";
export type ButtonType = "primary" | "default" | "danger" | "link";
interface BaseButtonProps {
className?: string;
/**设置 Button 的禁用 */
disabled?: boolean;
/**设置 Button 的尺寸 */
size?: ButtonSize;
/**设置 Button 的类型 */
btnType?: ButtonType;
children: React.ReactNode;
href?: string;
}
// ButtonHTMLAttributes 是button所有原生属性类型
type NativeButtonProps = BaseButtonProps & ButtonHTMLAttributes<HTMLElement>;
// a 链接原生属性
type AnchorButtonProps = BaseButtonProps & AnchorHTMLAttributes<HTMLElement>;
// TS Utility Types : Partial 属性可选,并不是都有的
export type ButtonProps = Partial<NativeButtonProps & AnchorButtonProps>;
export const Button: FC<ButtonProps> = (props) => {
const {
btnType,
className, // 用户自定义className
disabled,
size,
children,
href,
...restProps // 包含了其他的所有原生属性
} = props;
// 配置 classNames : btn, btn-lg, btn-primary
// disable说明:button 默认支持disabled属性;但 a 链接disable属性就要通过样式来控制了,所以添加到classname里
const classes = classNames("btn", className, {
[`btn-${btnType}`]: btnType,
[`btn-${size}`]: size,
disabled: btnType === "link" && disabled,
});
// button 包括 link类型和其他类型
if (btnType === "link" && href) {
return (
<a className={classes} href={href} {...restProps}>
{children}
</a>
);
} else {
return (
<button className={classes} disabled={disabled} {...restProps}>
{children}
</button>
);
}
};
Button.defaultProps = {
disabled: false,
btnType: "default",
};
export default Button;
4. 使用 Jest 测试框架
Create React App 中,Jest 已经能够开箱即用,且包含许多实用的默认配置。
从 package.json 中可以看到 CRA 已内置了相关测试包:
{
"scripts": {
"test": "react-scripts test"
},
"dependencies": {
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/user-event": "^12.1.10",
"@testing-library/react": "^11.2.5"
}
}
1. 编写测试用例
// Button.test.tsx
import React from "react";
import { render } from "@testing-library/react";
import Button from "./Button";
test("my test", () => {
const wrapper = render(<Button>按钮</Button>);
const ele = wrapper.queryByText("按钮");
expect(ele).toBeTruthy();
});
2. 执行 npm run test
此时会先运行 setupTests.ts 文件,然后跑一遍测试用例。
参考:
create-react-app.dev/docs/runnin…
5. 组件库文档开发与部署
本文使用文档生成工具 docz 进行开发。docz Demo 参考 create-react-app-ts Doc。
1. 安装 npm install docz
2. 配置 scripts 脚本
{
"scripts": {
"docz:dev": "docz dev",
"docz:build": "docz build",
"docz:serve": "docz build && docz serve"
}
}
3. 为 Button 组件添加文档说明
新建 Button.mdx 文件(按照模板规范编辑即可)
注意需要引入全局样式 index.scss.
---
name: Button
menu: Components
---
import { Playground, Props } from "docz";
import { Button } from "./Button";
import "../../style/index.scss";
# Button
## Properties
<Props of={Button} />
## Basic usage
<Playground>
<Button btnType="primary"> primary button </Button>
</Playground>
## Using different kinds
<Playground>
<Button btnType="danger"> danger button </Button>
<Button btnType="link" href="https://google.com">
link button
</Button>
</Playground>
4. 添加配置文件 doczrc.js
主要用来支持编译 TS
// doczrc.js
export default {
typescript: true,
files: ["./src/**/*.mdx"], // 指定生成文档的文件
};
5. 编译 SCSS
此时运行的本地组件库文档没法正常展示样式,需要配置编译 SCSS 文件,参考 Using docz with CSS Preprocessors
npm install --save gatsby-plugin-sass- 配置
gatsby-config.js文件
//gatsby-config.js
module.exports = {
plugins: ["gatsby-plugin-sass"],
};
6. 本地预览与打包
执行 npm run docz:dev,此时本地文档就可以正常跑起来啦 (没有做美观调整,组件库样式简单粗暴)
一般本地运行报错之后,会存在缓存文件,需要删除本地.docz 文件夹,重新运行 npm run docz:dev 即可。
下面是代码目录结构
接下来就是如何将打包后的组件库文档,部署到远端服务器,并进行在线浏览
7. 使用 Netlify 一键部署
本项目采用 Netlify 一个可以用来做静态网站的持续集成与持续部署的工具。只需设置一次,以后每次我们提交代码的时候,Netlify 会自动帮我们部署最新的代码。
- 首先执行
npm run docz:build,生成打包后的文档默认在.docz/dist目录下,提交代码。 - 然后就是 Netlify 的相关配置,主要就是配置需要部署的代码 git 地址、部署前自动执行的脚本
npm run docz:build以及需要配置待部署的文件目录位置.docz/dist等
Netlify 的部署配置工作是十分简单的,基本按照提示就可以完全配置好。可以参考这篇文章使用 netlify 部署你的前端应用。
Deploy log 日志可以很清晰的看出 Netlify 的构建过程 :
Installing dependencies -> Build command from Netlify app --> Deploy site --> Build script success
一键 deploy 成功后,直接点击域名链接即可愉快的访问我们的组件库在线文档啦!传送门 🚪
6. 组件库打包
部署完组件库在线文档后,接下来就是如何将我们的组件库进行打包与发布了,这里主要使用 TS 进行编译配置。
1. 创建组件库入口文件
// index.tsx
export { default as Button } from "./components/Button";
2. 编写 tsconfig 配置文件及打包
- 新建 tsconfig.build.json 文件进行 TS 编译配置文件
- 配置 script 脚本:
"build-ts":"tsc -p tsconfig.build.json" - 执行
npm run build-ts进行打包
{
"compilerOptions": {
"outDir": "dist",
"module": "esnext",
"target": "es5",
"declaration": true,
"jsx": "react",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true
},
"include": ["src"],
"exclude": ["src/**/*.test.tsx", "src/setupTests.ts"]
}
发现此时 scss 文件并没有被打包,接下来使用 node-sass 进行编译
-
添加 script 脚本:
"build-css": "node-sass ./src/styles/index.scss ./dist/index.css" -
编译前需要删除老的 dist 文件夹。 Linux 下可以使用
rm -rf dist,但不兼容 windows。CRA 已经内置了 rimraf 插件,增加删除 script 脚本"clean": "rimraf ./dist", 参考如下:
{
"scripts": {
"start": "react-scripts start",
"build": "npm run clean && npm run build-ts && npm run build-css", // 顺序执行
"clean": "rimraf ./dist",
"build-ts": "tsc -p tsconfig.build.json",
"build-css": "node-sass ./src/style/index.scss ./dist/index.css"
}
}
执行 npm run build, 控制台可以看到三条命令依次执行。
打包后目录结构如下
3. 配置组件库入口文件
- package.json 中新增字段
{
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.ts"
}
7. 使用 npm link 本地测试组件库
在本地开发 npm 模块的时候,我们可以使用 npm link 命令,将 npm 模块链接到对应的运行项目中去,方便地对模块进行调试和测试
- 本地新建一个 demo 项目 test-component-library 用于测试组件库的使用
- 当前组件库 my-component-library 下(需要被 link 的包)执行:
npm link
// success : /usr/local/lib/node_modules/my-component-library -> /Users/当前组件库项目路径/my-component-library
// 全局 node_modulus 下会创建一个软链接 ---> 链接到当前组件库项目路径
- demo 项目(需要 link 本地包的测试项目)下执行:
npm link my-component-library
// success : /Users/当前测试项目路径/test-component-library/node_modules/my-component-library -> /usr/local/lib/node_modules/my-component-library -> /Users/liyang86/当前组件库项目路径/my-component-library
// 本地 test 项目中 node_modules/my-component-library 创建软链接 ---> 链接到全局环境 node_modules/my-component-library 作为中转 ---> 又链接到当前组件库项目路径
此时 test 项目 node_modules 中已有 my-component-library 文件夹了!并且修改组件库内容时,demo 项目中 link 的组件包也会实时更新哦。
- 引入组件及全局样式
// test-component-library 下
import { Button } from "my-component-library";
import "my-component-library/dist/index.css";
<Button btnType="primary" size="lg">
Button
</Button>;
运行一下测试项目,Button 组件已经可以正常使用啦。
8. 发布 npm
本地测试组件库通过后,接下来就是最后一步,发布组件库到 npm!
1. 配置 package.json 常用字段
- description: "React Component Lib",
- author: "my",
- private: false,
- license: "MIT",
- keywords: [ "Component","UI","React"],
- homepage: "github.com/sdyz/my-com…",
- repository: { "type": "git", "url": "github.com/sdyz/my-com…" },
- files: ["dist"], dist 文件夹下内容即待发布文件
即使不配置 ignore 或者 files 也会被发布的文件:package.json、README.md、changelog.md、license
2. 提交发布前检查
通过命令行钩子函数的方式进行验证,包括测试用例验证和 lint 代码格式检查
- ESLint 检查
--ext选项 指定 ESLint 在指定的目录下查找 JavaScript 文件时要使用的文件扩展名- 配置脚本
"lint": "eslint --ext js,ts,tsx src --max-warnings 5" - 执行
npm run lint进行测试
- Test 检查
npm run test方式会 watch,但不会返回结果,下面进行改进 参考:create-react-app.dev/docs/runnin…- cross-env 跨平台设置环境变量
npm install --save-dev cross-env - 配置脚本
"test:nowatch": "cross-env CI=true react-scripts test", - 执行
npm run test:nowatch测试成功。假如测试用例不通过,会中断退出运行。
- 增加代码提交校验工具 Husky
npm install husky --save-dev- 配置 package.json ,commit 之前运行的执行指令, 参考 typicode.github.io/husky/#/?id…
"husky": {
"hooks": {
"pre-commit": "npm run test:nowatch && npm run lint"
}
},
3. 配置 publish 脚本
- prepublish 发布前的钩子函数
- 配置脚本
"prepublish": "npm run test:nowatch && npm run lint && npm run build"
4. 发布
npm whoami检测是否登录 npmnpm adduser未登录的话进行登录/注册npm config ls或nrm ls查看当前 registry 信息(需要使用默认的 npm 源)- 执行
npm publish成功发布!
9. 组件库使用
npm install @sdyz/my-component-library
import { Button } from "@sdyz/my-component-library";
import "@sdyz/my-component-library/dist/index.css";
<Button btnType="primary" size="lg">
Button
</Button>;
大功告成!!撒花 ✿✿ ヽ(°▽°)ノ ✿ ✌️✌️✌️