快速开始
安装
shell npm i @chamn/engine @chamn/model @chamn/render  shell pnpm i @chamn/engine @chamn/model @chamn/render  shell yarn i @chamn/engine @chamn/model @chamn/render  你可以在你的机器上的任何地方运行 create astro,因此在开始之前无需创建一个新的空目录。如果你还没有为你的新项目准备一个空目录,向导将会自动为你创建一个。
如果一切顺利,你将看到一个成功信息,随后是一些推荐的后续步骤。现在你的项目已经创建好了,你可以 cd 进入你的新项目目录开始使用 Astro。
由于演示用例使用了 antd 以及 @chamn/demo-page 库(这不是必须的,只是这里做演示使用),所以你还需要安装:
shell npm i antd @ant-design/icons @chamn/demo-page  shell pnpm i antd @ant-design/icons @chamn/demo-page  shell yarn i antd @ant-design/icons @chamn/demo-page  用法
创建一个 Editor.tsx 文件,将以下代码拷贝进去:
import { BasePage, Material } from '@chamn/demo-page';import { Button, message, Modal } from 'antd';import React, { useCallback, useEffect, useState } from 'react';import ReactDOM from 'react-dom';import ReactDOMClient from 'react-dom/client';import '@chamn/engine/dist/style.css';import { Engine, EnginContext, InnerComponentMeta, plugins } from '@chamn/engine';import { RollbackOutlined } from '@ant-design/icons';import './index.css';
const { DisplaySourceSchema, DEFAULT_PLUGIN_LIST } = plugins;
const win = window as any;win.React = React;win.ReactDOM = ReactDOM;win.ReactDOMClient = ReactDOMClient;
export const App = () => {  const [ready, setReady] = useState(false);  const [page, setPage] = useState(BasePage);
  useEffect(() => {    // 从本地获取 page schema    const localPage = localStorage.getItem('pageSchema');    if (localPage) {      setPage(JSON.parse(localPage));    }    setReady(true);  }, []);
  const onReady = useCallback(async (ctx: EnginContext) => {    const designer = await ctx.pluginManager.onPluginReadyOk('Designer');    const reloadPage = async () => {      setTimeout(() => {        const designerExports = designer?.export;        designerExports.reload();      }, 0);    };
    // 获取 引擎 工作台对象    const workbench = ctx.engine.getWorkbench();
    // 自定义顶部 bar    workbench?.replaceTopBarView(      <div        style={{          width: '100%',          height: '100%',          display: 'flex',          alignItems: 'center',          justifyContent: 'flex-end',          paddingRight: '10px',        }}      >        <div className="logo">Chameleon EG</div>
        <a target="_blank" href="https://github.com/hlerenow/chameleon" rel="noreferrer">          <Button style={{ marginRight: '10px' }}>Github </Button>        </a>
        <Button          style={{ marginRight: '10px' }}          onClick={async () => {            const res = await ctx.pluginManager.get('History');            res?.export.preStep();          }}        >          <RollbackOutlined />        </Button>        <Button          style={{ marginRight: '10px' }}          onClick={async () => {            const res = await ctx.pluginManager.get('History');            res?.export.nextStep();          }}        >          <RollbackOutlined            style={{              transform: 'rotateY(180deg)',            }}          />        </Button>
        <DisplaySourceSchema pageModel={ctx.engine.pageModel} engineCtx={ctx}>          <Button style={{ marginRight: '10px' }}>Source Code</Button>        </DisplaySourceSchema>
        <Button          style={{ marginRight: '10px' }}          onClick={() => {            reloadPage();          }}        >          Refresh Page        </Button>        <Button          style={{ marginRight: '10px' }}          onClick={() => {            const src = '/#/preview';
            Modal.info({              closable: true,              icon: null,              width: 'calc(100vw - 100px)',              centered: true,              title: (                <div>                  Preview                  <Button                    size="small"                    style={{                      float: 'right',                      marginRight: '30px',                    }}                    onClick={() => {                      window.open(src);                    }}                  >                    Open in new window                  </Button>                </div>              ),              content: (                <div                  style={{                    width: '100%',                    height: 'calc(100vh - 200px)',                  }}                >                  <iframe                    style={{                      border: '1px solid #e7e7e7',                      width: '100%',                      height: '100%',                      borderRadius: '4px',                      overflow: 'hidden',                    }}                    src={src}                  />                </div>              ),              footer: null,            });          }}        >          Preview        </Button>        <Button          type="primary"          onClick={() => {            const newPage = ctx.engine.pageModel.export();            localStorage.setItem('pageSchema', JSON.stringify(newPage));            message.success('Save successfully');          }}        >          Save        </Button>      </div>    );  }, []);
  if (!ready) {    return <>loading...</>;  }
  return (    <Engine      plugins={DEFAULT_PLUGIN_LIST}      schema={page}      // 传入组件物料, 这里使用内置的基础物料以及 测试物料信      material={[...InnerComponentMeta, ...Material]}      onReady={onReady}    />  );};添加 css 让编辑器撑满窗口
html,body,#root {  width: 100%;  height: 100%;  overflow: hidden;}
body {  margin: 0;  padding: 0;}
.logo {  height: 100%;  font-size: 20px;  display: flex;  align-items: center;  margin-left: 20px;  font-weight: bolder;  margin-right: auto;}拷贝 render.umd.js
因为渲染画布是在 iframe 中运行,所以需使用 umd 模式的 js,然后让 iframe 加载,这里只需要将 render.umd.js 拷贝到公共资源目录下即可,一般是 public 文件
cp -rf ./node_modules/@chamn/render/dist/index.umd.js ./public/render.umd.jscp -rf ./node_modules/@chamn/render/dist/index.umd.js.map ./public/render.umd.js.map如果公共资源文件夹不是 public,也可以自定义 renderJSUrl:
<Engine  plugins={DEFAULT_PLUGIN_LIST}  schema={page}  // 传入组件物料, 这里使用内置的基础物料以及 测试物料信  material={[...InnerComponentMeta, ...Material]}  // 传入组件物料对应的 js 运行库,只能使用 umd 模式的 js  assetPackagesList={assetPackagesList}  onReady={onReady}  renderJSUrl="./xxxx/render.umd.js"/>配置 monaco-editor 构建
因为引擎使用了 monaco-editor 代码编辑器所以需要配置相应的构建配置
Vite
import { defineConfig } from 'vite';import react from '@vitejs/plugin-react';import monacoEditorPlugin from 'vite-plugin-monaco-editor';
// https://vitejs.dev/config/export default defineConfig({  plugins: [react(), monacoEditorPlugin({})],});Webpack
运行
将 Editor.tsx 页面作为你项目中的一个页面,运行,打开对应的地址你将会得到一个编辑页面
 
Good Luck! :)