Zudo Token Panel

Type to search...

to open search from anywhere

Frameworks Comparison

このページはまだ翻訳されていません。原文のまま表示しています。

Side-by-side wiring for Astro, Vite + React, Next.js, zfb, and zfb + Tailwind v4 — what changes, what stays the same.

The panel’s public surface is a single configurePanel({...}) call plus a Preact-rendered shell, so the wiring shape is the same across hosts. The only differences are who calls configurePanel, where the styles import lives, how the host interacts with view-transitions, and how the apply proxy is registered.

This page is the side-by-side overview. For full code, run any of the example apps linked at the bottom of each section.

Comparison

StepAstroVite + ReactNext.js (App Router)zfbzfb + Tailwind v4
Install packagepnpm add @takazudo/zudo-design-token-panel preactsamesamesamesame + tailwindcss
Define PanelConfigone TS file, host-sidesamesamesamesame
Mount the host<DesignTokenPanelHost> in layoutcall configurePanel(...) from entrycall configurePanel(...) from a 'use client' modulecall configurePanel(...) from a "use client" islandsame as zfb
Side-effect scriptvoid import('.../astro/host-adapter') next to the hostnot requirednot requiredvoid import('.../astro/host-adapter') in a "use client" islandsame as zfb
Styles importonce on the static graphonce on the static graphonce on the static graphonce on the static graphonce on the static graph; tokens also registered via @theme block
Tailwind integrationn/an/an/an/atokens registered into Tailwind namespaces via @theme; utility classes like text-body and p-hsp-md resolve to panel custom properties
View-transition lifecyclewired automatically by the host adapter when <ClientRouter /> is presentn/an/an/an/a
Apply proxy (dev)Vite dev server proxy configVite dev server proxy configNext.js rewriteszfb plugin’s devMiddleware hooksame as zfb
Apply-endpoint URLbare relative path (api/dev/apply)bare relative pathbare relative pathfull base-prefixed pathfull base-prefixed path
Apply-pipeline binspawn via concurrently in dev scriptspawn via concurrently in dev scriptspawn via concurrently in dev scriptspawn via concurrently in dev scriptspawn via concurrently in dev script

What stays the same:

  • The PanelConfig shape and all of its fields.
  • The console API — window.<consoleNamespace>.{show,hide,toggle}DesignPanel() — installed identically by every host.
  • Storage-key derivation under storagePrefix.
  • Apply-pipeline behaviour — POST to applyEndpoint is identical regardless of host.

What differs:

  • Whether you call configurePanel(...) (Vite, Next.js, zfb, zfb-tailwind) or the host adapter calls it for you (Astro).
  • Whether the page goes through Astro’s <ClientRouter /> view-transition lifecycle (only Astro).
  • How the apply proxy is registered: Vite/Next use built-in proxy or rewrite config; zfb and zfb-tailwind use a plugin’s devMiddleware hook.
  • Whether the applyEndpoint URL is bare (api/dev/apply) or base-prefixed (zfb and zfb-tailwind — see the zfb section below).
  • Whether tokens are also registered into Tailwind v4’s design-system namespaces via an @theme block (zfb-tailwind only).

Astro

The Astro entry handles mounting for you. Drop <DesignTokenPanelHost> into a shared layout, pair it with the host-adapter script tag, and import the styles. That’s the entire integration.

---
// src/layouts/Layout.astro
import { ClientRouter } from 'astro:transitions';
import { DesignTokenPanelHost } from '@takazudo/zudo-design-token-panel/astro';
import '@takazudo/zudo-design-token-panel/styles';
import { myPanelConfig } from '../lib/my-panel-config';
---

<!doctype html>
<html lang="en">
  <head>
    <ClientRouter />
  </head>
  <body>
    <slot />
    <DesignTokenPanelHost config={myPanelConfig} />
  </body>
</html>

<script>
  void import('@takazudo/zudo-design-token-panel/astro/host-adapter');
</script>

Worked example: <code>examples/astro</code>.

Vite + React

Vite hosts call configurePanel(...) themselves at app boot. The panel mounts as a Preact island — your React tree is untouched.

// src/main.tsx
import React from 'react';
import { createRoot } from 'react-dom/client';
import { configurePanel } from '@takazudo/zudo-design-token-panel';
import '@takazudo/zudo-design-token-panel/styles';
import { App } from './App';
import { myPanelConfig } from './lib/my-panel-config';

configurePanel(myPanelConfig);

createRoot(document.getElementById('root')!).render(<App />);

Open devtools, run window.myapp.toggleDesignPanel(), and the panel mounts.

Worked example: <code>examples/vite-react</code>.

Next.js (App Router)

Next.js needs a 'use client' boundary so configurePanel(...) runs in the browser. The cleanest shape is a tiny client component you mount in your root layout.

// app/_panel/install-panel.tsx
'use client';

import { useEffect } from 'react';
import { configurePanel } from '@takazudo/zudo-design-token-panel';
import '@takazudo/zudo-design-token-panel/styles';
import { myPanelConfig } from '@/lib/my-panel-config';

export function InstallPanel(): null {
  useEffect(() => {
    configurePanel(myPanelConfig);
  }, []);
  return null;
}
// app/layout.tsx
import { InstallPanel } from './_panel/install-panel';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <InstallPanel />
      </body>
    </html>
  );
}

📝 Why a useEffect?

configurePanel(...) is synchronous and idempotent at the same value. Calling it from useEffect avoids running it during a server render and lets you keep the install module otherwise inert. If you’d rather call it inline at module init, you can — just make sure the file is reachable only from the client bundle.

Worked example: <code>examples/next</code>.

zfb

zfb is a WIP build orchestrator the author is developing in a separate repo (Takazudo/zudo-front-builder). The zfb example shows how to drop the panel into a zfb project.

The integration shape is close to Astro: zfb uses Preact islands with a "use client" marker, so the @takazudo/zudo-design-token-panel/astro/host-adapter side-effect import is used the same way.

The key difference from the other three examples is how the dev-time apply proxy is wired up. Vite and Next.js have built-in proxy/rewrite config; zfb exposes a devMiddleware plugin hook instead. Register the proxy in a plugin:

// zfb.config.ts
import { defineConfig } from '@takazudo/zfb/config';

export default defineConfig({
  framework: 'preact',
  base: '/pj/zudo-design-token-panel/examples/zfb/',
  plugins: [
    { name: './plugins/dev-apply-proxy.mjs' },
  ],
});
// plugins/dev-apply-proxy.mjs
export default {
  name: 'dev-apply-proxy',
  devMiddleware(app) {
    // Forward POST requests at the FULL base-prefixed path to the bin server.
    app.post(
      '/pj/zudo-design-token-panel/examples/zfb/api/dev/apply',
      proxyHandler,
    );
  },
};

Apply-endpoint URL is base-prefixed. Unlike the other examples — which use the bare relative path api/dev/apply — the zfb demo must use the full base-prefixed URL:

/pj/zudo-design-token-panel/examples/zfb/api/dev/apply

After zfb fix #229, devMiddleware-registered paths are scoped under base, so the bare path resolves to 405. This is a configuration requirement for this deployment, not a zfb bug. See <code>examples/<wbr/>zfb/<wbr/>PROBE-<wbr/>REPORT.<wbr/>md</code> for the full rationale.

Worked example: <code>examples/zfb</code>.

zfb + Tailwind v4

The zfb + Tailwind v4 example extends the zfb integration with Tailwind CSS v4. It shares the same panel wiring and devMiddleware-based apply proxy as the plain zfb example. The distinguishing feature is that design tokens are also registered into Tailwind’s design-system namespaces via an @theme block, so utility classes like text-body, p-hsp-md, and rounded-radius-sm resolve to the panel’s CSS custom properties at build time.

/* styles/tokens.css */
@theme {
  --font-size-body: var(--zfbtailwindexample-text-body);
  --spacing-hsp-md: var(--zfbtailwindexample-hsp-md);
  --color-primary: var(--zfbtailwindexample-color-primary);
}

With that @theme block in place, Tailwind utility classes and panel tokens stay in sync automatically: tweaking --zfbtailwindexample-text-body in the panel updates every element using text-body.

The apply-endpoint URL follows the same base-prefixed pattern as the plain zfb example:

/pj/zudo-design-token-panel/examples/zfb-tailwind/api/dev/apply

Worked example: <code>examples/zfb-tailwind</code>.

Where to go next

  • For per-field detail on PanelConfig, see the Configure Panel reference.
  • For the apply-pipeline bin (design-token-panel-server) and routing JSON, see the CLI reference once it lands.
  • For the smallest possible end-to-end wiring, see Quickstart.

Revision History