跳到主要内容

安装

npm install @dineug/erd-editor

该包仅支持 ESM("type": "module"),并且只发布 dist 目录。 没有 CommonJS 构建,因此 require('@dineug/erd-editor') 无法使用。

使用

import '@dineug/erd-editor';

const editor = document.createElement('erd-editor');
editor.style.cssText = 'display: block; width: 100%; height: 100vh;';
document.body.appendChild(editor);

// load a document without adding an undo entry, then keep it in sync
editor.setInitialValue(localStorage.getItem('my-diagram') ?? '');
editor.addEventListener('change', () => {
localStorage.setItem('my-diagram', editor.value);
});

<erd-editor> 没有固有尺寸。请为该元素或其容器显式指定 width 和 height。

setInitialValue('') 会以空文档开始。为 value 赋值则会把加载当作一次编辑,因此会记录到历史列表中。 其余 API 参见 ErdEditorElement

CDN

<script type="module">
import 'https://esm.run/@dineug/erd-editor';

const editor = document.createElement('erd-editor');
editor.style.cssText = 'display: block; width: 100%; height: 100vh;';
document.body.appendChild(editor);
</script>
<!-- or -->
<script type="module" src="https://esm.run/@dineug/erd-editor"></script>

不带版本号的 URL 始终提供最新的发布版本。如果不希望大版本升级在毫无预告的情况下进入页面,可以像 https://esm.run/@dineug/[email protected] 这样固定版本。

HTML

<erd-editor system-dark-mode enable-theme-builder></erd-editor>
<script type="module">
import 'https://esm.run/@dineug/erd-editor';

const editor = document.querySelector('erd-editor');
</script>
erd-editor {
display: block;
width: 100%;
height: 100vh;
}

在此加上 readonly 会禁止编辑:为 value 赋值、调用 clear() 以及所有 setSchema*() 都会被忽略,change 事件也不会发出。读取 editor.value 仍然有效。加载时改用 setInitialValue()

服务端渲染

导入该包会在模块作用域中注册自定义元素,因此需要 DOM,在 Node 中会抛出错误。 在 Next.js、Nuxt、SvelteKit 或 Astro 中,应从仅在客户端执行的路径导入。

useEffect(() => {
import('@dineug/erd-editor');
}, []);

TypeScript

导入该包会把 erd-editor 合并到 HTMLElementTagNameMap 中,因此无需类型断言即可获得元素的类型。

import '@dineug/erd-editor';
import type { ErdEditorElement } from '@dineug/erd-editor';

const editor = document.createElement('erd-editor'); // ErdEditorElement
const found = document.querySelector('erd-editor'); // ErdEditorElement | null

ErdEditorElement 已导出,可用于为自己的变量和 props 标注类型。

语法高亮

如果不提供高亮器,Schema SQL 和 Code Generator 面板会以纯文本显示。 @dineug/erd-editor-shiki-worker会在 shared worker 中运行一个高亮器。 由于 Shiki 及其语法文件的构建体积远超 1MB,它需要单独安装。

npm install @dineug/erd-editor-shiki-worker
import { setGetShikiServiceCallback } from '@dineug/erd-editor';

// deferred, so the highlighter never lands in your main chunk
import('@dineug/erd-editor-shiki-worker').then(({ getShikiService }) => {
setGetShikiServiceCallback(getShikiService);
});

从 CDN 使用时:

<script type="module">
import { setGetShikiServiceCallback } from 'https://esm.run/@dineug/erd-editor';
import { getShikiService } from 'https://esm.run/@dineug/erd-editor-shiki-worker';

setGetShikiServiceCallback(getShikiService);
</script>

注册一次即可,在编辑器挂载之前或之后都可以。已经显示在屏幕上的面板会在高亮器就绪后重新渲染。 支持 SQL、TypeScript、GraphQL、C#、Java、Kotlin、Scala、Go 和 Python。代码生成AMLDBML 目标在包中没有对应的语法文件,因此这些面板仍为纯文本。

有两种情况会让它无法工作。由于 worker 会以 data: URI 的形式内联,CSP 严格的页面需要 worker-src data:。 在没有 SharedWorker 的环境中(Android 上的 Chrome、16.4 之前的 Safari),不会返回高亮器,面板仍为纯文本。

入口点

导入 @dineug/erd-editor 会作为副作用注册 <erd-editor>。除此之外,它还导出元素的类型和三个回调 setter。

导出说明
ErdEditorElement(类型)元素的接口,参见 ErdEditorElement
setGetShikiServiceCallback(cb)提供语法高亮器,() => ShikiService | null
setExportFileCallback(cb)替换浏览器的下载行为,(blob, { fileName }) => void
setImportFileCallback(cb)替换浏览器的文件选择框,({ type, op, accept }) => void

@dineug/erd-editor/engine.js 是第二个入口点。它在没有 DOM 的情况下运行文档 store,因此也可以在 Web Worker 中使用。参见远程存储

文件对话框

导入与导出都会经过可注入的回调,因此没有浏览器文件对话框的宿主(例如 IDE 的 webview)也可以提供自己的实现。 两者并不对称:导出会直接交出已经生成好的文件,而导入只是请求一个文件,其内容需要自行放回编辑器。

opsetdiff。为 diff 时无论 type 是什么都会交给 setDiffValue()。其余情况由 type 决定使用哪个方法,accept 中是该类型的扩展名,可以直接传给宿主的文件对话框。

typeaccept方法
json.jsoneditor.value = text
sql.sqleditor.setSchemaSQL(text)
graphql.graphql,.gql,.graphqlseditor.setSchemaGraphQL(text)
dbml.dbmleditor.setSchemaDBML(text)
aml.amleditor.setSchemaAML(text)
import { setExportFileCallback, setImportFileCallback } from '@dineug/erd-editor';

setExportFileCallback((blob, { fileName }) => host.writeFile(fileName, blob));

setImportFileCallback(async ({ type, op, accept }) => {
const text = await host.pickFile(accept);

if (op === 'diff') {
editor.setDiffValue(text);
} else if (type === 'json') {
editor.value = text;
} else if (type === 'sql') {
editor.setSchemaSQL(text);
} else if (type === 'graphql') {
editor.setSchemaGraphQL(text);
} else if (type === 'dbml') {
editor.setSchemaDBML(text);
} else if (type === 'aml') {
editor.setSchemaAML(text);
}
});

对需要处理的每个 type 分别分支,其余的忽略即可。 为 value 赋值会在解析之前先清空文档,因此把并非 .erd.json 文档的内容送到那里(例如写了兜底的 else,或者后来新增的 type 漏掉了处理),结果不是导入任何内容,而是把图清空。

编辑器生成的 fileName<数据库名>-<时间戳> 加上 .erd.json.sql.png,其中时间戳的格式为 yyyy-MM-dd'T'HH_mm_ss。数据库名为空时会退回为 unnamed

不设置时,编辑器会使用浏览器自身的下载与文件选择行为。传入 null 可以恢复为该行为。

浏览器支持

支持 Chrome 91+、Edge 94+、Firefox 93+、Safari 16.4+,这是所发布的包构建时所基于的 ES2022 基准。 包中不包含 polyfill。如果需要支持更旧的浏览器,需要自行添加。