/ Page constructor

Page constructor

一套时尚、功能齐全的块,用于快速创建宣传页和着陆页。

@gravity-ui/page-constructor · npm package CI Release storybook

Page constructor

Page-constructor 是一个用于根据 JSON 数据渲染网页或其部分的库(稍后将支持 YAML 格式)。

在创建页面时,会采用组件化方法:页面由一组现成的块组成,这些块可以按任意顺序放置。每个块都有特定的类型和一组输入数据参数。

有关输入数据格式和可用块列表,请参阅文档

安装

npm install @gravity-ui/page-constructor

快速入门

首先,我们需要一个 React 项目和某种服务器。例如,您可以使用 Vite 和 Express 服务器创建一个 React 项目,或者创建一个 Next.js 应用程序——它将同时拥有客户端和服务器端。

安装所需的依赖项:

npm install @gravity-ui/page-constructor @diplodoc/transform @gravity-ui/uikit

Page Constructor 插入页面。为了正常工作,它必须包装在 PageConstructorProvider 中:

import {PageConstructor, PageConstructorProvider} from '@gravity-ui/page-constructor';
import '@gravity-ui/page-constructor/styles/styles.scss';

const App = () => {
  const content = {
    blocks: [
      {
        type: 'header-block',
        title: 'Hello world',
        background: {color: '#f0f0f0'},
        description:
          '**Congratulations!** Have you built a [page-constructor](https://github.com/gravity-ui/page-constructor) into your website',
      },
    ],
  };

  return (
    <PageConstructorProvider>
      <PageConstructor content={content} />
    </PageConstructorProvider>
  );
};

export default App;

这是最简单的连接示例。为了使 YFM 标记生效,您需要在服务器上处理内容并在客户端接收它。

如果您的服务器是独立的应用程序,那么您需要安装 page-constructor:

npm install @gravity-ui/page-constructor

要处理所有基础块中的 YFM,请调用 contentTransformer 并将内容和选项传递给它:

const express = require('express');
const app = express();
const {contentTransformer} = require('@gravity-ui/page-constructor/server');

const content = {
  blocks: [
    {
      type: 'header-block',
      title: 'Hello world',
      background: {color: '#f0f0f0'},
      description:
        '**Congratulations!** Have you built a [page-constructor](https://github.com/gravity-ui/page-constructor) into your website',
    },
  ],
};

app.get('/content', (req, res) => {
  res.send({content: contentTransformer({content, options: {lang: 'en'}})});
});

app.listen(3000);

在客户端,添加一个端点调用来接收内容:

import {PageConstructor, PageConstructorProvider} from '@gravity-ui/page-constructor';
import '@gravity-ui/page-constructor/styles/styles.scss';
import {useEffect, useState} from 'react';

const App = () => {
  const [content, setContent] = useState();

  useEffect(() => {
    (async () => {
      const response = await fetch('http://localhost:3000/content').then((r) => r.json());
      setContent(response.content);
    })();
  }, []);

  return (
    <PageConstructorProvider>
      <PageConstructor content={content} />
    </PageConstructorProvider>
  );
};

export default App;

现成模板

要启动新项目,您可以使用我们准备的基于 Next.js 的现成模板

静态站点生成器

Page Constructor Builder - 用于使用 @gravity-ui/page-constructor 从 YAML 配置构建静态页面的命令行实用程序。

文档

参数

interface PageConstructorProps {
  content: PageContent; // 块数据,JSON 格式。
  shouldRenderBlock?: ShouldRenderBlock; // 在渲染每个块时调用的函数,允许您设置其显示的条件。
  custom?: Custom; // 自定义块(参见“自定义”)。
  renderMenu?: () => React.ReactNode; // 渲染页面菜单(带导航)的函数(我们计划添加默认菜单版本的渲染)。
  navigation?: NavigationData; // 用于在 JSON 格式中使用导航组件的导航数据
  isBranded?: boolean; // 如果为 true,则添加一个链接到 https://gravity-ui.com/ 的页脚。尝试使用 BrandFooter 组件进行更多自定义。
}

interface PageConstructorProviderProps {
  isMobile?: boolean; // 指示代码在移动模式下执行的标志。
  locale?: LocaleContextProps; // 关于语言和域的信息(用于生成和格式化链接)。
  location?: Location; // 浏览器或路由历史记录的 API,页面 URL。
  analytics?: AnalyticsContextProps; // 用于处理分析事件的函数

  ssrConfig?: SSR; // 指示代码在服务器端运行的标志。
  theme?: 'light' | 'dark'; // 用于渲染页面的主题。
  mapsContext?: MapsContextType; // 地图参数:apikey、type、scriptSrc、nonce
}

export interface PageContent extends Animatable {
  blocks: Block[];
  menu?: Menu;
  background?: MediaProps;
}

interface Custom {
  blocks?: CustomItems;
  subBlocks?: CustomItems;
  headers?: CustomItems;
  loadable?: LoadableConfig;
}

type ShouldRenderBlock = (block: Block, blockKey: string) => Boolean;

interface Location {
  history?: History;
  search?: string;
  hash?: string;
  pathname?: string;
  hostname?: string;
}

interface Locale {
  lang?: Lang;
  tld?: string;
}

interface SSR {
  isServer?: boolean;
}

interface NavigationData {
  logo: NavigationLogo;
  header: HeaderData;
}

interface NavigationLogo {
  icon: ImageProps;
  text?: string;
  url?: string;
}

interface HeaderData {
  leftItems: NavigationItem[];
  rightItems?: NavigationItem[];
}
{
  "navigationLogo": {
    "icon": "ImageProps",
    "text": "string",
    "url": "string"
  }
}

服务器工具

该包提供了一组服务器工具,用于转换您的内容。

const {fullTransform} = require('@gravity-ui/page-constructor/server');

const {html} = fullTransform(content, {
  lang,
  extractTitle: true,
  allowHTML: true,
  path: __dirname,
  plugins,
});

底层使用了一个包来将 Yandex Flavored Markdown 转换为 HTML - diplodoc/transfrom,它也是对等依赖项。

您也可以在需要的地方使用有用的工具,例如在您的自定义组件中。

function sendEvents(events: MyEventType []) {
  ...
}

<PageConstructorProvider
    ...

    analytics={{sendEvents, autoEvents: true}}

    ...
/>

事件对象只有一个必需字段 - name。它还包含预定义字段,用于帮助管理复杂逻辑。例如,counter.include 可以帮助在项目中使用多个分析系统时,将事件发送到特定的计数器。

type AnalyticsEvent<T = {}> = T & {
  name: string;
  type?: string;
  counters?: AnalyticsCounters;
  context?: string;
};

可以为项目配置所需的事件类型。

type MyEventType = AnalyticsEvent<{
  [key: string]?: string; // 只支持 'string' 类型
}>;

计数器选择器

可以配置事件发送到哪个分析系统。

type AnalyticsCounters = {
  include?: string[]; // 将应用的分析计数器 ID 数组
  exclude?: string[]; // 不会应用的分析计数器 ID 数组
};

context 参数

传递 context 值来定义事件触发的项目中的位置。

使用下面的选择器或创建满足项目需求的逻辑。

// analyticsHandler.ts
if (isCounterAllowed(counterName, counters)) {
  analyticsCounter.reachGoal(counterName, name, parameters);
}

保留的事件类型

几个预定义的事件类型用于标记自动配置的事件。例如,可以使用这些类型来过滤默认事件。

enum PredefinedEventTypes {
  Default = 'default-event', // 每次点击按钮时触发的默认事件
  Play = 'play', // React 播放器事件
  Stop = 'stop', // React 播放器事件
}

开发

npm ci
npm run dev

关于 Vite 的说明

import react from '@vitejs/plugin-react-swc';
import dynamicImport from 'vite-plugin-dynamic-import';

export default defineConfig({
  plugins: [
    react(),
    dynamicImport({
      filter: (id) => id.includes('/node_modules/@gravity-ui/page-constructor'),
    }),
  ],
});

对于 Vite,您需要安装 vite-plugin-dynamic-import 插件并配置 config 以便动态导入正常工作。

发布流程

通常情况下,我们使用两种类型的提交:

  1. fix: fix 类型的提交用于修复代码库中的错误(这对应于语义化版本控制中的 PATCH)。
  2. feat: feat 类型的提交在代码库中引入新功能(这对应于语义化版本控制中的 MINOR)。
  3. BREAKING CHANGE: 包含 BREAKING CHANGE: 页脚的提交,或在类型/范围后附加 ! 的提交,会引入破坏性的 API 更改(对应于语义化版本控制中的 MAJOR)。BREAKING CHANGE 可以是任何类型提交的一部分。
  4. 要手动设置发布包版本,您需要在提交消息中添加 Release-As: <version>,例如:
git commit -m 'chore: bump release

Release-As: 1.2.3'

您可以在 这里 查看所有信息。

当您的 pull-request 获得代码所有者的批准并通过所有检查后,请执行以下操作:

  1. 检查是否有来自其他贡献者的发布 pull-request(看起来像 chore(main): release 0.0.0)。如果存在,请检查它未合并的原因。如果贡献者同意发布共享版本,请继续下一步。如果不同意,请要求他发布自己的版本,然后继续下一步。
  2. Squash and merge 您的 PR(发布新版本需要使用 Github-Actions)。
  3. 等待机器人创建一个包含新包版本和 CHANGELOG.md 中您更改信息的 PR。您可以在 Actions 标签页 上查看此过程。
  4. 检查 CHANGELOG.md 中的更改并批准机器人的 PR。
  5. Squash and merge PR。您可以在 Actions 标签页 上查看发布过程。

Alpha 版本发布

如果您想从您的分支发布包的 alpha 版本,您可以手动进行:

  1. 转到 Actions 标签页。
  2. 在左侧页面选择 "Release alpha version" 工作流。
  3. 右侧会显示 "Run workflow" 按钮。在这里您可以选择分支。
  4. 您还可以看到一个手动版本字段。如果您是第一次在您的分支发布 alpha 版本,请不要在此处设置任何内容。首次发布后,您必须手动设置新版本,因为我们不会更改 package.json,以防分支很快过期。否则,您将收到错误。请在您的手动版本中使用 alpha 前缀,否则您将收到错误。
  5. 点击 "Run workflow" 并等待操作完成。您可以发布任意次数的版本,但不要滥用它,只在真正需要时发布版本。在其他情况下,请使用 npm pack

Beta-major 版本发布

如果您想发布新 major 版本,在稳定版本之前您可能需要 beta 版本,请执行以下操作:

  1. 创建或更新 beta 分支。
  2. 将您的更改添加到其中。
  3. 当您准备好发布新的 beta 版本时,请手动使用一个空提交进行发布(或者您可以将此提交消息和页脚添加到最后一个提交中):
git commit -m 'fix: last commit

Release-As: 3.0.0-beta.0' --allow-empty
  1. Release please 机器人将创建一个新的 PR 到 beta 分支,其中包含更新的 CHANGELOG.md 并增加包的版本。
  2. 您可以根据需要重复此操作。当您准备好发布没有 beta 标签的最新 major 版本时,您需要从 beta 分支创建 PR 到 main 分支。请注意,您的包版本带有 beta 标签是正常的。机器人知道这一点并会正确更改它。3.0.0-beta.0 将变为 3.0.0

之前 major 版本的发布流程

如果您想在提交到 main 后为之前的 major 版本发布新版本,请执行以下操作:

  1. 更新必要的分支,之前的 major 版本分支名称为:
    1. version-1.x.x/fixes - 用于 major 1.x.x
    2. version-2.x.x - 用于 major 2.x.x
  2. 从之前的 major 版本分支检出新分支。
  3. main 分支 cherry-pick 您的提交。
  4. 创建 PR,获得批准并合并到之前的 major 版本分支。
  5. Squash and merge 您的 PR(发布新版本需要使用 Github-Actions)。
  6. 等待机器人创建一个包含新包版本和 CHANGELOG.md 中您更改信息的 PR。您可以在 Actions 标签页 上查看此过程。
  7. 检查 CHANGELOG.md 中的更改并批准机器人的 PR。
  8. Squash and merge PR。您可以在 Actions 标签页 上查看发布过程。

页面构造器编辑器

编辑器提供用于页面内容管理的 UI 界面,并支持实时预览。

如何使用:

import {Editor} from '@gravity-ui/page-constructor/editor';

interface MyAppEditorProps {
  initialContent: PageContent;
  transformContent: ContentTransformer;
  onChange: (content: PageContent) => void;
}

export const MyAppEditor = ({initialContent, onChange, transformContent}: MyAppEditorProps) => (
  <Editor content={initialContent} onChange={onChange} transformContent={transformContent} />
);

Memory Bank


本项目包含一个全面的**记忆库**——一个 Markdown 文档文件的集合,提供了关于项目架构、组件和使用模式的详细信息。记忆库对于与 AI 代理协同工作尤其有用,因为它包含了关于以下内容的结构化信息:

- **项目概述**:核心需求、目标和背景
- **组件文档**:所有组件的详细使用指南
- **系统架构**:技术模式和设计决策
- **开发进度**:当前状态和实现细节

### 使用记忆库

记忆库位于 `memory-bank/` 目录中,由常规的 Markdown 文件组成,可以像阅读其他文档一样阅读:

- `projectbrief.md` - 包含核心需求的基础文档
- `productContext.md` - 项目目的和用户体验目标
- `systemPatterns.md` - 架构和技术决策
- `techContext.md` - 技术、设置和约束
- `activeContext.md` - 当前工作重点和近期更改
- `progress.md` - 实现状态和已知问题
- `usage/` - 特定于组件的使用文档
- `storybookComponents.md` - Storybook 集成详情

## 测试

可在提供的 [链接](./test-utils/docs/README.md) 找到全面的文档。

## 许可证

根据 MIT 许可证分发。详情请参阅 [LICENSE](LICENSE)。

## 面向 AI 代理

一个用于从声明式 JSON/YAML 配置渲染整个网页或页面部分的库,使用一组现成的、可排序的块——用于构建营销/登陆页面,而不是通用的应用程序 UI。

### 何
关于库
用星标支持该库
版本
8.19.0
最后更新
25.08.2026
代码仓库
github.com/gravity-ui/page-constructor
许可证
MIT License
维护者