---
title: "Dependency rules"
description: "Which layer of @skaile/forge-editor may import which, and how the bundle isolation check enforces it."
canonical_url: "https://skaile-ai.github.io/forge-editor/reference/dependency-rules"
---
# Dependency rules

> Which layer of @skaile/forge-editor may import which, and how the bundle isolation check enforces it.

Imports inside `packages/editor/src` follow one direction; the entry checks enforce them on the emitted bundles.

<table>
<thead>
  <tr>
    <th>
      Layer
    </th>
    
    <th>
      May import
    </th>
    
    <th>
      Must not import
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        core
      </code>
      
      , <code>
        settings
      </code>
    </td>
    
    <td>
      each other, external packages other than <code>
        vue
      </code>
      
      , <code>
        @tiptap/vue-3
      </code>
      
      , <code>
        @nuxt/ui
      </code>
      
      , <code>
        react
      </code>
      
      , <code>
        sonner
      </code>
    </td>
    
    <td>
      those, <code>
        vue/
      </code>
      
      , <code>
        react/
      </code>
      
      , any feature, integration, <code>
        outline
      </code>
      
      , <code>
        tree
      </code>
      
      , preset, <code>
        nuxt
      </code>
      
      , <code>
        server
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        vue
      </code>
      
       (<code>
        src/vue
      </code>
      
      : <code>
        EditorSurface
      </code>
      
      , <code>
        EditorToolbar
      </code>
      
      , settings components, <code>
        createEditor
      </code>
      
      , <code>
        useEditorUi
      </code>
      
      , <code>
        vueSuggestionRenderer
      </code>
      
      , the queued notifier; <code>
        SimpleEditor
      </code>
      
      /<code>
        AdvancedEditor
      </code>
      
       also the preset they mount)
    </td>
    
    <td>
      <code>
        core
      </code>
      
      , <code>
        settings
      </code>
      
      , Vue, <code>
        @tiptap/vue-3
      </code>
      
      , Nuxt UI
    </td>
    
    <td>
      <code>
        react
      </code>
      
      , <code>
        nuxt
      </code>
      
      , <code>
        server
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        react
      </code>
      
       (<code>
        src/react
      </code>
      
      : <code>
        EditorSurface
      </code>
      
      , <code>
        EditorToolbar
      </code>
      
      , settings components, <code>
        EditorContextProvider
      </code>
      
      , <code>
        reactSuggestionRenderer
      </code>
      
      , <code>
        reactNotifier
      </code>
      
      , vendored shadcn primitives in <code>
        ui/
      </code>
      
      ; <code>
        SimpleEditor
      </code>
      
      /<code>
        AdvancedEditor
      </code>
      
       also the preset they mount)
    </td>
    
    <td>
      <code>
        core
      </code>
      
      , <code>
        settings
      </code>
      
      , React, <code>
        @tiptap/react
      </code>
      
      , Radix, sonner, <code>
        @iconify/react
      </code>
      
      , framework-free features and presets
    </td>
    
    <td>
      <code>
        vue
      </code>
      
      , <code>
        @tiptap/vue-3
      </code>
      
      , Nuxt UI, <code>
        nuxt
      </code>
      
      , <code>
        server
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        outline
      </code>
      
      , <code>
        outline/vue
      </code>
      
      , <code>
        outline/react
      </code>
    </td>
    
    <td>
      <code>
        core
      </code>
      
       (and its layer)
    </td>
    
    <td>
      <code>
        tree
      </code>
      
      , composites, any feature
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        search
      </code>
      
      , <code>
        search/vue
      </code>
      
      , <code>
        search/react
      </code>
    </td>
    
    <td>
      <code>
        core
      </code>
      
       (and its layer)
    </td>
    
    <td>
      <code>
        tree
      </code>
      
      , <code>
        outline
      </code>
      
      , composites, any feature
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        change-sets
      </code>
      
      , <code>
        change-sets/vue
      </code>
      
      , <code>
        change-sets/react
      </code>
    </td>
    
    <td>
      <code>
        core
      </code>
      
       (and its layer)
    </td>
    
    <td>
      <code>
        tree
      </code>
      
      , <code>
        outline
      </code>
      
      , <code>
        search
      </code>
      
      , composites, any feature
    </td>
  </tr>
  
  <tr>
    <td>
      features (<code>
        media
      </code>
      
      , <code>
        mentions
      </code>
      
      , <code>
        transcript
      </code>
      
      , <code>
        authors
      </code>
      
      , <code>
        comments
      </code>
      
      , <code>
        composites
      </code>
      
      , <code>
        ai
      </code>
      
      , <code>
        collab
      </code>
      
      , <code>
        block-ui
      </code>
      
      , <code>
        themes
      </code>
      
      ): <code>
        features/<x>/{index,feature,model…}.ts
      </code>
    </td>
    
    <td>
      <code>
        core
      </code>
      
      , <code>
        settings
      </code>
      
      , their own <code>
        schema
      </code>
      
      /<code>
        protocol
      </code>
      
      ; no UI framework
    </td>
    
    <td>
      another feature (by implementation), integrations, <code>
        tree
      </code>
      
      , <code>
        vue
      </code>
      
      , <code>
        react
      </code>
      
      , <code>
        nuxt
      </code>
      
      , <code>
        server
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        transfer
      </code>
      
       (<code>
        features/transfer
      </code>
      
      : the block drop target, its menu, <code>
        copyTransform
      </code>
      
      , <code>
        BlockTransform
      </code>
      
      /<code>
        TransferEnv
      </code>
      
      , the payload plumbing)
    </td>
    
    <td>
      <code>
        core
      </code>
      
       and the <code>
        composites/schema
      </code>
      
       entry
    </td>
    
    <td>
      any other feature by implementation, integrations, <code>
        tree
      </code>
      
      , a UI framework in its framework-free files. Its AI transforms (<code>
        summaryTransform
      </code>
      
      , <code>
        bulletsTransform
      </code>
      
       and their tasks) live in <code>
        integrations/composite-ai
      </code>
      
      ; <code>
        composeEditor
      </code>
      
       (a preset) adds them to the transfer row when <code>
        ai
      </code>
      
       is on
    </td>
  </tr>
  
  <tr>
    <td>
      feature bindings (<code>
        features/<x>/vue.ts
      </code>
      
       + <code>
        vue/
      </code>
      
       components, <code>
        features/<x>/react.ts
      </code>
      
       + <code>
        react/
      </code>
      
       components)
    </td>
    
    <td>
      the feature's framework-free files, <code>
        core
      </code>
      
      , <code>
        settings
      </code>
      
      , and that framework's layer (<code>
        vue
      </code>
      
       or <code>
        react
      </code>
      
      )
    </td>
    
    <td>
      the other framework, other features' implementations, <code>
        nuxt
      </code>
      
      , <code>
        server
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      integrations
    </td>
    
    <td>
      the features they connect (framework-free feature entries, or only their schema)
    </td>
    
    <td>
      other integrations' internals, a UI framework, <code>
        nuxt
      </code>
      
      , <code>
        server
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        tree
      </code>
      
       (<code>
        index
      </code>
      
      , <code>
        tree-view-model
      </code>
      
      , <code>
        store
      </code>
      
      ; <code>
        vue.ts
      </code>
      
      ; <code>
        react.ts
      </code>
      
      )
    </td>
    
    <td>
      <code>
        core
      </code>
      
      , <code>
        outline
      </code>
      
      , <code>
        composites
      </code>
      
      , <code>
        media
      </code>
      
       (the bindings also their framework's layer)
    </td>
    
    <td>
      AI, collab, transcript, mentions, block-ui, integrations; the other framework
    </td>
  </tr>
  
  <tr>
    <td>
      presets (<code>
        presets/compose
      </code>
      
       framework-free; <code>
        vue/compose.ts
      </code>
      
      , <code>
        react/compose.ts
      </code>
      
       bind it)
    </td>
    
    <td>
      everything they compose
    </td>
    
    <td>
      <code>
        nuxt
      </code>
      
      , <code>
        server
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        adapters/direct-ai
      </code>
      
       (<code>
        ./adapters/direct-ai
      </code>
      
      , the browser-direct <code>
        EditorBackend['ai']
      </code>
      
      )
    </td>
    
    <td>
      <code>
        core
      </code>
      
       (<code>
        BackendError
      </code>
      
      , backend types), <code>
        settings
      </code>
      
       values, the client-safe protocols <code>
        features/ai/protocol
      </code>
      
       and <code>
        integrations/transcript-ai/protocol
      </code>
      
      , the platform <code>
        fetch
      </code>
    </td>
    
    <td>
      <code>
        server
      </code>
      
      , the AI SDK (<code>
        ai
      </code>
      
      , <code>
        @ai-sdk/*
      </code>
      
      ), an HTTP client, <code>
        vue
      </code>
      
      , <code>
        react
      </code>
      
      , <code>
        nuxt
      </code>
      
      , other adapters
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        nuxt
      </code>
      
      , <code>
        server
      </code>
    </td>
    
    <td>
      Nitro/Nuxt, framework-free schema entries, the client-safe <code>
        features/ai/protocol
      </code>
      
      ; the composite modules of the exception below
    </td>
    
    <td>
      browser components, any other feature implementation
    </td>
  </tr>
</tbody>
</table>

**Exception: server imports framework-free composite modules.** The server parses and converts Markdown and projects Blocks without an editor, so it needs more of `features/composites` than its schema entry. `server/document-mutator.ts` imports `block-types` and `convert`, `server/markdown-blocks.ts` imports `block-types`, `fences` and `reference-text`, `server/block-index.ts` imports `block-types` and `fences`, `server/workspace-tools.ts` imports the `block-types` type, and `server/stored-content.ts` imports `legacy` (the older precedent). These modules and the composite modules they pull in (`nodes`, `heading-composites`, `meta-keys`, `reference`) import only `core`, `settings`, `i18n`, TipTap's framework-free packages (`@tiptap/core`, `@tiptap/pm`, `@tiptap/suggestion`) and each other, never Vue, React, the DOM or another feature. The exception covers exactly them; a server module that needs another composite module or another feature implementation extends it only by an edit here. (`server/extract.ts` also takes a type from `features/media/assets`; a type import carries no code into the server bundle.)

Simple and advanced bundles are separate: the `simple` bundle contains no feature implementation, integration, tree, AI SDK, Yjs, y-tiptap, Hocuspocus, Nuxt or server module; a feature fixture contains core, settings and that feature only. The `core-headless` fixture builds an editor from `/core` alone (`createEditorContext`, `coreContentFeature()`, `mentionsFeature()`) and fails on any `vue`, `@vue`, `@tiptap/vue-3`, `@nuxt/ui` or `react` module; the `headless-<x>` fixtures do the same for the framework-free entry of each feature, integration and the tree.

The React fixtures (`react-simple`, `<x>-react`, `tree-react`, `outline-react`, `advanced-react`) mount their React binding with its toolbar and fail on any `vue`, `@vue`, `@tiptap/vue-3`, `@nuxt/ui`, `src/vue` or `.vue` module; the Vue fixtures fail on `react-dom`, `sonner` and `src/react`. `advanced-react` mounts the complete `AdvancedEditor` (`/react/advanced`) and requires every feature and integration binding, so no `.vue` file can slip into the React bundle unnoticed.

Run `typecheck:editor`, `check:editor-entries` and `check:editor-composition` as described in [Commands](https://skaile-ai.github.io/forge-editor/reference/commands).

`check:editor-entries` collects the module IDs of every emitted chunk (including dynamic ones) and fails on a forbidden module, on a source module outside the fixture's allow-list, or on a missing required module. To check your own composition, add `packages/editor/checks/fixtures/<name>/` (an `index.html` plus `main.ts`/`main.tsx` that mounts the surface with its toolbar, so unused factories cannot be tree-shaken away) and one `FIXTURES` entry with `forbid`, `require` and `allowSource` patterns (and `plugins: 'react'` for a React fixture) in `packages/editor/checks/entries.ts`. Fixtures exist for `simple`, each feature (Vue, `-react` and `headless-` variants), each integration, `tree`, `tree-react`, `headless-tree`, `advanced`, `advanced-react`, the headless core (`core-headless`), the React simple editor (`react-simple`) and the Node schema.

## Bundle isolation proof

`bun run check:editor-entries` builds each fixture in `packages/editor/checks/fixtures/<name>/` as its own production Vite app, collects the module IDs of every emitted chunk and fails on forbidden modules (or on a missing required one, so exported factories cannot be tree-shaken away unnoticed). Last result for `simple`: 325 modules, JS 1082.5 kB (gzip 331.1 kB), CSS 194.5 kB (gzip 25.2 kB); for `tree`: 433 modules, JS 1314.5 kB (gzip 389.2 kB), CSS 197.6 kB (gzip 25.7 kB). The `code-only` and `code-only-react` fixtures prove the code surface carries CodeMirror and no ProseMirror or TipTap (and nothing of this package outside `src/code`), and the `markdown-vue` and `tables` fixtures prove the Markdown entries contain no CodeMirror. The check also bundles the advanced schema for Node and compares it with a snapshot (`checks/schema.ts`).


## Sitemap

See the full [sitemap](https://skaile-ai.github.io/forge-editor/sitemap.md) for all pages.
