安装
npm install @dineug/erd-editor
该包仅支持 ESM("type": "module"),并且只发布 dist 目录。
没有 CommonJS 构建,因此 require('@dineug/erd-editor') 无法使用。
运行时依赖都以 bare import 的形式留在外部,交由你的打包器解析、去重和 tree-shaking。
其中的 shared worker 会作为独立的入口文件输出到 dist/workers/ 下,并通过 new URL('./…', import.meta.url) 构造——这正是 Vite、webpack 5 和 Rspack 识别为 worker 入口的写法。参见 Web Worker。
对于没有打包器的页面,还提供了一份自包含的构建,参见 script 标签。
使用
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>
esm.run 会替你解析该包的外部依赖,因此无需打包器也能工作。
不带版本号的 URL 始终提供最新的发布版本。如果不希望大版本升级在毫无预告的情况下进入页面,可以像 https://esm.run/@dineug/[email protected] 这样固定版本。
script 标签
从 3.6.0 起,该包还会发布一份 UMD 构建,把所有依赖和两个 shared worker 都装进同一个文件。
unpkg 与 jsdelivr 字段指向的就是它,因此这两个 CDN 上该包的基础 URL 提供的都是这个文件,它会定义 window.ErdEditor。
<erd-editor></erd-editor>
<script>
const editor = document.querySelector('erd-editor');
editor.setInitialValue(localStorage.getItem('my-diagram') ?? '');
</script>
引入它同样会注册 <erd-editor>,window.ErdEditor 上带有各个回调 setter,例如 ErdEditor.setGetShikiServiceCallback。
exports 映射仍然指向 ES 模块,因此从 npm 安装时打包器不会用到这个文件。
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>
在 script 标签中,则通过两份 UMD 构建定义的全局变量使用:
<script>
ErdEditor.setGetShikiServiceCallback(ErdEditorShikiWorker.getShikiService);
</script>
注册一次即可,在编辑器挂载之前或之后都可以。已经显示在屏幕上的面板会在高亮器就绪后重新渲染。
支持 SQL、TypeScript、GraphQL、C#、Java、Kotlin、Scala、Go 和 Python。代码生成的 AML 与 DBML 目标在包中没有对应的语法文件,因此这些面板仍为纯文本。
在没有 SharedWorker 的环境中(Android 上的 Chrome、16.4 之前的 Safari),不会返回高亮器,面板仍为纯文本。
Web Worker
编辑器会在 SharedWorker 中运行三件事:语法高亮、PNG 导出,以及文档自身的垃圾回收。
它们都不需要你来配置,但都可能被宿主环境阻止,因此每一项都有退路。
| Worker | 来源 | 缺少时 |
|---|---|---|
| 语法高亮 | @dineug/erd-editor-shiki-worker,由你注册 | Schema SQL 与 Code Generator 面板保持纯文本 |
| PNG 导出 | @dineug/erd-editor | 改在主线程绘制,绘制期间页面会卡住 |
| Schema 垃圾回收 | @dineug/erd-editor | 改为进程内运行 |
编辑器自带的这两个 worker 最多等待十秒,之后便不再依赖 worker 继续执行,因此阻止 worker 的宿主环境损失的是性能而不是功能。
在打包构建中,编辑器自带的两个 worker 会作为独立文件一同发布,因此 CSP 严格的页面需要 worker-src 'self';如果你的打包器把 worker 内联,还需要加上 blob:。
在 script 标签构建中,两个 worker 都以 data: URL 的形式装在文件里,因此这类页面需要的是 worker-src data:。
入口点
导入 @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)也可以提供自己的实现。 两者并不对称:导出会直接交出已经生成好的文件,而导入只是请求一个文件,其内容需要自行放回编辑器。
op 为 set 或 diff。为 diff 时无论 type 是什么都会交给 setDiffValue()。其余情况由 type 决定使用哪个方法,accept 中是该类型的扩展名,可以直接传给宿主的文件对话框。
type | accept | 方法 |
|---|---|---|
json | .json | editor.value = text |
sql | .sql | editor.setSchemaSQL(text) |
graphql | .graphql,.gql,.graphqls | editor.setSchemaGraphQL(text) |
dbml | .dbml | editor.setSchemaDBML(text) |
aml | .aml | editor.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。如果需要支持更旧的浏览器,需要自行添加。