Page constructor
@gravity-ui/page-constructor ·

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 以便动态导入正常工作。
发布流程
通常情况下,我们使用两种类型的提交:
fix:fix类型的提交用于修复代码库中的错误(这对应于语义化版本控制中的 PATCH)。feat:feat类型的提交在代码库中引入新功能(这对应于语义化版本控制中的 MINOR)。BREAKING CHANGE: 包含BREAKING CHANGE:页脚的提交,或在类型/范围后附加!的提交,会引入破坏性的 API 更改(对应于语义化版本控制中的 MAJOR)。BREAKING CHANGE可以是任何类型提交的一部分。- 要手动设置发布包版本,您需要在提交消息中添加
Release-As: <version>,例如:
git commit -m 'chore: bump release
Release-As: 1.2.3'
您可以在 这里 查看所有信息。
当您的 pull-request 获得代码所有者的批准并通过所有检查后,请执行以下操作:
- 检查是否有来自其他贡献者的发布 pull-request(看起来像
chore(main): release 0.0.0)。如果存在,请检查它未合并的原因。如果贡献者同意发布共享版本,请继续下一步。如果不同意,请要求他发布自己的版本,然后继续下一步。 - Squash and merge 您的 PR(发布新版本需要使用 Github-Actions)。
- 等待机器人创建一个包含新包版本和
CHANGELOG.md中您更改信息的 PR。您可以在 Actions 标签页 上查看此过程。 - 检查
CHANGELOG.md中的更改并批准机器人的 PR。 - Squash and merge PR。您可以在 Actions 标签页 上查看发布过程。
Alpha 版本发布
如果您想从您的分支发布包的 alpha 版本,您可以手动进行:
- 转到 Actions 标签页。
- 在左侧页面选择 "Release alpha version" 工作流。
- 右侧会显示 "Run workflow" 按钮。在这里您可以选择分支。
- 您还可以看到一个手动版本字段。如果您是第一次在您的分支发布 alpha 版本,请不要在此处设置任何内容。首次发布后,您必须手动设置新版本,因为我们不会更改
package.json,以防分支很快过期。否则,您将收到错误。请在您的手动版本中使用alpha前缀,否则您将收到错误。 - 点击 "Run workflow" 并等待操作完成。您可以发布任意次数的版本,但不要滥用它,只在真正需要时发布版本。在其他情况下,请使用 npm pack。
Beta-major 版本发布
如果您想发布新 major 版本,在稳定版本之前您可能需要 beta 版本,请执行以下操作:
- 创建或更新
beta分支。 - 将您的更改添加到其中。
- 当您准备好发布新的 beta 版本时,请手动使用一个空提交进行发布(或者您可以将此提交消息和页脚添加到最后一个提交中):
git commit -m 'fix: last commit
Release-As: 3.0.0-beta.0' --allow-empty
- Release please 机器人将创建一个新的 PR 到
beta分支,其中包含更新的CHANGELOG.md并增加包的版本。 - 您可以根据需要重复此操作。当您准备好发布没有 beta 标签的最新 major 版本时,您需要从
beta分支创建 PR 到main分支。请注意,您的包版本带有 beta 标签是正常的。机器人知道这一点并会正确更改它。3.0.0-beta.0将变为3.0.0。
之前 major 版本的发布流程
如果您想在提交到 main 后为之前的 major 版本发布新版本,请执行以下操作:
- 更新必要的分支,之前的 major 版本分支名称为:
version-1.x.x/fixes- 用于 major 1.x.xversion-2.x.x- 用于 major 2.x.x
- 从之前的 major 版本分支检出新分支。
- 从
main分支 cherry-pick 您的提交。 - 创建 PR,获得批准并合并到之前的 major 版本分支。
- Squash and merge 您的 PR(发布新版本需要使用 Github-Actions)。
- 等待机器人创建一个包含新包版本和
CHANGELOG.md中您更改信息的 PR。您可以在 Actions 标签页 上查看此过程。 - 检查
CHANGELOG.md中的更改并批准机器人的 PR。 - 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。
### 何