@archie/devtools

中文文档
0.1.33发布于 2026/11/05UNLICENSEDTypeScriptESM + CJS近 30 天下载 1.3万

DevTools for Archie generated applications - Route synchronization and editor communication

原始使用文档
文档目录18 节
  1. Public API
  2. Usage
  3. 1. Configure the Vite plugin
  4. 2. Bootstrap the app runtime
  5. 3. Export the router
  6. Responsibilities
  7. Requirements
  8. Deploy order
  9. Identidad data-vid , NodeMeta, protocolo 1.x
  10. sourceHash por archivo
  11. data-vid en build de producción
  12. Apagar el design mode y sesión de arrange
  13. Local linking
  14. Development
  15. Release notes
  16. 0.1.9
  17. 0.1.8
  18. 0.1.5

@archie/devtools

Devtools runtime for Archie-generated applications.

Public API

This package exposes only two supported entrypoints:

  • @archie/devtools -> archieDevTools
  • @archie/devtools/client -> ArchieDevToolProvider, ArchieDevToolProviderProps

Everything else is internal implementation detail.

Usage

1. Configure the Vite plugin

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { archieDevTools } from '@archie/devtools';

export default defineConfig({
  plugins: [react(), archieDevTools()],
});

2. Bootstrap the app runtime

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { ArchieDevToolProvider } from '@archie/devtools/client';
import App, { router } from './App';

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <ArchieDevToolProvider router={router}>
      <App />
    </ArchieDevToolProvider>
  </StrictMode>,
);

3. Export the router

import { createBrowserRouter, RouterProvider } from 'react-router-dom';

export const router = createBrowserRouter([
  // routes
]);

export default function App() {
  return <RouterProvider router={router} />;
}

router is optional: omit it when another piece already announces the routes (e.g. the gv2 routes announcer) to mount only the inspector and DnD, without the route listener.

Responsibilities

  • archieDevTools() handles compile-time editor metadata and internal DnD scope injection.
  • ArchieDevToolProvider handles runtime bootstrap: DnD provider, route sync, sanitizer install, and inspector initialization.

Requirements

  • React 18+
  • React Router DOM 6.4+
  • Vite 5+

Deploy order

Changes to babel-plugin-editor-meta.ts's __editorMeta prop shape and inspector.standalone.js's meta-read paths have a load-bearing publish order — see docs/deploy-order.md.

Identidad data-vid, NodeMeta, protocolo 1.x

babelPluginEditorMeta ahora LEE data-vid (persistido en el source por el stamper de Genesis, /^[a-z0-9]{6,8}$/) en vez de derivar la identidad de file:line:col:componentName, que se invalida en cada escritura del source. Cuando el elemento tiene data-vid, __editorMeta.nodeId === __editorMeta.vid y el plugin también emite los campos de NodeMeta (@8base-archie/editor-protocol): dynamicType, isKitOrigin, isChrome, containerKind y, cuando aplica, lockReason. parentNodeId usa el vid del padre cuando existe.

sourceHash por archivo

Cada __editorMeta lleva sourceHash: sha256 en hex (64 caracteres) del texto exacto del archivo que compiló el plugin (state.file.code, UTF-8, sin normalizar BOM ni CRLF). Es el mismo algoritmo que legacyIdsSourceHash de acg (createHash('sha256').update(texto).digest('hex')). El inspector lo propaga en inspectorSource (ELEMENT_SELECTED y demás mensajes que lo llevan), en editorMeta y en cada entrada de editorMetaChain; el InspectorRef del modo diseño (inserted, moved, resized, sesiones de arrange) lo lleva como sourceHash. Un valor mal formado se omite. El host lo compara con legacyIdsSourceHash para negarse a resolver legacy ids cuando el DOM del preview viene de una revisión distinta a la del mapa. Los hosts antiguos ignoran el campo.

Sin data-vid, el plugin cae al direccionamiento legado SOLO cuando la opción allowLegacyIds es true (default en esta versión — transicional, se eliminará más adelante); con allowLegacyIds: false el elemento no se instrumenta.

El plugin nunca estampa data-vid en runtime (eso lo hace el stamper de Genesis). El plugin Vite (archieDevTools()) solo VALIDA: en dev, un JSXOpeningElement sin data-vid dispara un warning una vez por archivo (onMissingVid en babel-plugin-editor-meta.ts).

En runtime, node-key.ts resuelve la identidad con la prioridad meta.vid → data-vid del DOM → (legado) meta.nodeId → runtime:N, y fiber-bridge.ts expone getNodeMeta(el), que valida el NodeMeta ensamblado contra NodeMetaSchema antes de devolverlo. structural-policy.ts añade isNonDraggableNodeMeta, isNonDroppableNodeMeta y computeDroppableSet sobre esos mismos campos.

El handshake (INSPECTOR_SCRIPT_LOADED/CAPABILITIES_RESULT) añade editorProtocolVersion (el PROTOCOL_VERSION semver del paquete de contrato — un campo NUEVO, nunca superpuesto al protocolVersion numérico existente que archie-app ya compara estrictamente) y las capabilities vidIdentity, nodeMeta, refusals. ELEMENT_SELECTED añade vid y nodeMeta. El vocabulario REFUSED{code, cause, vid} está disponible (refuseNode en inspector.standalone.js) para cuando un host rechaza un gesto de arrastre/drop fuera de política.

Consume @8base-archie/editor-protocol como fuente única del contrato (Vid, NodeMeta, LockReason, los schemas Zod) — ver src/types/editor-meta.ts, que re-exporta esos tipos en vez de duplicarlos.

data-vid en build de producción

En vite build (command === 'build'), archieDevTools() elimina el atributo JSX data-vid del código generado — nada en el pipeline de deploy lo hace por su cuenta, y el atributo no aporta nada en runtime (la identidad sigue disponible vía __editorMeta.vid, que no se toca). Solo vite dev conserva data-vid sin cambios: este plugin corre en transform, así que vite preview sirve el dist/ ya construido por vite build y por lo tanto NO conserva data-vid — es el mismo build de producción, no un comando propio de este plugin. Opt-out explícito:

archieDevTools({ stripVidsInBuild: false })

Apagar el design mode y sesión de arrange

Al pasar de design mode ON a OFF (SET_EDITOR_MODE/SYNC_EDITOR_STATE, STOP_INSPECTION, Ctrl+Shift+D, crash del overlay o desmontaje) el runtime siempre vacía historial, cambios, drag externo, selección y canUndo/canRedo. Revertir además en el DOM los cambios de arrange sin guardar (moves, inserts, resizes, con las inversas del Discard del host) es opt-in del host, para no revertir lo ya guardado cuando el host es de una versión anterior:

  • SET_EDITOR_MODE acepta discardUnsavedArrangeOnDisable?: boolean. El inspector lo recuerda y lo reenvía al runtime en set-design-mode. Sin el campo (host legado) el DOM no se toca.
  • { type: 'ARRANGE_SESSION_SAVED' }, enviado por el host tras persistir la sesión, marca lo actual como guardado: el runtime olvida el historial sin tocar el DOM, emite un ARRANGE_SESSION_CHANGED vacío y activa el opt-in. Lo posterior vuelve a ser revertible.

Local linking

pnpm add file:../archie-devtools

After changing the library:

pnpm build

Development

pnpm test
pnpm typecheck

Tests follow a colocated-by-feature convention:

  • small modules keep *.test.ts(x) beside the source file
  • larger subsystems may use a local __tests__/ folder next to the feature
  • src/client/dnd/design-mode/__tests__/ is the reference pattern for multi-file feature coverage

Release notes

0.1.9

Fixes the arrange-session-changed index for a move onto a screen's own root (0.1.8's screen-root translation) so it matches the direct ELEMENT_MOVED event.

  • Screen-root move index. recordCommittedMove's after payload (the one serializeArrangeChange reads as event.payload.after.index for the arrange-session-changed change entry) carried the raw DOM-child index (command.to.index) even when the drop resolved to a screen-root target, instead of screenRootTarget.index — the position remapped to count only the screen's own root children. The direct element-moved runtime event already used the remapped index; only the session-change payload lagged. In the common case (no runtime-injected chrome interleaved among a screen's root children) the two indices coincide and nothing broke; the mismatch only surfaced when chrome sat between screen-root children and the drop slot was valid but not adjacent to the chrome node.

0.1.8

Fixes two related cases where a palette drop or an in-canvas move could land somewhere the host would later discard, instead of refusing the gesture up front:

  • Screen-root translation. A drop/insert that lands inside the app shell's children-slot container (kit-internal/chrome, containerKind: 'expression' — the element that renders {children}) between the screen's own root nodes now translates to a screen-root target instead of an ordinary container insert. The wire message (ELEMENT_INSERTED/ELEMENT_MOVED, and arrange-session-changed's per-change entries) carries screenRootFile (the screen's file) and an index remapped to the position among the screen's own root children — containerVid is unchanged, still the observed DOM container.
  • Text/expression containers, and every other chrome/kit-internal container. Any OTHER drop/insert into app-shell/kit chrome, or into a non-plain (containerKind !== 'plain') element such as a text-bearing <p>/<h3>/<span>, now refuses the gesture instead of completing — the engine falls back to the nearest enclosing PLAIN container under the pointer when one exists (e.g. the card <div> wrapping a paragraph), or refuses the gesture entirely when none does. This also fixes a gap where the external-palette-insert path (useExternalDragLoop.ts) never applied the NodeMeta-derived chrome/kit-origin/non-plain blocking at all, unlike the in-canvas move path — every palette drop onto text or app-shell chrome used to be accepted and silently discarded by the host afterward.

The screenRootFile wire field is additive: a host whose own @8base-archie/editor-protocol copy has not yet added DropMessage.screenRootFile simply ignores it. This package does not construct InsertOp/MoveOp itself, and does not import any @8base-archie/editor-protocol schema at runtime (only two plain constants, VID_ATTR/VID_PATTERN — everything else is import type), so it carries no dependency-version coupling to this change.

0.1.5

Treats a JSX comment ({/* ... */}) as a plain container, not an expression one — a container whose only non-element child is a comment now gets containerKind: 'plain' instead of 'expression'. This is coupled to archie-code-generation (acg) PR #416: acg's own container-kind handling must already treat {/* ... */} the same way before this version is deployed, or containers that used to agree between the two will disagree once 0.1.5 ships. No code-level gate enforces the pairing — deploy acg #416 first (or together with this version), not after.

版本与发布记录

@archie/devtools 共发布 80 个版本,首次发布于 2026/01/25;过去 12 个月发布了 80 个版本。

版本发布日期距今
0.1.33latest2026/11/053 天前
0.1.322026/11/043 天前
0.1.312026/11/035 天前
0.1.302026/11/026 天前
0.1.292026/10/309 天前
0.1.282026/10/2811 天前

其他发布通道:beta → 0.0.12-beta。

关于 @archie/devtools 的常见问题

@archie/devtools 是什么?

DevTools for Archie generated applications - Route synchronization and editor communication

如何安装 @archie/devtools?

在项目目录运行 npm install @archie/devtools,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(>=18.0.0)、react-dom(>=18.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@archie/devtools 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@archie/devtools 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@archie/devtools 可以商用吗?

@archie/devtools 使用 UNLICENSED 许可。作者声明为 UNLICENSED,即不授予公开使用许可(与公共领域的 Unlicense 不同)。使用前需获得作者授权。以上为概括,不构成法律意见,请以许可原文为准。

@archie/devtools 的下载量有多少?

根据 npm 官方下载统计,@archie/devtools 在 2026/10/07 – 2026/11/05 这 30 天内被下载 12,640 次,日均约 421 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@archie/devtools 还在维护吗?

最新版本 0.1.33 发布于 2026/11/05(3 天前);至今共发布 80 个版本,其中过去 12 个月发布了 80 个;首次发布于 2026/01/25。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。