发布于 2026-01-06 4 阅读
0

构建并发布组件库 - React、TypeScript、Storybook AWS AI LIVE!

构建并发布组件库 - React、TypeScript、Storybook

AWS AI 直播!

介绍

本文最后,您将创建自己的自定义React 组件库,并将其发布到npm,这样其他人就可以通过简单的npm install来使用它。

为什么?

React凭借其组件驱动的架构,主导了现代Web开发。

组件可以是大型应用程序的最小原子单元,而且我们往往会经常重用它们。例如,按钮几乎随处可见,登录页面、注册页面、行动号召(CTA)等等。

这些可重用组件构成页面,页面又构成应用程序。拥有组件库有很多优势。

  • 风格一致
  • 发展速度
  • 可维护性

今天,我们将学习如何构建现代组件库(​​如Chakra UIMaterial UI ),并将其用于我们的项目中。


所需工具和知识

  • VS Code(或你喜欢的任何代码编辑器)
  • NPM
  • Git
  • React
  • TypeScript
  • 故事书

让我们开始建造吧🛠️

搭建骨架🩻

  • 创建一个空目录或cd将其复制到现有目录中
mkdir abhi-cl-blog  -> cd abhi-cl-blog
Enter fullscreen mode Exit fullscreen mode
  • 初始化项目
npm init
Enter fullscreen mode Exit fullscreen mode

这将创建一个 package.json 文件package.json,只需按回车键继续,我们稍后会对其进行编辑。下图将与为您生成的 package.json 文件类似。

package.json

  • 初始化 Git
git init
Enter fullscreen mode Exit fullscreen mode

首次学习/构建时,请使用原子提交,这样可以帮助我们回溯/找到出错的步骤。

  • 安装 React 和 TypeScript 即可开始使用
npm install react react-dom typescript @types/react --save-dev
Enter fullscreen mode Exit fullscreen mode

--save-dev 将它们安装为devDependency阅读更多

注意:由于我们将把这个库发布到 npm 供其他人使用,因此我们必须确保用户在使用我们的库时拥有正确版本的依赖项,所以我们将 react 和 react-dom 保存为peerDependencies.

package.json 文件至今

  • 创建一个.gitignore文件,以便node_modules稍后排除其他文件。

.gitignore 文件

在这个阶段创建一个提交,如果之后遇到错误,你可以回滚到这个阶段,而不是对着电脑大喊大叫然后重新开始教程🙂


构建我们的第一个组件

要创建我们的组件,请构建以下结构

-
├── src
   ├── components
|      ├── Button
|   |      ├── Button.tsx
|   |      └── index.ts
|      └── index.ts
   └── index.ts
├── package.json
└── package-lock.json
Enter fullscreen mode Exit fullscreen mode

我们正在构建一个库,希望用户能够轻松地使用/导入index我们的组件,因此我们在每个层级都创建了文件(点击此处了解更多信息)。

共有三个 index.ts文件,请在继续操作前仔细检查。

  • 初始化并配置 TypeScript
npx tsc --init
Enter fullscreen mode Exit fullscreen mode

这将在项目根目录创建一个tsconfig.json文件,其中包含 TypeScript 的默认配置,我们将修改其中一些配置。

{
  "compilerOptions": {
     "target": "es2016",
     "jsx": "react",
     "module": "ESNext",
     "moduleResolution": "node",
     "declaration": true, 
     "emitDeclarationOnly": true,
     "outDir": "dist", 
     "declarationDir": "types",
     "allowSyntheticDefaultImports": true,
     "esModuleInterop": true,
     "forceConsistentCasingInFileNames": true,
     "strict": true, 
     "skipLibCheck": true

  }
}
Enter fullscreen mode Exit fullscreen mode

这就是我们的tsconfig.json文件,把它复制到你的项目中。

具体内容可以在我的gist中查看。

如果您想了解更多关于 tsconfig 的信息,请继续阅读。

  • 在内部构建 Button.tsx src/components/Button

Button.tsx

import React from "react";


export interface ButtonProps{
    label: string;

}

const Button = ( {label}: ButtonProps) => {
    return <button>{label}</button>
}

export default Button;

Enter fullscreen mode Exit fullscreen mode

这里我们定义了按钮将接收的 props 的接口。

然后,我们构建一个简单的<Button />组件,该组件接受label一个 prop 作为参数,并返回一个带有所传递的 label prop 的 html 按钮元素。

我们将发布一个包含单个组件的库,并确认其功能正常后,再根据需要添加更多组件。

现在我们将导出按钮。

第一次出口:src/components/Button/index.ts

// This is importing Button and exporting it directly
// Syntactic sugar
export { default } from "./Button";
Enter fullscreen mode Exit fullscreen mode

第二次出口:src/components/index.ts

export { default as Button } from "./Button";
Enter fullscreen mode Exit fullscreen mode

第三出口:src/index.ts

export * from './components';
Enter fullscreen mode Exit fullscreen mode

如果你想进行比较,请查看此提交以比较你的文件。

想了解更多关于上述导出功能的信息?请查看StackOverflow 上的这个回答。


添加 Rollup

Rollup 是一个类似于 webpack 的工具,我们将使用它来打包我们的库,然后发布到 npm。

注意:在开始之前,请务必记住,这些打包工具使用了大量软件包,而且这些软件包更新频繁,因此您可能会遇到一些错误。
我会尽量解释每个安装步骤的作用,以便您在遇到问题时可以尝试解决。如果您发现任何问题,也可以在此处留言,我会尽力修复。

第一步:

npm install --save-dev tslib
Enter fullscreen mode Exit fullscreen mode

步骤二:

npm install rollup @rollup/plugin-node-resolve 
@rollup/plugin-typescript @rollup/plugin-commonjs 
rollup-plugin-dts --save-dev
Enter fullscreen mode Exit fullscreen mode
  • @rollup/plugin-node-resolve允许 Rollup 解析库的依赖项,从而可以从外部包导入模块。

  • @rollup/plugin-typescript:需要tslib作为对等依赖项,因此,步骤 1. 用于转译库中的 TypeScript 代码。

  • @rollup/plugin-commonjs将 CommonJS 模块转换为 ES6。

  • rollup-plugin-dts用于生成 .d.ts 文件,该文件为库提供 TypeScript 类型定义。这对 TypeScript 用户来说非常重要,因为它允许他们以完全的类型安全方式使用该库。

现在我们将在项目根目录下创建一个配置文件。

rollup.config.mjs

import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import typescript from "@rollup/plugin-typescript";
import dts from "rollup-plugin-dts";

import packageJson from "./package.json" assert { type: "json" };


export default [
    {
        input: "src/index.ts",
        output: [
            {
                file: packageJson.main,
                format: "cjs",

            },
            {
                file: packageJson.module,
                format: "esm",

            },
        ],
        plugins: [
            resolve(),
            commonjs(),
            typescript({tsconfig: "./tsconfig.json"}),

        ],
    },
    {
        input: "dist/esm/types/index.d.ts",
        output: [{ file: "dist/index.d.ts", format: "esm" }],
        plugins: [dts()],
    },

];
Enter fullscreen mode Exit fullscreen mode

上面的代码块是一个 Rollup 配置文件,用于打包使用 Typescript 创建的 React 组件库。

第一个配置对象
input是我们库的入口点,即目录中导出我们所有组件的index.ts文件。src

我们使用 ESM 和 commonJS 模块来分发我们的库,以便用户可以选择使用哪种类型。

我们调用的这三个插件决定了实际生成的 JavaScript 代码。

第二个配置对象:
它决定了我们库中的类型是如何分布的,并且它使用dts插件来实现这一点。

我们现在将进行更新main,并module在我们的package.json

//package.json
{
  "name": "abhi-cl-blog", // 👈name it what you want
  "version": "0.0.1", 
  "description": "A Component Library for Building React Applications faster",
  "scripts": {
// 👇👇This is what you will run to create a library
    "rollup-build-lib": "rollup -c"
  },
  "author": "Abhijit Sharma",
  "license": "ISC",
  "devDependencies": {
    "@rollup/plugin-commonjs": "^24.0.1",
    "@rollup/plugin-node-resolve": "^15.0.1",
    "@rollup/plugin-typescript": "^11.0.0",
    "@types/react": "^18.0.27",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "rollup": "^3.14.0",
    "rollup-plugin-dts": "^5.1.1",
    "tslib": "^2.5.0",
    "typescript": "^4.9.5"
  },
 "peerDependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
//new additions 👇👇
  "main": "dist/cjs/index.js",
  "module": "dist/esm/index.js",
  "files": [
    "dist"
  ],
  "types": "dist/index.d.ts"
}
Enter fullscreen mode Exit fullscreen mode
  • "main" - commonJS 模块的输出路径。
  • "module" - es6 模块的输出路径。
  • “文件” - 我们已经定义了整个库的输出目录。
  • “types” - 我们已经定义了库中类型的位置。
  • “scripts”——我们将使用它来运行我们的脚本。例如:npm run rollup-build-lib

运行汇总脚本:

npm run rollup-build-lib
Enter fullscreen mode Exit fullscreen mode

你会注意到出现了一个名为 dist 的新文件夹。

Dist 文件夹映像


将我们的库发布到 npm

  1. 创建一个 npm 帐户,如果您已有帐户,请忽略此操作。

  2. 在项目目录的根目录下,运行npm login

  3. 请更新您的package.json信息,使其包含正确的名称、版本和描述信息。

    初始版本号保留为 0.0.1

  4. 跑步npm publish

恭喜🥳,您已将组件库发布到 npm。

如果你搞不定,网上有很多教程和视频讲解。这个YouTube频道很棒


在项目中测试我们的库

  • 创建一个新的 React 应用(使用 CRA、Vite 等)。

  • 打开新应用

  • 从 npm 安装你的库

npm install <YOUR_PACKAGE_NAME>
// npm install abhi-cl-blog
Enter fullscreen mode Exit fullscreen mode
  • 让我们<Button/>在……中使用我们的组件App.tsx
import React from "react";
import { Button } from "YOUR_PACKAGE_NAME";
// import {Button} from "abhi-cl-blog";

function App() {
  return <Button label="Building Stuff is fun"/>;
}

export default App;

Enter fullscreen mode Exit fullscreen mode
  • 保存并重启应用程序后,我们看到组件按预期工作。

应用程序使用了我们库中的组件

给自己点个赞!你刚刚构建了一个可用的组件库,现在所有人都可以使用它了🙌

如果您想继续自行学习,现在可以离开本教程了,因为下一部分我们将学习如何添加

  • CSS
  • 故事书

添加 CSS

如果我们想让我们的组件拥有一些样式,我们就必须使用 CSS。

  • 在目录button.css创建一个文件Buttonsrc/components/Button/button.css

button.css

.btn{
   background-color: blueviolet;
}
Enter fullscreen mode Exit fullscreen mode
  • btn在我们的类中使用该类Button.tsx
import React from "react";
import "./button.css" // 👈new addition

export interface ButtonProps{
    label: string;

}

const Button = ({label}: ButtonProps) => {
    // btn class added 👇👇
    return <button className="btn">{label}</button>
}

export default Button;

Enter fullscreen mode Exit fullscreen mode

这看起来似乎可行,但import "./button.css"Rollup 无法识别,因此无法使用。我们需要添加一些配置,才能让 Rollup 理解我们写入的内容。

npm install postcss rollup-plugin-postcss save-dev
Enter fullscreen mode Exit fullscreen mode

rollup-plugin-postcss用于将 CSS 文件打包到最终构建中,而postcss它本身用于转换 CSS 以使其与不同的浏览器兼容(当我们使用 Tailwind 时将使用)。

更新我们的汇总配置

rollup.config.mjs

import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import typescript from "@rollup/plugin-typescript";
import dts from "rollup-plugin-dts";
import packageJson from "./package.json" assert { type: "json" };

import postcss from "rollup-plugin-postcss"; //👈 new

export default [
    {
        input: "src/index.ts",
        output: [
            {
                file: packageJson.main,
                format: "cjs",

            },
            {
                file: packageJson.module,
                format: "esm",

            },
        ],
        plugins: [
            resolve(),
            commonjs(),
            typescript({tsconfig: "./tsconfig.json"}),
          // 👇 new
            postcss({
                plugins: []
              })
        ],
    },
    {
        input: "dist/esm/types/index.d.ts",
        output: [{ file: "dist/index.d.ts", format: "esm" }],
        plugins: [dts()],
        external: [/\.(css|less|scss)$/], //👈 new
    },

];

Enter fullscreen mode Exit fullscreen mode

现在我们可以重新发布(或更新)我们的软件包了。

  • 将版本号更新package.json为 0.0.2
npm run rollup-build-lib
num publish
Enter fullscreen mode Exit fullscreen mode

请在您的演示应用程序中再次进行测试,以查看 CSS 是否已生效。

使用 terser 进行优化

这是可选步骤,只是为了减小软件包的大小。

npm install --save-dev @rollup/plugin-terser rollup-plugin-peer-deps-external
Enter fullscreen mode Exit fullscreen mode

安装完成后,我们将更新汇总配置。

rollup.config.mjs

import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import typescript from "@rollup/plugin-typescript";
import dts from "rollup-plugin-dts";
import packageJson from "./package.json" assert { type: "json" };

import postcss from "rollup-plugin-postcss";

// 👇new imports
import terser from "@rollup/plugin-terser";
import peerDepsExternal from "rollup-plugin-peer-deps-external";

export default [
    {
      input: "src/index.ts",
      output: [
        {
          file: packageJson.main,
          format: "cjs", 
        },
        {
          file: packageJson.module,
          format: "esm",
        },
      ],
      plugins: [
        peerDepsExternal(), // 👈 new line
        resolve(),
        commonjs(),
        typescript({ tsconfig: "./tsconfig.json" }),
        postcss({
          plugins: []
        }),
        terser(), // 👈 new line
      ],
    },
    {
      input: "dist/esm/types/index.d.ts",
      output: [{ file: "dist/index.d.ts", format: "esm" }],
      plugins: [dts()],
      external: [/\.(css|less|scss)$/],
    },
  ];

Enter fullscreen mode Exit fullscreen mode
  • 运行npm run rollup-build-lib以创建更新的 dist

  • 更新版本号package.json

  • 运行npm publish以更新库

整合故事书

Storybook 是一款功能强大的工具,可用于独立开发和测试组件。它允许你在沙盒环境中构建和查看组件,而无需担心应用程序的其他部分。这使得组件的迭代开发更加便捷,并确保它们在集成到大型应用程序之前能够正常工作。

此外,Storybook 还提供了一种极佳的方式来记录组件,方便其他开发者理解其使用方法。总而言之,对于任何构建组件库或使用可重用 UI 组件的开发者来说,Storybook 都是一款必不可少的工具。

从本质上讲,storybook 可以让我们在无需创建 React 应用的情况下测试我们的按钮。

在项目根目录中运行,

npx storybook init
Enter fullscreen mode Exit fullscreen mode

Storybook 如何检测到我们的项目是用 React 编写的?(谷歌)

你会注意到故事书创建了一些新文件夹.storybook 请删除该目录src/stories因为我们将学习如何创建自己的故事。
src/stories

src/components/Button让我们来创作我们的故事,在名为“故事”的目录中创建一个文件Button.stories.tsx

src/components/Button/Button.stories.tsx

import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import Button from './Button';

// You can learn about this: https://storybook.js.org/docs/react/writing-stories/introduction

export default { 
    title: 'Button',
    component: Button,
} as ComponentMeta<typeof Button>;

const Template: ComponentStory<typeof Button> = (args) => <Button {...args} />

export const Primary = Template.bind({});
Primary.args = {
    label: "Primary"
}

export const Secondary = Template.bind({})
Secondary.args = {
    label: "Secondary"
}

Enter fullscreen mode Exit fullscreen mode

Storybook 中有两个基本的组织层级:
组件及其子故事。
您可以将每个故事视为组件的一种排列组合。每个组件可以包含任意数量的故事,具体取决于您的需要。

  • 成分 (Button
  • 故事 (Primary Button
  • 故事 (Secondary Button
  • 故事 (Large Button

export default定义将在 Storybook 中显示的按钮

TemplateTemplate.bind真是一个很棒的想法,你可以点击这里查看。

让我们一起读故事书

npm run storybook
Enter fullscreen mode Exit fullscreen mode

如果遇到错误,不要着急,仔细阅读错误信息并尝试修复,因为这些工具会经常更新。

如果运行良好,你会看到这个

故事书应用

这仅仅是个开始,如果你通过文档了解更多关于 Storybook 的信息(他们甚至还有一些很棒的 YouTube 视频),你一定会喜欢的。

最后想说的话

你读完这篇文章做得很好,这篇文章让你接触到了很多新概念,例如……

  • 修改配置文件
  • 捆绑您自己的图书馆
  • 发布到 npm
  • 进行原子提交
  • 故事书

这些都是非常宝贵的学习经历,恭喜你🥳。

现在,你已经准备好构建自己的组件库,并将其发布到全世界。

如果您喜欢这篇文章,并且认为它对其他人有帮助,请随意分享。如果您觉得有什么可以改进或补充的地方,欢迎留言。


如果您想阅读更多内容:

你可以在领英推特上关注我🐦

文章来源:https://dev.to/abhijitdotsharma/build-and-publish-a-component-library-react-typescript-storybook-34ba