Установка
npm install @dineug/erd-editor
Пакет распространяется только в формате ESM ("type": "module") и включает лишь папку dist.
Сборки CommonJS нет, поэтому вызов require('@dineug/erd-editor') не работает.
Он содержит два пользовательских элемента: <erd-editor> — редактор и, начиная с версии 5.0.0, <erd-viewer>, который показывает диаграмму только для чтения, — см. ErdViewerElement.
Начиная с версии 5.0.0 импорт корня пакета не определяет ни одного из них. У каждого элемента есть собственная точка входа, которая его определяет, — см. Регистрация элементов.
Зависимости времени выполнения оставлены внешними, в виде импортов по имени пакета, которые сборщик разрешает, дедуплицирует и очищает от неиспользуемого кода. Начиная с версии 5.0.0 его dist содержит по одному файлу на модуль, поэтому сборщик оставляет только те модули, до которых доходит страница, — см. Точки входа.
Общие воркеры пакета выводятся отдельными файлами точек входа в папке dist/workers/ и создаются через new URL('./…', import.meta.url) — в той форме записи, которую Vite, webpack 5 и Rspack собирают как точку входа воркера. См. Web Worker.
Для страницы без сборщика есть две самодостаточные сборки — см. Тег script.
Использование
import '@dineug/erd-editor/erd-editor.js';
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);
});
@dineug/erd-editor/erd-editor.js определяет <erd-editor> в момент импорта. Страница, которая лишь показывает диаграмму, импортирует вместо него @dineug/erd-editor/erd-viewer.js — см. ErdViewerElement.
У элемента <erd-editor> нет собственного размера. Задайте ему (или его контейнеру) явные ширину и высоту.
Начиная с версии 4.1.0 открытый Обозреватель закрепляется внутри элемента слева от холста ERD и сужает холст, а не перекрывает его. В новом редакторе он изначально закрыт.
Панель отрисовывается шириной не менее 200px и оставляет холсту не менее 320px, поэтому в элементе шириной менее 520px открытый Обозреватель не отрисовывается, пока элемент не станет шире, — см. Рядом с холстом.
Вызов setInitialValue('') создает новый пустой документ. Присваивание значения свойству value, напротив, загружает документ как правку, поэтому она попадает в историю изменений.
Начиная с версии 4.0.0 свойство editor.value содержит документ в той форме, в которой его хранит файл, — именно его и нужно сохранять. Свойство editor.runtimeValue содержит документ в том виде, в каком его держит редактор, включая удаленные сущности: оно служит для инициализации соавтора и никогда не попадает в файл — см. runtimeValue.
Начиная с версии 4.0.0 в новом документе также включены все блокировки настроек: область просмотра, вкладка, язык Генератора кода, оба стиля имен, тип кавычек, а начиная с версии 4.2.0 — и режим отображения имен. Прокрутка, масштабирование, переключение вкладок, переключение режима отображения имен или изменение одной из остальных настроек оставляют свойство editor.value прежним, и событие change не возникает. Документ, загруженный из текста, сохраняет указанные в нем блокировки. Документ, в котором блокировки не указаны, например любой файл, сохраненный до версии 4.0.0, открывается со всеми включенными блокировками, с масштабом 100% и на вкладке ERD, какие бы область просмотра и вкладку он ни сохранил. Его область просмотра заблокирована в начале координат 0, 0, а если там не отрисовано ничего из диаграммы, вид вместо этого открывается на диаграмме — см. setInitialValue.
Файл, сохраненный до версии 4.2.0, открывается в режиме Physical Names с заблокированным режимом отображения имен, даже если все остальные блокировки в нем выключены. Редактор версии 4.0.0 или 4.1.0 при сохранении оставляет блокировку режима отображения имен как есть, но отбрасывает сам режим, поэтому файл версии 4.2.0, сохраненный с разблокированным режимом отображения имен, остается разблокированным, но снова открывается в режиме Physical Names.
Об остальном API см. ErdEditorElement.
CDN
<script type="module">
import 'https://esm.run/@dineug/erd-editor@5.1.0/erd-editor.js';
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@5.1.0/erd-editor.js"></script>
Сервис esm.run сам разрешает внешние зависимости пакета, поэтому такой вариант работает без сборщика.
Каждая точка входа выбирается путем после версии: …/erd-editor.js определяет редактор, а …/erd-viewer.js — просмотрщик, который загружает с CDN каждый язык интерфейса, кроме английского, когда страница его запрашивает. URL без точки входа, https://esm.run/@dineug/erd-editor@5.1.0, отдает корень, который не определяет ни одного элемента.
URL без версии всегда отдает последнюю версию. Закрепите версию, как выше, если не хотите, чтобы новая мажорная версия попала на страницу без предупреждения.
Версия 5.0.0 — как раз такая: страница, которой нужно остаться на 4.x, закрепляет версию @4.2.0 — см. Переход с версии 4.x.
esm.run отдает общие воркеры с cdn.jsdelivr.net, а браузер не запускает общий воркер с источника, отличного от источника страницы. Поэтому редактор, загруженный таким способом, работает без своих воркеров, как на хосте, который их блокирует, — см. Web Worker. Сборка для тега script несет их внутри своего файла.
Тег script
Начиная с версии 3.6.0 пакет также содержит UMD-сборку, в которой все зависимости и все общие воркеры находятся внутри одного файла, dist/erd-editor.umd.js.
Именно на нее указывают поля unpkg и jsdelivr, поэтому на любой из этих двух CDN ее отдает URL с одним лишь именем пакета, и она определяет window.ErdEditor.
<erd-editor></erd-editor>
<script src="https://cdn.jsdelivr.net/npm/@dineug/erd-editor@5.1.0"></script>
<script>
const editor = document.querySelector('erd-editor');
editor.setInitialValue(localStorage.getItem('my-diagram') ?? '');
</script>
Ее загрузка определяет <erd-editor>. Объект window.ErdEditor содержит два файловых колбэка, ErdEditor.setExportFileCallback и ErdEditor.setImportFileCallback, начиная с версии 3.9.2 — ErdEditor.createKeyBindingMap, начиная с версии 4.2.0 — ErdEditor.dictionaryRowChords (см. dictionaryRowChords), а начиная с версии 5.0.0 — ErdEditor.ErdEditorElement и ErdEditor.defineErdEditor (см. Регистрация элементов). toImage в нем нет.
Начиная с версии 5.0.0 второй файл, dist/erd-viewer.umd.js, определяет <erd-viewer> и помещает ErdViewerElement и defineErdViewer в window.ErdViewer. Он не запускает ни одного воркера, содержит все 25 языков интерфейса и не запрашивает ничего, кроме переданного ему src.
<erd-viewer src="diagram.erd.json" style="display: block; height: 480px"></erd-viewer>
<script src="https://cdn.jsdelivr.net/npm/@dineug/erd-editor@5.1.0/dist/erd-viewer.umd.js"></script>
Ни один из файлов не определяет тег другого, и каждый оставляет на странице только свой глобальный объект и window.Konva.
Карта экспортов пакета по-прежнему направляет сборщик к ES-модулям, поэтому установка из npm никогда не подхватывает ни один из этих файлов.
Страница, которая не может загрузить собственный скрипт, может вместо этого встроить размещенный просмотрщик erd-editor.io/embed во фрейм — см. Встраивание.
HTML
<erd-editor system-dark-mode enable-theme-builder enable-locale-picker enable-welcome-screen></erd-editor>
<script type="module">
import 'https://esm.run/@dineug/erd-editor@5.1.0/erd-editor.js';
const editor = document.querySelector('erd-editor');
</script>
erd-editor {
display: block;
width: 100%;
height: 100vh;
}
Начиная с версии 4.0.0 атрибут enable-locale-picker добавляет на панель инструментов окно выбора Display Language, а атрибут enable-welcome-screen — экран приветствия, который показывается на пустой диаграмме, — см. enableLocalePicker и enableWelcomeScreen.
Страница, которая загружает документ, как в разделе Использование, включает свойство enableWelcomeScreen не в разметке, а после того как метод setInitialValue() загрузит документ, поэтому экран никогда не мелькает поверх файла, который еще загружается.
Редактор содержит все 25 языков интерфейса, причем как в ES-сборке, так и в сборке для тега script, поэтому не нужно ни отдавать файлы локалей с сервера, ни что-либо регистрировать. Без окна выбора и без вызова setLocale() редактор отображается на английском языке.
Если добавить сюда атрибут readonly, редактор открывается как читатель: присваивание значения свойству value, вызов clear() и любые вызовы setSchema*() — в том числе setSchemaJSON() и вызовы с добавлением — игнорируются, а событие change никогда не возникает. Его вкладки, Обозреватель и быстрый поиск остаются для чтения, а каждый элемент управления, который изменял бы диаграмму, исчезает.
Чтение editor.value и editor.runtimeValue по-прежнему работает, и оба сохраняют собственные настройки документа: настройка вида, которую меняет читатель, например масштаб или СУБД, остается на экране этого редактора. Вместо этого загружайте документ через setInitialValue() — см. readonly.
Серверный рендеринг
Каждая точка входа, кроме engine.js и peer.js, требует DOM, поэтому в Node она выбрасывает исключение. erd-editor.js и erd-viewer.js определяют свой элемент на уровне модуля, а корень пакета, который с версии 5.0.0 ничего не определяет, при загрузке все равно создает оба класса элементов.
В Next.js, Nuxt, SvelteKit или Astro загружайте точку входа элемента из кода, который выполняется только на клиенте, и именованный импорт из корня, например setExportFileCallback или toImage, — из того же кода.
useEffect(() => {
import('@dineug/erd-editor/erd-editor.js');
}, []);
Vite
В режиме разработки добавьте в предварительную сборку Vite бандл ELK, который импортирует воркер размещения редактора, иначе размещения, которые строит этот воркер, завершаются сбоем: Flow, Tree - vertical и Tree - horizontal в Автоматическом размещении, режим Flow на вкладке «Визуализация» и импорт, размещаемый с помощью Flow.
Vite 7 и более ранним версиям нужно также исключить редактор из предварительной сборки, поскольку при ней URL воркеров указывают на файлы, которые она никогда не записывает, и все три воркера дают сбой. В Vite 8 не добавляйте этот exclude: он лишь заставляет сервер разработки загружать каждый файл пакета по отдельности. Производственной сборке не нужно ни то, ни другое.
// vite.config.js
export default {
optimizeDeps: {
include: ['@dineug/erd-editor > elkjs/lib/elk.bundled.js'],
// Vite 7 and older only:
// exclude: ['@dineug/erd-editor'],
},
};
TypeScript
Импорт @dineug/erd-editor/erd-editor.js добавляет erd-editor в HTMLElementTagNameMap, а @dineug/erd-editor/erd-viewer.js — erd-viewer, поэтому элемент типизирован без приведения типа. Любой импорт из корня, в том числе только типа, приносит оба.
import '@dineug/erd-editor/erd-editor.js';
import type { ErdEditorElement } from '@dineug/erd-editor';
const editor = document.createElement('erd-editor'); // ErdEditorElement
const found = document.querySelector('erd-editor'); // ErdEditorElement | null
Тип ErdEditorElement экспортируется для аннотирования собственных переменных и пропсов. Начиная с версии 5.0.0 это еще и класс элемента, а ErdViewerElement — интерфейс и класс просмотрщика, — см. Регистрация элементов.
Начиная с версии 4.0.0 пакет также экспортирует типы LocaleCode, LocaleOption и SchemaSQLOptions, а начиная с версии 5.0.0 — и ToImageOptions, — см. Точки входа. У параметров, которые принимают методы setSchema*(), нет экспортируемого имени; получайте их из типа элемента в виде Parameters<ErdEditorElement['setSchemaSQL']>[1]. То же относится к общему хранилищу и его типам.
Начиная с версии 5.0.0 поле typesVersions пакета типизирует и каждую точку входа-подпуть при moduleResolution: "node10", который не читает карту экспортов.
Регистрация элементов
Начиная с версии 5.0.0 пакет определяет тег только там, где его об этом просит страница.
| Импорт | Определяет |
|---|---|
@dineug/erd-editor/erd-editor.js | <erd-editor> |
@dineug/erd-editor/erd-viewer.js | <erd-viewer> |
@dineug/erd-editor | Ничего |
Каждая из двух точек входа определяет свой тег при вычислении и ничего не экспортирует, поэтому ее импортируют ради побочного эффекта, и ни одна из них не определяет тег другой.
Корень экспортирует оба класса элементов, ErdEditorElement и ErdViewerElement, а также defineErdEditor() и defineErdViewer(), которые определяют свой тег там, где вы их вызываете:
import { defineErdEditor } from '@dineug/erd-editor';
defineErdEditor();
Вызов ничего не делает, пока тег уже занят этим классом, поэтому точка входа и вызов define или два вызова define могут встретиться на одной странице. Он выбрасывает Error с названием тега, если тег занят другим классом, как это было бы со второй копией пакета, собранной в ту же страницу: Another element class already defines the custom element name erd-editor.
Классы корня — это те же классы, которые определяют точки входа, поэтому после запуска любой из них customElements.get('erd-editor') === ErdEditorElement. Пока тег не определен, document.createElement('erd-editor') создает обычный HTMLElement без членов редактора, а new ErdEditorElement() выбрасывает исключение.
Для собственного тега определите класс под ним сами и сами добавьте тег в HTMLElementTagNameMap. Делайте это в окне, которое не загружает ни точку входа этого элемента, ни его сборку для тега script и не вызывает для него функцию define, поскольку класс получает одно имя на окно:
import { ErdEditorElement } from '@dineug/erd-editor';
customElements.define('my-erd-editor', ErdEditorElement);
declare global {
interface HTMLElementTagNameMap {
'my-erd-editor': ErdEditorElement;
}
}
Бандл, содержащий оба элемента, заставляет Vite и Rolldown выдать предупреждение INEFFECTIVE_DYNAMIC_IMPORT по одному разу для каждого языка интерфейса, кроме английского. Просмотрщик загружает каждый из них собственным import(), а редактор импортирует все словари сразу, поэтому они остаются в чанке редактора и загружаются вместе с ним. Ничего не ломается, а в бандле с одним лишь просмотрщиком каждый язык остается в собственном чанке.
Подсветка синтаксиса
Панели Схемы SQL и Генератора кода подсвечивает Shiki в собственном общем воркере, а начиная с версии 4.0.0 — и скрипты Before tables и After tables на вкладке «Схема SQL».
Начиная с версии 3.7.0 ничего не нужно ни устанавливать, ни регистрировать: воркер создается при первой отрисовке панели с кодом, поэтому страница, которая не открывает ни одной такой панели, никогда не загружает грамматики.
| Языки | SQL, TypeScript, GraphQL, C#, Java, Kotlin, Scala, Go, Python, PHP, Rust, Swift, JSON, Mermaid |
| Темы | github-dark и github-light в зависимости от светлого или темного оформления редактора |
Это ровно те языки, которые выводят панели: JPA подсвечивается как Java, SQLAlchemy — как Python, TypeORM, Sequelize, Drizzle и Zod — как TypeScript, Doctrine — как PHP, SeaORM — как Rust, JSON Schema — как JSON, а DBML и AML — как SQL, самая близкая к ним грамматика в комплекте, — см. Генератор кода.
Движок регулярных выражений написан на чистом JavaScript, поэтому политике хоста не требуется разрешение wasm-unsafe-eval.
Там, где SharedWorker отсутствует, — в Chrome для Android до Chrome 148 и в Safari до версии 16.4 — сбой записывается в журнал, а код отображается обычным текстом; скрипты по-прежнему можно редактировать.
При переходе с версии 3.6.0 или более ранней: пакет @dineug/erd-editor-shiki-worker больше не публикуется, и вместе с ним исчезла функция setGetShikiServiceCallback.
Уберите установку пакета и регистрацию, а со страницы, которая загружала воркер с CDN, также уберите второй тег <script>.
Web Worker
Редактор выполняет три задачи в воркерах SharedWorker: подсветку синтаксиса, экспорт изображения и размещение таблиц, на котором основаны Автоматическое размещение, режим Flow на вкладке «Визуализация» и начиная с версии 4.0.0 размещение импортированной схемы.
Все три воркера входят в пакет @dineug/erd-editor. Ни один из них не требует настройки, но любой из них может быть заблокирован хостом.
Начиная с версии 5.0.0 каждый воркер создается в собственном модуле, поэтому бандл несет только те воркеры, до которых доходят его модули: бандл toImage без элемента несет один лишь воркер экспорта изображения, а <erd-viewer> не запускает воркеров вообще — см. Точки входа.
Воркер, который выполнял сборку мусора документа, удален в версии 4.0.0 вместе с самой сборкой мусора.
| Воркер | Без него |
|---|---|
| Подсветка синтаксиса | Панели Схемы SQL и Генератора кода, а также скрипты Схемы SQL остаются обычным текстом |
| Экспорт изображения | PNG, SVG, Copy to clipboard, предварительный просмотр в окне Export image и, начиная с версии 5.0.0, toImage() отрисовываются в основном потоке, что блокирует страницу на время отрисовки |
| Размещение таблиц | Варианты размещения Flow, Tree - vertical и Tree - horizontal в Автоматическом размещении, а также режим Flow на вкладке «Визуализация» завершаются сообщением Could not place tables; импорт, размещаемый с помощью Flow, — файл SQL, GraphQL, DBML или AML из пункта Import или Import and Add либо вызов setSchema*() с параметром placement: 'auto' — располагает свои таблицы рядами без какого-либо сообщения; Force и режим Graph это не затрагивает, так как они выполняются внутри редактора |
Экспорт изображения ждет ответа своего воркера десять секунд и затем рисует в основном потоке, а подсветка синтаксиса оставляет код обычным текстом, как только ее воркер дает сбой, поэтому, если хост блокирует воркеры, теряется производительность, а не функциональность.
Исключение — размещение таблиц: движок, который вычисляет размещение, весит больше самого редактора и никогда не загружается в процесс страницы, поэтому при первом размещении эта задача ждет свой воркер тридцать секунд, а после того как воркер ответил, отводит размещению шестьдесят секунд на возврат результата.
Если время любого из этих ожиданий истекает, размещение завершается так же, как без воркера. Автоматическое размещение показывает Placing tables сразу после запуска, а режим Flow и импорт, размещаемый с помощью Flow, показывают его, только когда размещение, включая запуск воркера, длится уже шесть секунд.
Vite, webpack 5 и Rspack выводят воркеры файлами рядом с вашими чанками. esbuild и Rolldown, используемый сам по себе, а не через Vite, не выводят ничего, поэтому страница, которую они собирают, работает без воркеров.
В экспериментальном режиме webpack experiments.outputModule ни один воркер не запускается, поскольку каждый ждет отделенный от него чанк, который никто не загружает. Оставьте стандартный вывод webpack или задайте optimization.splitChunks: false.
Content Security Policy
Странице со строгой политикой Content Security Policy для элементов нужны следующие директивы:
worker-src 'self'для сборки со сборщиком, воркеры которой — файлы рядом с пакетом, плюсblob:, если сборщик встраивает воркер в код. В сборке для тега script все три находятся внутри файла в виде URLdata:, поэтому такой странице вместо этого нужна директиваworker-src data:.<erd-viewer>не нужно ни то, ни другое, так как он не запускает воркеров.- Начиная с версии
5.0.0оба элемента оформляют себя сконструированными таблицами стилей, которые пропускаетstyle-src 'self'. Панели кода редактора по-прежнему раскрашивают текст атрибутамиstyle, а предварительный просмотр окнаExport image— это изображение по URLblob:, поэтому редактору для них нужны такжеstyle-src 'unsafe-inline'иimg-src blob:. - Браузер без сконструированных таблиц стилей, например Firefox до версии 101, получает вместо них элементы
<style>, которым для любого из элементов нужна директиваstyle-src 'unsafe-inline'. <erd-viewer>загружает свойsrcчерез fetch, поэтому этот источник нужно указать вconnect-src— см. Что он добавляет на страницу.
Точки входа
В пакете пять точек входа:
| Точка входа | Что это |
|---|---|
@dineug/erd-editor | Корень: экспорты ниже. Начиная с версии 5.0.0 он не определяет ни одного элемента, но для загрузки ему по-прежнему нужен DOM |
@dineug/erd-editor/erd-editor.js | Начиная с версии 5.0.0. Определяет <erd-editor> и ничего не экспортирует |
@dineug/erd-editor/erd-viewer.js | Начиная с версии 5.0.0. Определяет <erd-viewer> и ничего не экспортирует |
@dineug/erd-editor/engine.js | Хранилище документа без DOM |
@dineug/erd-editor/peer.js | Начиная с версии 3.9.1. Участник без интерфейса для MCP-сервера и, начиная с версии 5.1.0, для привязки Yjs |
Корень экспортирует оба класса элементов и их функции define, два сеттера колбэков, начиная с версии 3.9.2 — привязки клавиш по умолчанию с их типами, начиная с версии 4.0.0 — типы языка интерфейса и тип параметров getSchemaSQL(), начиная с версии 4.2.0 — сочетания клавиш для строк на вкладке «Словарь», а начиная с версии 5.0.0 — toImage.
| Экспорт | Описание |
|---|---|
ErdEditorElement | Интерфейс элемента — см. ErdEditorElement. Начиная с версии 5.0.0 также его класс, тот, которым определен <erd-editor>, — см. Регистрация элементов. |
ErdViewerElement | Начиная с версии 5.0.0. Интерфейс и класс просмотрщика — см. ErdViewerElement. |
defineErdEditor(), defineErdViewer() | Начиная с версии 5.0.0. Определяют <erd-editor> или <erd-viewer> его классом. Вызов ничего не делает, пока тег занят этим классом, и выбрасывает Error, когда тег занят другим, — см. Регистрация элементов. |
toImage(value, options) | Начиная с версии 5.0.0. Рисует документ как Blob с PNG или как строку SVG с параметрами окна Export image — см. toImage. |
ToImageOptions (тип) | Начиная с версии 5.0.0. Параметры, которые принимает toImage(): format, background, darkMode и scale. |
setExportFileCallback(cb) | Заменяет скачивание файла браузером, (blob, { fileName }) => void. |
setImportFileCallback(cb) | Заменяет окно выбора файла браузера, ({ type, op, accept, mode }) => void; mode — начиная с версии 4.0.0. Начиная с версии 4.2.0 кнопка Import CSV на вкладке «Словарь» открывает окно выбора файла браузера, даже если колбэк задан, — см. Диалоговые окна выбора файлов. |
createKeyBindingMap() | При каждом вызове возвращает привязки клавиш по умолчанию в виде нового объекта KeyBindingMap — см. createKeyBindingMap. |
KeyBindingMap, KeyBindingName, ShortcutOption (типы) | Карта привязок, тип-объединение имен ее команд и одна привязка. |
dictionaryRowChords(map) | Начиная с версии 4.2.0. При каждом вызове возвращает в виде нового массива ShortcutOption[] сочетания клавиш, которыми сетка вкладки «Словарь» вставляет и удаляет строки при переданной карте KeyBindingMap. Сочетания, которое вставляет строки выше (Alt+Shift+Enter при привязках по умолчанию), нет ни в одной привязке — см. dictionaryRowChords. |
LocaleCode, LocaleOption (типы) | Начиная с версии 4.0.0. Коды 25 языков интерфейса, а также эти коды вместе со значением 'system', которые принимает метод setLocale(), — см. Язык интерфейса. |
SchemaSQLOptions (тип) | Начиная с версии 4.0.0. Параметры, которые принимает метод getSchemaSQL(): statements, header и (начиная с версии 4.2.0) logicalNameAsComment — см. getSchemaSQL. |
Начиная с версии 5.0.0 dist содержит по одному неминифицированному файлу на модуль, каждый рядом со своим объявлением, а поле sideEffects в package.json называет только две точки входа тегов и две заглушки, нужные файлам воркеров. Поэтому сборщик отбрасывает каждый модуль, до которого страница не доходит, и минифицирует один раз:
- Именованный импорт из корня, например
setExportFileCallback, не приносит ни одного элемента и ни одного воркера. toImageприносит воркер экспорта изображения и ни одного элемента.erd-editor.jsприносит редактор и все три общих воркера.erd-viewer.jsприносит просмотрщик и ни одного воркера, с английским языком внутри и каждым другим языком интерфейса в собственном чанке, который загружается, когда страница его запрашивает.
@dineug/erd-editor/engine.js запускает хранилище документа без DOM, поэтому работает в Web Worker — см. Удаленное хранение.
Она экспортирует createReplicationStore и тип ReplicationStore. Начиная с версии 3.10.0 она также экспортирует тип ReplicationChange, { value: string; changed: boolean }, который получает обработчик события change реплики, — см. on@change.
Начиная с версии 4.0.0 у ReplicationStore также есть свойство runtimeValue. Как и у элемента, его свойство value и значение, которое передает событие change, имеют форму хранения, как в файле, — см. ReplicationStore.
@dineug/erd-editor/peer.js — это участник без интерфейса, через которого MCP-сервер редактирует документ.
Начиная с версии 5.1.0 это еще и то, что bindPeerStore из @dineug/erd-editor-yjs привязывает к Y.Doc: одноранговое хранилище, созданное вызовом createPeerStore() этой точки входа, как участник комнаты без интерфейса или как сжимающий процесс, который сворачивает историю комнаты.
Помимо того, что показывает о нем страница Yjs — вызова createPeerStore(), value привязанного однорангового хранилища и его destroy(), — эти страницы его не описывают.
Диалоговые окна выбора файлов
Импорт и экспорт проходят через подключаемые колбэки, поэтому хост без браузерного окна выбора файла — например, webview в IDE — может предоставить собственное.
Эти колбэки несимметричны: экспорт передает вам готовый файл, а импорт лишь запрашивает его, и содержимое в редактор вы загружаете сами.
Начиная с версии 4.2.0 кнопка Import CSV на вкладке «Словарь» — единственный импорт, который никогда не вызывает колбэк импорта, в поле type которого нет значения для CSV. Она всегда открывает собственное окно выбора файла браузера для файлов .csv — см. Импорт и экспорт CSV.
Поле op принимает значение set или diff — запрос diff передается в setDiffValue(), каким бы ни было поле type. В остальных случаях поле type определяет метод, а поле accept содержит расширения этого типа, готовые для передачи окну выбора файла хоста.
Начиная с версии 4.0.0 запрос set содержит mode: 'append', если пользователь выбрал Импорт с добавлением, и не содержит mode при обычном Импорте. Передавайте его дальше: колбэк, который его отбрасывает, заменяет диаграмму, в которую пользователь хотел добавить содержимое.
type | accept | Метод |
|---|---|---|
json | .json | editor.setSchemaJSON(text, { mode }) |
sql | .sql | editor.setSchemaSQL(text, { placement: 'auto', mode }) |
graphql | .graphql,.gql,.graphqls | editor.setSchemaGraphQL(text, { placement: 'auto', mode }) |
dbml | .dbml | editor.setSchemaDBML(text, { placement: 'auto', mode }) |
aml | .aml | editor.setSchemaAML(text, { placement: 'auto', mode }) |
Параметр placement: 'auto' располагает таблицы по их связям до того, как они появятся на холсте, как это делает собственный Импорт редактора, и заставляет вызов возвращать Promise. Без него таблицы сразу появляются рядами — см. setSchemaSQL и setSchemaJSON.
import { setExportFileCallback, setImportFileCallback } from '@dineug/erd-editor';
setExportFileCallback((blob, { fileName }) => host.writeFile(fileName, blob));
setImportFileCallback(async ({ type, op, accept, mode }) => {
const text = await host.pickFile(accept);
if (op === 'diff') {
editor.setDiffValue(text);
} else if (type === 'json') {
editor.setSchemaJSON(text, { mode });
} else if (type === 'sql') {
editor.setSchemaSQL(text, { placement: 'auto', mode });
} else if (type === 'graphql') {
editor.setSchemaGraphQL(text, { placement: 'auto', mode });
} else if (type === 'dbml') {
editor.setSchemaDBML(text, { placement: 'auto', mode });
} else if (type === 'aml') {
editor.setSchemaAML(text, { placement: 'auto', mode });
}
});
Предусмотрите отдельную ветку для каждого обрабатываемого значения type, а остальные игнорируйте.
Замещающий вызов setSchemaJSON(), как и присваивание значения свойству value, очищает документ перед разбором, поэтому передача туда данных, не являющихся документом .erd.json, — через универсальную ветку else или потому, что добавленный позже type не нашел своей ветки, — оставляет диаграмму пустой вместо того, чтобы что-либо импортировать.
Имя файла fileName, которое генерирует редактор, имеет вид <database name>-<timestamp> с добавленным расширением файла, где метка времени — это локальное время в формате yyyy-MM-dd'T'HH_mm_ss. Если имя базы данных пустое, используется значение unnamed. В имени CSV-файла Словаря перед расширением указывается его лист, например <database name>-<timestamp>-words.csv.
Колбэк экспорта получает следующие файлы. Начиная с версии 4.0.0 среди них есть SVG и файлы Генератора кода, а файл .sql поступает от кнопки Save file на вкладке «Схема SQL», а не напрямую из меню Export. Начиная с версии 4.2.0 среди них есть и CSV-файл вкладки «Словарь». toImage() не вызывает ни один из колбэков: он возвращает изображение вам.
| Файл | Расширение | type объекта Blob |
|---|---|---|
| Экспорт JSON | .erd.json | application/json |
Кнопка Save file на вкладке «Схема SQL», сохраняющая отображаемый на вкладке текст, — см. Схема SQL | .sql | нет |
| Окно «Экспорт изображения» | .png или .svg | image/png или image/svg+xml |
Кнопка Save file на вкладке «Генератор кода» — см. Генератор кода | Расширение языка: .cs, .go, .java, .kt, .php, .rs, .scala, .swift, .ts, .py, .aml, .dbml, .graphql, .json или .mmd | нет |
Кнопка Export CSV на вкладке «Словарь», сохраняющая все строки открытого листа независимо от того, какие строки показывает его поиск, — см. Импорт и экспорт CSV | .csv | text/csv |
Хосту, который выбирает обработчик по расширению, нужен обработчик для каждого из них.
Если колбэки не заданы, редактор использует стандартное поведение браузера для скачивания и выбора файлов. Чтобы вернуться к нему, передайте null.
Поддержка браузеров
Chrome 91+, Edge 94+, Firefox 93+, Safari 16.4+ — базовый уровень ES2022, на который рассчитаны опубликованные сборки. Полифилы в сборку не входят. Если нужна поддержка более старых браузеров, добавьте собственные.
Переход с версии 4.x
Версия 5.0.0 — мажорная. При переводе страницы с 4.x проверьте каждый из следующих пунктов:
-
import '@dineug/erd-editor'больше не определяет<erd-editor>. Вместо этого импортируйте@dineug/erd-editor/erd-editor.jsради его эффекта или вызовитеdefineErdEditor(), а именованные импорты из корня оставьте как есть. TypeScript не отмечает страницу, оставленную на голом импорте, поскольку объявления корня по-прежнему называют тег вHTMLElementTagNameMap, но создаваемый ею элемент — обычныйHTMLElement, поэтому первый же вызов его метода выбрасываетTypeError— см. Регистрация элементов.-import '@dineug/erd-editor';+import '@dineug/erd-editor/erd-editor.js';import { setExportFileCallback } from '@dineug/erd-editor'; -
То же относится к CDN:
https://esm.run/@dineug/erd-editorтеперь отдает корень и ничего не определяет, поэтому импортируйтеhttps://esm.run/@dineug/erd-editor@5.1.0/erd-editor.js. URL jsDelivr и unpkg с одним лишь именем пакета по-прежнему отдают сборку для тега script, которая определяет<erd-editor>, как и раньше. URL без версии теперь отдает последнюю версию 5.x; чтобы остаться на 4.x, закрепите версию@4.2.0— см. CDN и Тег script. -
Корень ничего не определяет, но ему по-прежнему нужен DOM, поэтому при серверном рендеринге именованный импорт из него, например
setExportFileCallback, остается в коде только для клиента рядом с точкой входа элемента — см. Серверный рендеринг. -
В
window.ErdEditorпоявляютсяErdEditorElementиdefineErdEditor. Сборка просмотрщика для тега script помещаетErdViewerElementиdefineErdViewerвwindow.ErdViewer, и ни один из глобальных объектов не содержитtoImage. -
Редактор с
readonlyоткрывается как читатель. Его шесть вкладок, Обозреватель, быстрый поиск и присутствие остаются, а каждый элемент управления, который изменял бы диаграмму, исчезает, а не отключается: панель инструментов показывает название СУБД текстом, вкладка «Настройки» показывает свои настройки с отключенными элементами управления под меткойRead only, а плавающая панель инструментов сохраняет только масштаб, режим отображения имен, режим дзен и компас, так чтоHandиSelectисчезают, а перетаскивание перемещает холст. Нажатие ничего не выделяет: единственное выделение — это контур, который переход из Обозревателя или быстрого поиска рисует вокруг того, к чему он ведет, и его снимает короткий щелчок без движения, а сочетания клавиш выделения всего ничего не выделяют. Включениеreadonlyзавершает все, что было открыто, например выделение, инструмент «Рука», редактор ячейки, перетаскивание,Map Columns, предварительный просмотрForceв Автоматическом размещении и Time Travel, и сохраняет прокрутку, масштаб, вкладку и режим отображения имен — см. readonly. -
Настройки, которые меняет читатель
readonly, остаются на экране этого редактора, какими бы ни были их блокировки: прокрутка и масштаб, вкладка, режим отображения имен, Параметры вида, СУБД, а также язык, стили имен и тип кавычек Генератора кода.value,runtimeValueи экспорт JSON сохраняют собственные настройки документа, до которых изменения читателя в 4.x могли доходить, аgetSharedStore()не отправляет их остальным редакторам.getSchemaSQL()без указания СУБД записывает ту, которую выбрал читатель. Выключениеreadonlyвозвращает СУБД, настройки кода и Параметры вида к тому, что этот редактор показывал бы, если бы читатель ничего не менял, а прокрутку, масштаб, вкладку и режим отображения имен оставляет там, где их оставил читатель. -
Строка
Recalculation table widthна вкладке «Настройки» исчезла. Загрузка и вставка по-прежнему подгоняют ширину каждой таблицы под ее текст. -
В Vite 8 уберите
exclude: ['@dineug/erd-editor']изoptimizeDeps, который по-прежнему нужен лишь Vite 7 и более ранним, и оставьтеincludeдля ELK — см. Vite.
Переход с версии 3.x
Версия 4.0.0 — мажорная. При переводе страницы с 3.x проверьте каждый из следующих пунктов, а затем пункты раздела Переход с версии 4.x для версии 5.0.0:
- Свойство
editor.value, свойствоvalueреплики и значениеvalue, которое передает ее событиеchange, имеют форму хранения, как в файле: без удаленных сущностей, измеренных ширин, порядка наложения и точек привязки связей. Продолжайте сохранятьvalue, а эти данные читайте изruntimeValue; метки времени сущностей (meta) удалены полностью. Инициализируйте соавтора или реплику, которые подключаются к уже идущему сеансу, изruntimeValueработающего участника, а не изvalueили файла, и никогда не сохраняйтеruntimeValue— см. value и runtimeValue. - Блокировки настроек заменяют
Save Scroll InformationиSave Zoom Information. В новом документе и в любом документе, сохраненном до версии4.0.0, включены все блокировки, поэтому прокрутка, масштабирование, переключение вкладки или изменение языка Генератора кода, стиля имен либо типа кавычек оставляют свойствоvalueпрежним, и событиеchangeне возникает. Странице, которая сохраняла вид через событиеchange, нужно разблокировать строкуViewport(иCanvas Typeдля вкладки) на вкладке «Настройки» либо использовать документ, в котором полеsettings.lockSettingsоставляет эти биты сброшенными, — см. Блокировка. - В объекте
settingsбольше нет полейwidth,height,scrollTop,scrollLeft,relationshipOptimizationиignoreSaveSettings, а константыSaveSettingTypeудалены. Полеsettings.lockSettingsс битамиLockSettingTypeзаменяет полеignoreSaveSettings, которое версии4.0.0или новее не читают и не записывают, — см. Settings. - JSON Schema, которую каждый файл указывает в поле
$schema, теперь описывает только форму хранения и является закрытой: она отклоняет файл, сохраненный более ранней версией, пока его не перезапишет сохранение в версии4.0.0или новее. - Сборка мусора документа удалена вместе с ее воркером, поэтому удаленная сущность остается в
runtimeValueдо следующего открытия документа из файла. Остаются три общих воркера — см. Web Worker. - Держите все редакторы и реплики в общем сеансе на версии
4.0.0или новее. Более ранняя версия игнорирует новые типы действий: действия групп таблиц, окна «Сопоставить столбцы», блокировок и скриптов Схемы SQL — см. Разные версии в одном сеансе. - Колбэк импорта получает
mode: 'append'для Импорта с добавлением, и колбэк должен передать его дальше. Колбэк экспорта теперь также получает файлы.svgи файлы Генератора кода, аExport▸Schema SQLоткрывает вкладку «Схема SQL» вместо сохранения, поэтому файл.sqlпоступает только от кнопкиSave fileна этой вкладке — см. Диалоговые окна выбора файлов. - Клавиши
DeleteиBackspaceпривязаны к новой командеremoveSelection. Пока фокус находится в редакторе вне текстового поля, стандартное действие клавиши подавляется на всех вкладках, а на вкладке ERD выделение удаляется. Команда добавлена вKeyBindingNameиKeyBindingMap, а вызовsetKeyBindingMap({ removeSelection: [] })оставляет обе клавиши странице — см. setKeyBindingMap. - Свойство
ThemeOptions.appearanceтакже принимает'system'— вариантSystemконструктора темы, который устанавливается при включенииsystemDarkMode. СобытиеchangePresetThemeсообщает'system', пока выбран этот вариант, поэтому сохраняйте значение как есть и передавайте его обратно вsetPresetTheme. При включенномsystemDarkModeвызовsetPresetTheme()со значением'light'или'dark'теперь остается в силе, а не перезаписывается следующим изменением в ОС — см. systemDarkMode и changePresetTheme. - Пакет
@dineug/erd-editor-mcpверсии1.0.0или новее, расширение VS Code версии4.0.0или новее и плагины для Obsidian и JetBrains версии1.0.0или новее используют протокол хаба версии 2. Сервер версии1.0.0или новее и более ранняя версия редактора, обслуживающая агентов, либо более ранний сервер и один из этих редакторов отклоняют друг друга с ошибкойprotocolMismatch, указывая, какую сторону нужно обновить, — см. Обновление. - URL CDN без версии отдает последнюю версию, с
5.0.0— 5.x. Чтобы остаться на 3.x, закрепите версию@3.10.0— см. CDN.