Skip to content

feat(editorjs): add batteries-included bundle package and make core headless#183

Open
gohabereg wants to merge 6 commits into
mainfrom
feat/editorjs-bundle-package
Open

feat(editorjs): add batteries-included bundle package and make core headless#183
gohabereg wants to merge 6 commits into
mainfrom
feat/editorjs-bundle-package

Conversation

@gohabereg

Copy link
Copy Markdown
Member

Why

Default tools, plugins, infra (DOM adapter, collaboration), and UI were hardcoded into Core's constructor, so @editorjs/core couldn't be consumed as a pure engine and there was no batteries-included package a v2 user could drop in.

What Changes

  • New package @editorjs/editorjs (packages/editorjs): a batteries-included entry point whose default export EditorJS composes Core + DOMAdapters + CollaborationManager + default tools (paragraph, bold, italic, link) + plugins (clipboard, shortcuts) + UI. It auto-initializes in the constructor and exposes an isReady promise, and honors a v2-style config.tools map merged over the defaults with override-by-name.
  • Core is now headless (BREAKING): the constructor no longer registers any default tools/plugins/infra/UI. initialize() fails loudly — it throws when no rendering adapter is registered or the defaultBlock tool is missing, and re-throws init failures instead of swallowing them with console.error.
  • ShortcutsPlugin moved out of @editorjs/core into @editorjs/editorjs.
  • Dependency alias: the published @editorjs/editorjs v2 dep is aliased as editorjs-v2 (npm:@editorjs/editorjs@…) in core, sdk, ui, tools/paragraph to free the package name. Non-behavioral; import specifiers only.
  • Playground now consumes @editorjs/editorjs instead of wiring Core + UI by hand.

Verification

  • Full workspace build, lint, and tests pass (incl. 6 new bundle tests covering override-by-name and isReady resolve/reject).
  • Playground verified end-to-end in-browser: renders the configured paragraphs, typing updates the model, and the CMD+B inline toolbar fires — all through the bundle.

Specs

Implemented via OpenSpec change add-editorjs-bundle-package (archived in this PR). Main specs updated: core (headless + fail-loud scenarios; shortcuts requirement removed) and new editorjs-bundle capability.

@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown

Unit Tests

Package Coverage Delta
@editorjs/core 90.47% 0% ⚪️
@editorjs/clipboard-plugin 66.66% 0% ⚪️
@editorjs/collaboration-manager 85.81% 0% ⚪️
@editorjs/dom-adapters 86.95% 0% ⚪️
@editorjs/ot-server 20% 0% ⚪️
@editorjs/model N/A N/A
@editorjs/editorjs 100% N/A

Mutation Tests

Package Mutation score Dashboard URL
@editorjs/clipboard-plugin No files to mutate found.
@editorjs/dom-adapters No files to mutate found.
@editorjs/collaboration-manager No files to mutate found.
@editorjs/core 38.65% 🔴 Dashboard

…eadless

Introduce `@editorjs/editorjs`, a batteries-included entry point that composes
`@editorjs/core` with the default DOM adapter, collaboration, tools, plugins,
and UI, auto-initializes in its constructor, and exposes an `isReady` promise.
It honors a v2-style `config.tools` map merged over the defaults with
override-by-name.

To support it, `Core` becomes a headless engine:
- Remove the hardcoded default tool/plugin/infra `use()` calls from the
  constructor; drop the corresponding dependencies.
- `initialize()` now fails loudly: it throws when no rendering adapter is
  registered or the `defaultBlock` tool is missing, and re-throws init
  failures instead of swallowing them.

`ShortcutsPlugin` stays in `@editorjs/core` (no longer auto-registered); its
relocation is handled by a separate change.

Free the `@editorjs/editorjs` package name by aliasing the published v2
dependency as `editorjs-v2` (`npm:@editorjs/editorjs@…`) across core, sdk, ui,
and tools/paragraph.

The playground now consumes `@editorjs/editorjs` instead of wiring `Core` and
UI by hand.

Specs updated via OpenSpec change `add-editorjs-bundle-package` (archived).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@gohabereg
gohabereg force-pushed the feat/editorjs-bundle-package branch from 433933c to 182b01d Compare July 22, 2026 21:29
gohabereg and others added 4 commits July 22, 2026 22:46
…gration test

Core no longer depends on `@editorjs/dom-adapters`, so its dist is not built
in CI when checking `@editorjs/core`. The leftover `jest.unstable_mockModule`
call still resolved the specifier, failing the suite (and the Stryker dry run)
with "Cannot find module '@editorjs/dom-adapters'".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Runs lint, build and unit tests for the new bundle package on pull requests
and merge groups, mirroring the other package workflows. Mutation tests are
disabled since the package has no Stryker config yet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`tsc --build` only produces output for TypeScript project references, so
`@editorjs/ui` — which is bundled by vite — had no `dist/ui.js` after building
`@editorjs/editorjs` from a clean checkout. Jest then failed to resolve
`@editorjs/ui` in the bundle test.

Build dependencies first via `yarn workspaces foreach`, mirroring how the
playground package builds its own dependency graph.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new batteries-included @editorjs/editorjs bundle package and refactors @editorjs/core into a truly headless engine by removing hardcoded defaults and adding fail-loud precondition checks. It also aliases the legacy v2 @editorjs/editorjs dependency as editorjs-v2 across the workspace to free the @editorjs/editorjs name, and updates the playground to consume the new bundle.

Changes:

  • Add packages/editorjs (@editorjs/editorjs) that composes Core + DOM adapter + collaboration + default tools/plugins + UI and auto-initializes with isReady.
  • Make @editorjs/core headless (no default use() registrations) and add synchronous initialization precondition validation.
  • Alias v2 @editorjs/editorjs as editorjs-v2 and update imports/dependencies; switch the playground to the new bundle.

Reviewed changes

Copilot reviewed 46 out of 47 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
yarn.lock Updates workspace lockfile for new package and editorjs-v2 aliasing.
packages/ui/package.json Replaces direct v2 @editorjs/editorjs dependency with editorjs-v2 alias.
packages/tools/paragraph/src/index.ts Updates v2 type imports to use editorjs-v2.
packages/tools/paragraph/package.json Swaps v2 @editorjs/editorjs dependency for editorjs-v2 alias.
packages/sdk/src/tools/facades/BlockTuneFacade.ts Updates v2 type imports to use editorjs-v2.
packages/sdk/src/tools/facades/BlockToolFacade.ts Updates v2 type imports to use editorjs-v2.
packages/sdk/src/tools/facades/BaseToolFacade.ts Updates v2 type imports to use editorjs-v2.
packages/sdk/src/entities/InlineTool.ts Updates v2 type imports to use editorjs-v2.
packages/sdk/src/entities/EventBus/events/core/BlockAddedCoreEvent.ts Updates v2 type imports to use editorjs-v2.
packages/sdk/src/entities/Config.ts Updates EditorConfig type source to editorjs-v2.
packages/sdk/src/entities/BlockTune.ts Updates v2 type imports to use editorjs-v2.
packages/sdk/src/entities/BlockTool.ts Updates v2 type imports to use editorjs-v2.
packages/sdk/src/entities/BaseTool.ts Updates v2 type imports to use editorjs-v2.
packages/sdk/src/api/BlocksAPI.ts Updates v2 type imports to use editorjs-v2.
packages/sdk/package.json Replaces v2 @editorjs/editorjs dependency with editorjs-v2 alias.
packages/playground/src/App.vue Switches from manual Core+UI wiring to new EditorJS() bundle usage.
packages/playground/package.json Simplifies deps by depending on @editorjs/editorjs bundle.
packages/editorjs/tsconfig.json Adds TS project config for new bundle package.
packages/editorjs/tsconfig.eslint.json Adds ESLint TS project config for the new package.
packages/editorjs/tsconfig.build.json Adds build-specific TS project config for the new package.
packages/editorjs/src/mergeTools.ts Adds override-by-name merge helper for default + user tool constructors.
packages/editorjs/src/mergeTools.spec.ts Adds unit tests for tool merging semantics.
packages/editorjs/src/index.ts Implements EditorJS bundle class composition + isReady.
packages/editorjs/src/index.spec.ts Adds bundle tests for composition and isReady resolve/reject behavior.
packages/editorjs/package.json Defines the new @editorjs/editorjs workspace package and scripts.
packages/editorjs/jest.config.ts Adds Jest config for new package tests (ESM + TS).
packages/editorjs/eslint.config.mjs Adds ESLint config for the new package.
packages/editorjs/.gitignore Adds package-local ignores for build/test artifacts.
packages/core/tsconfig.json Removes build references to defaults now moved out of core.
packages/core/tsconfig.build.json Removes build references to defaults now moved out of core.
packages/core/src/utils/composeDataFromVersion2.ts Updates v2 type imports to use editorjs-v2.
packages/core/src/tools/ToolsManager.ts Updates v2 type imports to use editorjs-v2.
packages/core/src/tools/ToolsFactory.ts Updates v2 type imports to use editorjs-v2.
packages/core/src/index.ts Removes default registrations and adds precondition validation + rethrow behavior.
packages/core/src/components/BlockRenderer.ts Switches v2 imports to editorjs-v2.
packages/core/src/components/BlockManager.ts Switches v2 imports to editorjs-v2.
packages/core/src/api/BlocksAPI.integration.spec.ts Adjusts test scaffolding/mocks in response to refactors.
packages/core/package.json Drops baked-in defaults; adds editorjs-v2 alias dependency.
openspec/specs/editorjs-bundle/spec.md Adds main spec for the new bundle capability.
openspec/specs/core/spec.md Updates core spec to reflect headless + fail-loud initialization behavior.
openspec/changes/archive/2026-07-22-add-editorjs-bundle-package/tasks.md Archives change tasks and implementation checklist.
openspec/changes/archive/2026-07-22-add-editorjs-bundle-package/specs/editorjs-bundle/spec.md Archives delta spec for new bundle capability.
openspec/changes/archive/2026-07-22-add-editorjs-bundle-package/specs/core/spec.md Archives delta spec for core headless behavior changes.
openspec/changes/archive/2026-07-22-add-editorjs-bundle-package/proposal.md Archives the change proposal for traceability.
openspec/changes/archive/2026-07-22-add-editorjs-bundle-package/design.md Archives the design decisions and trade-offs.
openspec/changes/archive/2026-07-22-add-editorjs-bundle-package/.openspec.yaml Adds archived change metadata for OpenSpec workflow.
.github/workflows/editorjs.yml Adds CI workflow to run package-check for @editorjs/editorjs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/core/src/index.ts Outdated
Comment on lines +178 to +182
} catch (error) {
console.error('Editor.js initialization failed', error);

throw error;
}
Comment on lines 11 to 14
import { TOKENS } from '../tokens.js';
import ToolsManager from '../tools/ToolsManager.js';
import { BlockAPI } from '@editorjs/editorjs';
import { BlockAPI } from 'editorjs-v2';
import {
Comment on lines 16 to 20
import { TOKENS } from '../tokens.js';
import ToolsManager from '../tools/ToolsManager.js';
import { BlockToolData } from '@editorjs/editorjs';
import { BlockToolData } from 'editorjs-v2';
import { CoreConfigValidated, EventBus } from '@editorjs/sdk';

Comment on lines 62 to 65
});

core
.use(EditorjsUI)
.use(BlocksUI)
.use(InlineToolbarUI)
.use(ToolbarUI)
.use(ToolboxUI)
.initialize();
void editor.isReady;
});
Comment on lines +22 to +26
if (userTools !== undefined) {
for (const [name, tool] of Object.entries(userTools)) {
merged.set(name, tool);
}
}
Comment on lines +3 to +5
## Purpose
TBD - created by archiving change add-editorjs-bundle-package. Update Purpose after archive.
## Requirements
- Core.initialize() no longer logs to console.error before re-throwing
  (dead try/catch removed)
- BlockRenderer/BlockManager import editorjs-v2 types with `import type`
  instead of pulling it in as a runtime dependency
- Playground attaches a .catch() to editor.isReady instead of discarding
  the promise, avoiding an unhandled rejection
- mergeTools() now throws when a config.tools key doesn't match the
  tool's static name, since Core looks up tools by name, not map key
- editorjs-bundle spec: replaced TBD Purpose and documented the new
  fail-loud mismatch scenario

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants