这里有从零开始构建现代化前端UI组件库所需要的一切(四)

在上一篇《这里有从零开始构建现代化前端UI组件库所需要的一切(三)》中,我们实现了一套高效的版本管理和发布的解决方案,其实到这里我们组件库的架构基本上就差不多了(当然如果有遗漏欢迎留言补充),接下来的几篇文章,我们会首先为组件库搭建一个文档网站,然后再扩展一些组件开发中的一些基础功能(CSS、主题等)。

那么这篇文章就是向大家展示组件库文档网站搭建的整个过程,其中包括比如:Markdown快速生成组件文档、组件示例及其代码的展示、快速创建实例并跳转至codesandbox等核心功能。

文档网站的搭建

搭建组件文档网站时,你可以根据项目需求、团队熟悉度和个人偏好选择适合的技术。以下是一些流行的技术选型:

  1. VuePress

    • 适用于 Vue.js 项目。
    • 使用 Markdown 编写文档,支持 Vue 组件。
    • 简单易用,提供了默认主题,同时支持自定义主题。
  2. Docusaurus

    • 适用于 React 项目。
    • 由 Facebook 开发,支持 Markdown 和 MDX 编写文档。
    • 提供了专业外观的默认主题,易于定制。
  3. MkDocs

    • 适用于 Python 项目,但也可以用于其他语言。
    • 使用 Markdown 编写文档,易于上手。
    • 提供了多个主题供选择,可以通过插件进行扩展。
  4. GitBook

    • 支持多种语言和框架。
    • 使用 Markdown 编写文档,提供实时预览。
    • 具有丰富的插件生态系统。
  5. Hugo

    • 使用 Go 语言构建的静态网站生成器。
    • 支持 Markdown 编写文档,速度快。
    • 提供多个主题和布局。
  6. Docsify

    • 轻量级的文档工具,适用于小型项目。
    • 使用 Markdown 编写文档,无需构建过程,实时预览。
    • 支持自定义主题和插件。
  7. Gatsby

    • 适用于 React 项目,可用于构建静态站点。
    • 支持 Markdown 和 MDX 编写文档。
    • 功能强大,支持数据源插件和定制主题。
  8. Nuxt.js

    • 适用于 Vue.js 项目。
    • 可以使用 Nuxt Content 模块来管理文档,支持 Markdown 编写。
    • 提供默认主题和可定制性。
  9. Next.js

    • 适用于 React 项目。
    • 支持 Markdown 和 MDX 编写文档。
    • 提供默认主题和灵活的定制选项。
  10. Gridsome

    • 适用于 Vue.js 项目,可用于构建静态站点。
    • 支持 Markdown 和 GraphQL 查询。
    • 提供默认主题和可定制性。

选择适合你项目需求的技术,考虑到文档的复杂度、团队的熟悉度以及所需的扩展性和定制性。最重要的是确保文档工具能够简化文档编写和维护的流程。

这里我们选择Next.js,因为其具有以下一些优势:

  1. React 支持 Next.js 是一个 React 框架,如果你的组件库是基于 React 构建的,那么使用 Next.js 可以更好地集成和展示 React 组件。

  2. 支持 Markdown 和 MDX Next.js 支持使用 Markdown 和 MDX 编写文档,这使得编写和管理文档变得更加灵活和简单。

  3. 数据获取 Next.js 具有灵活的数据获取方法,你可以通过获取外部数据或者使用 mock 数据来呈现组件的示例和文档。

  4. 静态生成和服务端渲染 Next.js 提供了静态生成和服务端渲染的能力,可以根据需要选择最适合你文档网站的渲染方式,提高性能和用户体验。

  5. 动态路由 使用 Next.js 的动态路由,你可以轻松地为每个组件生成动态页面,展示组件的不同用法和变化。

  6. 插件和生态系统 Next.js 拥有庞大的插件和生态系统,你可以根据需求引入各种插件,以扩展和定制你的文档网站。

  7. 热模块替换(HMR) Next.js 支持热模块替换,使得在开发过程中对文档进行实时更新变得更加高效。

  8. 社区支持 Next.js 拥有强大的社区支持,你可以在社区中获取到丰富的资源、解决方案和交流。

当然大家可以根据自己的技术栈选择一个合适自己的,对于我而言Next.js是最理想的选择了。当然如果你对Next.js还不熟悉,也不用担心,因为为组件搭建一个网站其实跟使用哪个框架并不是强关系的,你只需要了解到这样的网站需要的一些核心的功能及其如何实现即可。当然,我觉得你最后也会爱上Next.js生态的。

那么我们开始搭建我们的组件文档网站。

  • blankui的根目录下创建apps/目录

  • cd apps/,然后运行: pnpm create t3-app@latest

    shell 复制代码
    .../Library/pnpm/store/v3/tmp/dlx-76242  | +149 +++++++++++++++
    .../Library/pnpm/store/v3/tmp/dlx-76242  | Progress: resolved 149, reused 120, downloaded 29, added 149, done
    
       ___ ___ ___   __ _____ ___   _____ ____    __   ___ ___
      / __| _ \ __| /  \_   _| __| |_   _|__ /   /  \ | _ \ _ \
     | (__|   / _| / /\ \| | | _|    | |  |_ \  / /\ \|  _/  _/
      \___|_|_\___|_/‾‾\_\_| |___|   |_| |___/ /_/‾‾\_\_| |_|
    
    
    │
    ◇  What will your project be called?
    │  @blankui-org/docs
    │
    ◇  Will you be using TypeScript or JavaScript?
    │  TypeScript
    │
    ◇  Will you be using Tailwind CSS for styling?
    │  Yes
    │
    ◇  Would you like to use tRPC?
    │  No
    │
    ◇  What authentication provider would you like to use?
    │  None
    │
    ◇  What database ORM would you like to use?
    │  None
    │
    ◇   EXPERIMENTAL  Would you like to use Next.js App Router?
    │  Yes
    │
    ◇  Should we initialize a Git repository and stage the changes?
    │  No
    │
    ◇  Should we run 'pnpm install' for you?
    │  No
    │
    ◇  What import alias would you like to use?
    │  @/
    
    ✔ docs scaffolded successfully!
    
    Adding boilerplate...
    ✔ Successfully setup boilerplate for tailwind
    ✔ Successfully setup boilerplate for envVariables
    
    Next steps:
      cd docs
      pnpm install
      pnpm dev
      git commit -m "initial commit"
    
    Thank you for trying out the App Router option. If you encounter any issues, please open an issue!

    这里我们使用 Create T3 App 来快速创建出一个Next.js的项目,并且添加了TailwindCSS等功能。

    Create-t3-app 是一个 CLI(命令行界面),可帮助用户快速启动新的全栈 Web 应用程序。 它由 T3 Stack 开发人员创建,旨在简化设置模块化 T3 Stack 应用程序的过程。

    也可以使用Next.js官方的create-nextjs-app快速创建一个Next.js应用。

    这里就不过多介绍了,大家有兴趣可以去官网查看其详细的文档。

  • cd ../回到根目录下,先编辑pnpm-workspace.yaml文件,然后执行pnpm install安装依赖

    yml 复制代码
    packages:
      - "apps/**/**"
      - "packages/**/**"
      
  • 编辑根目录下的package.json,我们添加一个dev:docs命令:

    json 复制代码
    // ...
    "scripts": {
      // ...
      "dev:docs": "turbo dev --filter=@blankui-org/docs",
      // ...
    }
    // ...

这时候我们运行pnpm dev:docs,会报错:

shell 复制代码
> blankui@1.0.0 dev:docs /Users/******/Documents/public/blankui
> turbo dev --filter=@blankui-org/docs

 ERROR  run failed: package.json must have a name field:
/Users/******/Documents/public/blankui/apps/docs/docs/.next/types/package.json
 ELIFECYCLE  Command failed with exit code 1.

需要在pnpm-workspace.yaml中过滤掉.next/&dist/目录:

yml 复制代码
packages:
  - "apps/**/**"
  - "packages/**/**"
  - "!**/.next/**" # NEW
  - "!**/dist/**" # NEW

再次运行pnpm dev:docs,则成功启动,浏览器打开http://localhost:3000/可以看到默认的首页:

运行pnpm dev会同时启动@blankui-org/storybook & @blankui-org/docs

到这里为止的源代码:commit d8127d3

主题和国际化

网站的主题和国际化功能分别由 next-themes & next-intl 来实现:

  • 安装:pnpm add next-themes next-intl --filter @blankui-org/docs
  • 配置:
    • next-themes

      • @blankui-org/docs项目下新建src/app/theme-provider.tsx文件

        ts 复制代码
        "use client";
        
        import { ThemeProvider as NextThemeProvider } from "next-themes";
        
        export function ThemeProvider({ children }: { children: React.ReactNode }) {
          return <NextThemeProvider attribute="class">{children}</NextThemeProvider>;
        }
      • src/app/layout.tsx中引入ThemeProvider

        ts 复制代码
        // ...
        import { ThemeProvider } from "./theme-provider";
        // ...
            return (
                <html lang="en" suppressHydrationWarning>
                  <body className={`font-sans ${inter.variable}`}>
                    <ThemeProvider>{children}</ThemeProvider>
                  </body>
                </html>
              );
        // ...
      • 我们使用的是TailwindCSS,所以更改一下tailwind.config.ts配置:

        ts 复制代码
        export default {
          // ...
          darkMode: "class",
          // ...
        } satisfies Config;
    • next-intl ...

      next-intl的配置步骤比较多,这里就不做展开了,因为确实会很严重影响文章的篇幅,大家可以直接找到下面当前节点提交的代码查看👇。(后面很多的重复冗余的不那么重要的工作我也会直接带过,大家直接查看该节点的commit代码即可。)

next-themes&next-intl的配置代码:commit 415b9e5

这时候页面是空的,我们快速添加一点东西:

代码:commit e208535

使用Markdown快速为组件生成文档页面

这里我们需要安装一个库:Contentlayer

Contentlayer 是一个用于 Next.js 应用程序的数据查询和转换工具,旨在简化在 Next.js 项目中处理结构化内容的过程。以下是 Contentlayer 的主要特点:

主要特点:

  1. 内容查询:

    • Contentlayer 提供了一种类似于 GraphQL 的查询语法,让你能够从各种内容源中提取所需的数据。
    • 查询语法可以用于指定你需要获取的内容类型、字段和过滤条件。
  2. 多种内容源支持:

    • 支持从不同类型的内容源中获取数据,包括 Markdown 文件、JSON 文件和 YAML 文件。
    • 这使得你可以根据项目的需要选择最适合的内容来源。
  3. 强类型支持:

    • Contentlayer 与 TypeScript 集成,为查询结果提供强类型支持。
    • 在编写代码时,你可以受益于 TypeScript 的静态类型检查,避免潜在的类型错误。
  4. 可定制的模式:

    • 你可以定义一个模式,规定内容的结构和字段。
    • 这有助于保持一致的数据结构,使得在整个项目中使用内容变得更加可靠。
  5. 与 Next.js 紧密集成:

    • Contentlayer 专为 Next.js 项目设计,与 Next.js 的数据获取系统无缝集成。
    • 你可以在页面和组件中轻松使用 Contentlayer 查询到的数据。
  6. Markdown 内容处理:

    • Contentlayer 可以处理 Markdown 内容,将其解析为结构化数据,方便在应用中使用。

Contentlayer集成到@blankui-org/docs中:

  • 安装:

    shell 复制代码
    pnpm add contentlayer next-contentlayer date-fns --filter @blankui-org/docs
  • 配置,请参考官方的 configuration 文档,这里就只列出核心的配置:

    • @blankui-org/docs根目录下创建contentlayer.config.ts文件:

      ts 复制代码
      import { defineDocumentType, makeSource } from "contentlayer/source-files";
      import highlight from "rehype-highlight";
      import remarkGfm from "remark-gfm";
      
      export const Doc = defineDocumentType(() => ({
        name: "Doc",
        filePathPattern: `**/*.mdx`,
        contentType: "mdx",
        fields: {
          title: { type: "string", required: true },
          description: { type: "string", required: false },
          date: { type: "date", required: true },
        },
        computedFields: {
          url: {
            type: "string",
            resolve: (doc) => `/${doc._raw.flattenedPath}`,
          },
        },
      }));
      
      export default makeSource({
        contentDirPath: "./src/docs",
        documentTypes: [Doc],
        mdx: {
          remarkPlugins: [remarkGfm],
          // @ts-expect-error: Unreachable code error
          rehypePlugins: [highlight],
        },
      });

      这里我们将type配置成mdx:MDX 将 JSX 组件引入 Markdown,这可以为内容片段的主体区域提供强大的功能和灵活性,意思就是在 Markdown 可以直接引入组件,根据 MDX 文档,需要额外安装:pnpm add rehype-highlight remark-gfm @types/mdx --filter @blankui-org/docs

    • next.config.js

      js 复制代码
      import withNextIntl from "next-intl/plugin";
      import { withContentlayer } from "next-contentlayer";
      
      /**
       * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful
       * for Docker builds.
       */
      await import("./src/env.js");
      
      /** @type {import("next").NextConfig} */
      const config = {
        reactStrictMode: true,
        swcMinify: true,
        webpack: (config) => {
          // https://github.com/contentlayerdev/contentlayer/issues/272
          config.infrastructureLogging = {
            level: "error",
          };
      
          return config;
        },
      };
      
      export default withNextIntl()(withContentlayer(config));
    • 更改package.jsondev命令(需要pnpm add concurrently -D -w):

      json 复制代码
      // ...
      "dev": "concurrently \"contentlayer dev\" \"next dev\"",
      // ...

      这时候启动项目Contentlayer就会自动生成文档文件。

  • 项目中使用,在这里只列出核心的代码:

    • src/app/[locale]/目录下新建docs/[[...slug]]/page.tsx文件:

      ts 复制代码
      import { notFound } from "next/navigation";
      import { allDocs } from "contentlayer/generated";
      import { MdxComponent } from "@/components/mdx-components";
      
      export async function generateStaticParams() {
        return allDocs.map((doc) => ({
          slug: doc._raw.flattenedPath.split("/"),
        }));
      }
      
      export default async function Page({ params }: { params: { slug: string[] } }) {
        // Find the post for the current page.
        const slug = params.slug?.join("/") || "";
        // console.log(slug);
        const doc = allDocs.find((doc) => doc._raw.flattenedPath === slug);
      
        // 404 if the post does not exist.
        if (!doc) notFound();
      
        return (
          <div>
            <MdxComponent code={doc.body.code} />
          </div>
        );
      }
    • 根据contentlayer.config.ts的配置,我们创建src/docs/components/button.mdx文件:

      md 复制代码
      ---
      title: "Button"
      description: "Buttons allow users to perform actions and choose with a single tap."
      date: 2024-01-12
      ---
      
      # Button
      
      Buttons allow users to perform actions and choose with a single tap.
      
      ## hello

这时候我们在浏览器打开 URL http://localhost:3000/docs/components/button

根据button.mdx文档就生成了页面了,同理,其他组件也可以通过mdx文件生成页面,这样就很大程度上提升了生产力。

然后我们在button.mdx中直接使用Code组件:

yaml 复制代码
---
title: "Button"
description: "Buttons allow users to perform actions and choose with a single tap."
date: 2024-01-12
---

# Button

Buttons allow users to perform actions and choose with a single tap.

## hello

content from the Code component:

<Code />

需要扩展 MdxComponent 组件

ts 复制代码
export const components: MDXComponents = {
  NextImage,
  
  Code, // 这里引入

  h1: (props: React.HTMLAttributes<HTMLHeadElement>) => (
    <h1 className="text-red-600 font-bold" {...props} />
  ),
  h2: (props: React.HTMLAttributes<HTMLHeadElement>) => (
    <h2 className="text-green-400" {...props} />
  ),
  h3: (props: React.HTMLAttributes<HTMLHeadElement>) => <h3 {...props} />,
  h4: (props: React.HTMLAttributes<HTMLHeadElement>) => <h4 {...props} />,
  strong: (props: React.HTMLAttributes<HTMLElement>) => (
    <strong className="font-medium" {...props} />
  ),
  a: (props: React.HTMLAttributes<HTMLAnchorElement>) => <a {...props} />,
  Steps: ({ ...props }) => (
    <div
      className="[&>h3]:step [&>h4]:step border-default-100 relative mb-12 ml-4 border-l pl-[1.625rem] [counter-reset:step] [&>h3>a]:pt-0.5 [&>h4>a]:pt-0.5"
      {...props}
    />
  ),
};

import { useMDXComponent } from "next-contentlayer/hooks";
import { components } from "./components";

interface MdxProps {
  code: string;
}

export function MdxComponent({ code }: MdxProps) {
  const Component = useMDXComponent(code);

  return <Component components={components} />;
}

Code.tsx

ts 复制代码
import { useTranslations } from "next-intl";

export const Code: React.FC<{}> = () => {
  const t = useTranslations("Button");

  return <p>{t("desc")}</p>;
};

这时候页面:

中英文切换也都没问题。

页面好像非常简陋...是的,因为这里只是提供一个例子让你能够快速理解核心的功能,当然如果你有时间的话,可以自己完善它。

代码:commit 8308e75

稍微加了点样式和页面跳转:

代码:commit 6623a4b

为组件提供代码示例及其在线预览

组件的代码示例和在线预览的功能我们将借助 react-live 实现,我们先简单介绍一下它。

react-live 是一个 React 组件库,用于在实时编辑环境中展示和运行 React 代码。它通常用于文档、教程、博客等场景,允许用户直接在页面上编辑和执行 React 代码,并即时查看结果。以下是 react-live 的主要特点和使用说明:

特点:

  1. 实时编辑:

    • 用户可以直接在页面上编辑 React 代码,而不需要离开页面或刷新浏览器。
    • 每次编辑都会触发实时更新,用户可以立即看到代码变化的效果。
  2. 支持 JSX 和组件:

    • react-live 支持编辑和展示 JSX 语法的 React 代码。
    • 用户可以使用组件、状态和其他 React 特性,实现更丰富的交互和演示效果。
  3. 代码高亮:

    • 代码编辑器支持语法高亮,提高代码的可读性。
    • 这对于展示代码示例和教育性的内容非常有用。
  4. 错误处理:

    • react-live 能够捕获并展示代码中的错误信息。
    • 当用户输入的代码存在错误时,会在编辑器中明显显示,帮助用户更轻松地找到和解决问题。
  5. 自定义主题:

    • 支持自定义编辑器的主题,以适应不同项目或网站的设计风格。
  6. 可扩展性:

    • 可以轻松扩展 react-live 的功能,添加自定义渲染器、预处理器等。
    • 这使得它能够适应各种需求和项目。

使用说明:

  1. 安装 react-live

    • 运行以下命令安装 react-live

      bash 复制代码
      npm install react-live
  2. 在项目中使用:

    • 在你的 React 项目中导入 LiveProviderLiveEditor 等组件。

      jsx 复制代码
      import { LiveProvider, LiveEditor, LiveError, LivePreview } from 'react-live';
  3. 使用 LiveProvider 包装代码:

    • 将你的 React 代码包装在 LiveProvider 组件中。

      jsx 复制代码
      <LiveProvider code="<div>Hello World</div>">
        <LiveEditor />
        <LiveError />
        <LivePreview />
      </LiveProvider>
  4. 运行应用:

    • 启动你的应用,然后你就可以在页面上看到实时编辑和执行的效果了。
jsx 复制代码
// 完整的示例
import React from 'react';
import { LiveProvider, LiveEditor, LiveError, LivePreview } from 'react-live';

function LiveCodeExample() {
  return (
    <LiveProvider code={`<div style={{ color: 'red' }}>Hello World</div>`}>
      <LiveEditor />
      <LiveError />
      <LivePreview />
    </LiveProvider>
  );
}

export default LiveCodeExample;

通过这种方式,你可以在你的 React 项目中使用 react-live 来展示实时编辑和执行的 React 代码。

那么我们开始将react-live安装到我们组件的文档网站中来:

  • 安装:pnpm add react-live prism-react-renderer --filter @blankui-org/docs
  • 使用(这里只列出一些核心的代码):
    • 更改Code组件:

      ts 复制代码
      "use client";
      
      import { themes } from "prism-react-renderer";
      // import { useTranslations } from "next-intl";
      import { LiveProvider, LivePreview, LiveError, LiveEditor } from "react-live";
      import * as Components from "@blankui-org/react";
      
      type Props = {
        code?: string;
      };
      
      export const scope = {
        ...Components,
      } as Record<string, unknown>;
      
      console.log(scope);
      
      export const Code: React.FC<Props> = ({
        code = "<strong>Hello World!</strong>",
      }) => {
        // const t = useTranslations("Button");
      
        return (
          <LiveProvider
            code={`const App = () => {
              return (
                <Button primary={true} label="Button" onClick={() => alert("I'm Button")} />
              );
            }
            render(<App/>);`}
            noInline={true}
            scope={scope}
          >
            <LiveEditor theme={themes.oneDark} />
            <LiveError />
            <LivePreview />
          </LiveProvider>
        );
      };

这时候页面:

点击Button按钮也都正常,可以实时修改代码:

所以根据react-live我们可以为组件文档实现代码示例和在线预览的功能,比如一些很流程的UI框架的官方组件文档都会实现这个功能。

代码:commit 6814175

快速创建实例并跳转至codesandbox

@codesandbox/sandpack-react 是 CodeSandbox 团队为 React 项目提供的一个工具库,用于在 CodeSandbox 中构建和运行 React 代码。它通过提供一个基于 Webpack 的构建环境,使得在 CodeSandbox 中编辑和实时预览 React 项目变得更加方便。

以下是 @codesandbox/sandpack-react 的主要特点:

特点:

  1. 集成 React 环境:

    • @codesandbox/sandpack-react 提供了一个集成了 React 的构建环境,适用于在 CodeSandbox 中构建 React 项目。
  2. 实时预览:

    • 通过 @codesandbox/sandpack-react,你可以在 CodeSandbox 中实时预览你的 React 代码。
    • 每次编辑都会触发构建和预览,使得你可以立即查看结果。
  3. 支持 JSX 和组件:

    • 该工具库支持编辑和展示 JSX 语法的 React 代码。
    • 你可以使用 React 组件、状态和其他 React 特性,实现更丰富的交互和演示效果。
  4. 依赖管理:

    • @codesandbox/sandpack-react 能够处理项目中的依赖关系,确保所需的库和模块正确引入。
  5. 自定义配置:

    • 你可以通过提供自定义配置,调整构建环境以满足项目的特定需求。
  6. 用于 CodeSandbox 的适配器:

    • @codesandbox/sandpack-react 提供了与 CodeSandbox 集成的适配器,使得在 CodeSandbox 中运行 React 项目更为流畅。

还是一样,我们将其集成到项目里面来:

  • 安装:pnpm add @codesandbox/sandpack-react --filter @blankui-org/docs

  • 使用:

    ts 复制代码
    "use client";
    
    import {
      SandpackProvider,
      SandpackLayout,
      SandpackCodeEditor,
      SandpackPreview,
    } from "@codesandbox/sandpack-react";
    
    type Props = {};
    
    export const Sandpack: React.FC<Props> = () => {
      return (
        <SandpackProvider
          customSetup={{
            dependencies: {
              "@blankui-org/react": "^2.0.1",
            },
            entry: "index.tsx",
          }}
          files={{
            "index.tsx": {
              code: `
    import React from "react";
    import ReactDOM from "react-dom/client";
    import App from "./App";
    
    import "./styles.css";
    
    ReactDOM.createRoot(document.getElementById("root")).render(
      <React.StrictMode>
        <App />
      </React.StrictMode>
      );
              `,
              hidden: true,
            },
            "styles.css":`
            @import url("node_modules/@blankui-org/react/dist/index.css");
    
            body {
              font-family: sans-serif;
              -webkit-font-smoothing: auto;
              -moz-font-smoothing: auto;
              -moz-osx-font-smoothing: grayscale;
              font-smoothing: auto;
              text-rendering: optimizeLegibility;
              font-smooth: always;
              -webkit-tap-highlight-color: transparent;
              -webkit-touch-callout: none;
            }
    
            h1 {
              font-size: 1.5rem;
            }
    
            `,
            "/App.tsx": `import {Button} from "@blankui-org/react";
    
    export default function App() {
      return (
        <Button primary={true} label="Button" onClick={() => alert("I'm Button")} />
      );
    }
    `,
          }}
          template="vite-react-ts"
        >
          <SandpackLayout>
            <SandpackCodeEditor />
            <SandpackPreview />
          </SandpackLayout>
        </SandpackProvider>
      );
    };

    button.mdx

    md 复制代码
    ---
    title: "Button"
    description: "Buttons allow users to perform actions and choose with a single tap."
    date: 2024-01-12
    ---
    
    import { buttonContent } from "@/docs/content/button";
    
    # Button
    
    Buttons allow users to perform actions and choose with a single tap.
    
    ## Usage
    
    <Code code={buttonContent.usage} />
    
    ## Sandpack
    
    <Sandpack />

页面:

此时我们基本上实现了创建codesandbox示例的过程了,当然这里只是为了快速提供示例,后续的话代码肯定得重新封装组织一下的。建议是结合react-live一起,实现一个用户体验更好的文档,后续我会实现一下然后将代码贴出来。

代码:commit 3344fe7

刚刚从其它地方学到的代码,虽然页面没啥变化,但是代码重新封装组织了一下,方便复用,并且现在Code&Sandpack可以使用同一个模版文件渲染了:

md 复制代码
---
title: "Button"
description: "Buttons allow users to perform actions and choose with a single tap."
date: 2024-01-12
---

import { buttonContent } from "@/docs/content/button";

# Button

Buttons allow users to perform actions and choose with a single tap.

## Usage

<Code files={buttonContent.usage} />

## Sandpack

<Sandpack files={buttonContent.usage} />

buttonContent

ts 复制代码
const App = `import {Button} from "@blankui-org/react";

export default function App() {
  return (
    <Button primary label="Button" />
  );
}`;

const react = {
  "/App.tsx": App,
};

export default {
  ...react,
};

代码:commit f15ac63

这篇文章可能有点长,但是大家只需要简单过一遍即可,因为这里面的内容需要大家根据自己的实际情况来使用。好啦,那就下篇见啦~

相关推荐
passerby60614 小时前
完成前端时间处理的另一块版图
前端·github·web components
yunteng5215 小时前
通用架构(同城双活)(单点接入)
架构·同城双活·单点接入
麦聪聊数据6 小时前
Web 原生架构如何重塑企业级数据库协作流?
数据库·sql·低代码·架构
程序员侠客行6 小时前
Mybatis连接池实现及池化模式
java·后端·架构·mybatis
bobuddy8 小时前
射频收发机架构简介
架构·射频工程
桌面运维家8 小时前
vDisk考试环境IO性能怎么优化?VOI架构实战指南
架构
lbb 小魔仙9 小时前
【HarmonyOS实战】React Native 表单实战:自定义 useReactHookForm 高性能验证
javascript·react native·react.js
一个骇客10 小时前
让你的数据成为“操作日志”和“模型饲料”:事件溯源、CQRS与DataFrame漫谈
架构
鹏北海-RemHusband10 小时前
从零到一:基于 micro-app 的企业级微前端模板完整实现指南
前端·微服务·架构
2的n次方_12 小时前
Runtime 内存管理深化:推理批处理下的内存复用与生命周期精细控制
c语言·网络·架构