首页 > 其他分享 >React+TypeScript 组件库开发全攻略:集成Storybook可视化与Jest测试,一键发布至npm

React+TypeScript 组件库开发全攻略:集成Storybook可视化与Jest测试,一键发布至npm

时间:2024-07-21 21:18:44浏览次数:14  
标签:npm TypeScript Button ts 全攻略 react 组件 import

平时我除了业务需求,偶尔会投入到UI组件的开发中,大多数时候只会负责自己业务场景相关或者一小部分公共组件,极少有从创建项目、集成可视化、测试到发布的整个过程的操作,这篇文章就是记录组件开发全流程,UI组件在此仅作为调试用,重点在于集成项目环境。

组件

我们使用 React + TypeScript 来开发UI组件库,为了简化 webpack 环境和 Typescript 环境配置,这里直接使用 create-react-app 通过如下命令来创建一个新项目。

npx create-react-app 项目名称 --template typescript

创建项目后先将无用文件删除,在 scr/components/Button/index.tsx 下定义一个简单的 Button 组件。

import React, { FC, ReactNode } from "react";
import cn from "classnames";
import "./index.scss";

interface BaseButtonProps {
  className?: string;
  size?: "small" | "middle" | "large";
  disabled?: boolean;
  children?: ReactNode;
}

type ButtonProps = BaseButtonProps & React.ButtonHTMLAttributes<HTMLElement>;

const Index: FC<ButtonProps> = (props) => {
  const {
    size = "middle",
    children = "按钮",
    className,
    disabled,
    ...restProps
  } = props;
  
  return (
    <button
      className={cn("btn", `btn-${size}`, className, { disabled })}
      {...restProps}
    >
      {children}
    </button>
  );
};
export default Index;

使用 scss 对其进行样式编写,这里需要注意,create-react-app 中没有自动支持 scss 文件,如果需要使用需要手动安装 sass 资源来处理。

.btn {
    background-color: #fff;
    border: 1px solid #d9d9d9;
    color: rgba(0, 0, 0, 0.88);
    line-height: 1.5;
    &.disabled {
        cursor: not-allowed;
        color: rgba(0, 0, 0, 0.25);
        background-color: rgba(0, 0, 0, 0.04);
    }
}
.btn-large {
    font-size: 16px;
    height: 40px;
    padding: 7px 15px;
    border-radius: 8px;
}
.btn-middle {
    font-size: 14px;
    height: 32px;
    padding: 4px 15px;
    border-radius: 6px
}
.btn-small {
    font-size: 14px;
    height: 24px;
    padding: 0 7px;
    border-radius: 4px
}

在 App.tsx 文件中引入组件并测试,验证其功能是否可用。

import React from "react";
import Button from "./components/Button";
import "./app.scss";
function App() {
  return (
    <div className="container">
      <Button
        size="large"
        onClick={() => {
          console.log("我是一个大按钮");
        }}
      >
        大按钮
      </Button>
      <Button disabled>中等按钮</Button>
      <Button size="small">小按钮</Button>
    </div>
  );
}
export default App;

在浏览器中可以看到组件效果,以及点击【大按钮】会触发对应的事件

Jest测试

功能简单自测后,我们需要编写测试用例来对组件进行测试,一方面是为了提高代码质量减少bug,另一方面在后期的维护升级或者重构中,只需要执行自动化脚本,便可以确认是否兼容历史版本。

这里选用 jesttesting-library ,我们通过 create-react-app 创建的 react 脚手架已经集成了单元测试的能力。

首先查看项目中的 setupTests.ts 有如下 Jest 断言增强的导入语句

import '@testing-library/jest-dom/extend-expect';

然后在 Button 文件夹下增加 index.test.tsx 文件编写测试用例,先判断是否成功渲染一个 Button 组件。

import React from 'react';
import { render, screen } from "@testing-library/react";
import Button from ".";

describe("Button组件", () => {
  it("默认Button", () => {
    render(<Button>查询</Button>); // 渲染一个名为查询的按钮
    const element = screen.getByText("查询");
    expect(element).toBeInTheDocument(); // 判断按钮是否在页面上
  });
});

脚手架 package.json 中已经添加了 test 指令的配置,我们在执行单元测试的时候只需要执行 npm run test,等待几秒便可以看到单元测试的执行结果

当我们将 const element = screen.getByText("查询"); 中的字符串 查询 改为 上传 时,会立马给出错误信息。

另外,还可以进一步的对渲染的组件进行测试,如判断 tagName、判断类名、是否是 disabled 状态、点击事件是否执行。

import React from 'react';
import { fireEvent, render, screen } from "@testing-library/react";
import Button from ".";

const defaultProps = {
  onClick: jest.fn()
}
describe("Button组件", () => {
  it("默认Button", () => {
    render(<Button {...defaultProps}>查询</Button>);
    const element = screen.getByText("查询");
    expect(element).toBeInTheDocument();
    expect(element.tagName).toEqual('BUTTON');
    expect(element.disabled).toBeFalsy();
    expect(element).toHaveClass('btn btn-middle');
    fireEvent.click(element)
    expect(defaultProps.onClick).toHaveBeenCalled()
  });
});

为组件增加新属性或者新特性时,记得为其在原来测试用例的基础上新增用例并执行,这样能在保证兼容历史功能的基础上验证新功能。

Storybook

通过项目入口文件 app.tsx 引入 Button 组件可以在本地服务运行的页面中预览效果,但随着组件的开发,我们需要不断 import 新的组件注释旧的引用来调试。

这样开发起来非常的繁琐,我们期望能有一个地方可以根据对组件进行分类,并且随时预览组件的效果,最好还能展示所有的组件配置,能根据选择配置展示组件效果。

针对以上的诉求,Storybook 就是一个非常好的解决方案。

使用 npm install storybook -d 安装,并通过 npx sb init 初始化,此时 storybook 会开启个一本地端口来展示默认生成的 stories 文件夹内案例。

我们在开发组件的 Button 文件夹下新增 index.stories.tsx 文件,来编写我们自己组件描述,一开始如果不知道如何定义,可以直接在案例组件的基础上进行修改。

import type { Meta, StoryObj } from "@storybook/react";
import { fn } from "@storybook/test";
import Button from ".";

const meta = {
  title: "Example/iceButton", // 用于展示组件的目录
  component: Button,
  tags: ["autodocs"], // 是否存在 Docs 页面
  args: { onClick: fn() },
} satisfies Meta<typeof Button>;
export default meta;

type Story = StoryObj<typeof meta>;
export const Primary: Story = {
  args: {
    children: "按钮", // 配置自己组件的属性
  },
};

这样我们自己编写的组件就加入到了页面中,右下方 Control 中是我们为组件添加的
interface BaseButtonProps,storybook 会自动将这部分填充进来,并且部分属性还可以直接在页面上修改并预览效果。

每新增一个组件,我们为其添加一个对应的 stories 文件,不仅便于预览功能,同时还能为提供详细的配置说明,直接省去编写文档的时间。

编译

在进行发布之前,我们还需要做一些配置,首先是修改入口文件,原本在 React 项目中,index.jsx 文件是找到页面中 id 为 root 的根元素并渲染组件的,现在要修改成将所有定义的组件导出,开发者者通过 import 就能导入使用。

export { default as Button} from "./components/Button";

然后我们使用 typecript 工具来对项目进行编译,react 项目初始化了 tsconfig.json,这个文件和开发相关,编译的配置需要我们自定义 tsconfig.build.json 文件。

{
  "compilerOptions": {
    // 输出文件夹
    "outDir": "dist",
    // 是 esmodule 的形式,还可以选 amd、cmd
    "module": "esnext",
    // 输出的ES版本,ES3-ESNext
    "target": "ES5",
    // typescript 使用库的时候,可以获取类型提示,在 .d.ts 文件,所以这个文件也要导出
    "declaration": true,
    // jsx 是 React.createElement 的语法糖,可选 preserve | react | react-native,编译出来的文件使用 React.createElement 代替 jsx 语法
    "jsx": "react",
    // 加载资源的方案,有classic 和 node 两种,classic 对应的是相对路径的方案,从当前路径一直往上找到 root。但是 node 是去 node_modules 中查找
    "moduleResolution": "node",
    // 支持默认导出的方式,不定义时只支持 import * as React from 'react'
    "allowSyntheticDefaultImports": true
  },
  // 编译src下的文件
  "include": ["src"],
  
// 排除 src 无需编译的文件
  "exclude": ["src/**/*.test.tsx", "src/**/*.stories.tsx", "src/setupTests.ts"]
}

可以看到常用的组件库,样式资源都是单独加载的,比如 antd

标签:npm,TypeScript,Button,ts,全攻略,react,组件,import
From: https://www.cnblogs.com/vigourice/p/18308324

相关文章

  • npm 语义化依赖管理
    之前搞前端项目,经常遇到依赖的问题,这下学到了npm的依赖管理,以后应该能应对这些问题了什么是语义化依赖管理npm根据package.json中的dependencies字段来管理依赖,一般根据下面这种格式"dependencies":{"package-name":"version","express":"4.14.0"}npm中的version遵......
  • TypeScript与面向对象编程
    引言TypeScript简介TypeScript是JavaScript的一个超集,由微软开发,它在JavaScript的基础上添加了类型系统和对ES6+的新特性的支持。TypeScript最终会被编译成纯JavaScript代码,以便在任何支持JavaScript的环境中运行。面向对象编程(OOP)概念面向对象编程是一种编程范式,它使用“......
  • TypeScript体操(一):从基础到进阶
    目录前言UtilityTypes是什么?常用UtilityTypes前置知识`typeof``keyof``typeof`和`keyof`的区别`never`关键字`extends`关键字结合条件判断`infer`类型推断(模式匹配)判断是与非判断两个类型是否相等或兼容循环递归嵌套字符串数组协变(Covariance)逆变(Contravarian......
  • 《yanr 的安装与配置全攻略》
    在软件开发和技术领域,yanr 作为一款强大的工具,能够为我们带来诸多便利。本文将详细介绍 yanr 的安装与配置步骤,帮助您快速上手并充分发挥其优势。一、yanr 简介Yarn(YetAnotherResourceNegotiator)是一种新的JavaScript包管理工具,具有速度快、离线模式、确定性、多注......
  • 如何从“.d.ts”文件生成 TypeScript API 文档?
    如何从.d.ts文件生成typescriptAPI文档?我尝试typedoc传输这个库:%npxtypedocindex.js[warning]Theentrypoint./index.jsisnotreferencedbythe'files'or'include'optioninyourtsconfig[error]Unabletofindan......
  • 打造安全新防线,商业综合体消防安全视频AI智能解决方案全攻略
    据新闻报道,7月17日四川省自贡市某百货大楼发生大火,已造成16人遇难。经初步调查,此次火灾事故由施工作业引发,具体情况正在进一步调查中。随着城市化进程的加快,商场、百货大楼等商业综合体作为城市商业活动的重要载体,其消防安全工作显得尤为重要。传统的消防安全监控方式已难以满足......
  • 守护安全,商业综合体消防安全视频AI智能解决方案全攻略
    据新闻报道,7月17日四川省自贡市某百货大楼发生大火,已造成16人遇难。经初步调查,此次火灾事故由施工作业引发,具体情况正在进一步调查中。随着城市化进程的加快,商场、百货大楼等商业综合体作为城市商业活动的重要载体,其消防安全工作显得尤为重要。传统的消防安全监控方式已......
  • npm/yarn/pnpm install失败:ERR_PNPM_NO_VERSIONS No versions available for uWebSock
    ERR_PNPM_NO_VERSIONS NoversionsavailableforuWebSockets.js.Thepackagemaybeunpublished.我在新项目中想要切换包管理器从yarn到pnpm的时候,删除node_modules和yarn.lock之后,pnpminstall竟然提示这个包可能没发布。我觉得这个不可能,都需要使用了,怎么可能没发......
  • SpringBoot 跨域请求处理全攻略:从原理到实践
    文章目录SpringBoot如何处理跨域请求?你能说出几种方法?跨域请求概述跨域解决方案1.使用@CrossOrigin注解2.使用WebMvcConfigurer配置类3.使用过滤器(Filter)4.使用SpringSecurity处理CORS5.使用SpringCloudGateway处理CORS补充1.预检请求(PreflightRequests)2.其......
  • NFS服务器配置全攻略:从入门到精通
    NFS服务的配置NFS服务器配置文件NFS服务器共享目录配置文件为/etc/exports,此文件的语法结构如下:共享目录的绝对路径客户端地址1(选项)客户端地址2(选项)...NFS服务器在共享一个目录的时候,客户端选项部分定义允许哪些主机可以访问此共享目录,客户端地址与选项之间没......