Zudo Token Panel
GitHub リポジトリ

検索したい単語を入力

いつでも検索バーを開ける

自分(サイトオーナー)だけにパネルを読み込む

owner-autoload を使い、デザイントークンパネルを自分のブラウザだけに読み込んで、一般訪問者にはパネルの JS を一切読み込ませない方法。

公開サイトを運用していて、デザイントークンパネルを開発者である自分自身には 使えるようにしたい。ただし一般訪問者にはパネルの JavaScript を一切読み込ませたく ない——owner-autoload はそのための機能です。

  • 一般訪問者: バンドルコストはゼロ。パネルの JS は一切フェッチされません。 JavaScript も CSS も DOM 要素も生成されません。

  • オーナー(自分): ページを開くたびにパネルバンドルが即座に読み込まれ、 閉じた状態でマウントされます。さらに Alt+クリックの要素パスインスペクター が有効化され、パネル UI を開かなくても任意の要素をクリックしてそのセレクターを コピーできます。

オプトインは明示的で、ブラウザごとに行います。自分のマシンの DevTools で window.<ns>.enableAutoload() を一度だけ実行してください。このフラグは localStorage に保存されるため、ページの再読み込み・ソフトナビゲーション・ ブラウザの再起動をまたいで保持されます。しかも保存先は自分のブラウザだけで、 サーバーやビルド成果物には残りません。

ストレージキーの導出方法とゲートの完全な契約については、 PORTABLE-CONTRACT.md §6.2 を参照してください。

仕組み

ホストアダプターはページを読み込むたびに localStorage を調べ、オーナーシグナルが 1 つでもセットされているときだけパネルバンドルをフェッチします。どれも セットされていない場合——公開サイトに初めて訪れた人にとっては通常このケースです ——バンドルは一切フェッチされません。owner-autoload フラグはこのシグナルの 1 つです。

シグナル意味
${storagePrefix}:visible前回の訪問時にパネルが開いていた
${storagePrefix}-open同じ開閉状態を、パネル自身の開閉状態キーで表したもの
${storagePrefix}-state(v1)と ${storagePrefix}-state-v2-vNユーザーがトークンのオーバーライドを保存している
${storagePrefix}:autoloadowner-autoload フラグ——自分がオーナーモードである
${storagePrefix}-elpath-enabled要素パスインスペクターが有効になっている
${storagePrefix}-domtweaker-enabledDOM Tweaker が有効になっている(ホストが domTweaker を設定しているときだけ調べられる)

-state ファミリーは完全一致で照合されます(${storagePrefix}-state と、 任意のバージョンの ${storagePrefix}-state-v<N>)。そのため、自分のプレフィックスで 始まる名前を持つ別インスタンスのキーが、自分のゲートを誤って発火させることは ありません。さらに一致したキーは中身まで検査され、空のエンベロープ({}[]null、空文字列)はシグナルとみなされません。なおパネルのリセットは -state キー 自体を削除するため空のエンベロープを残しません。この検査が効くのは、手作業や別の ツールが書き込んだエンベロープに限られます。

enableAutoload():autoload フラグを書き込み、要素パスインスペクターを 有効化します。disableAutoload() は 4 つのオーナーモードキーすべてをクリアし、 パネルをアンマウントします。

オプトイン(DevTools で一度だけ実行)

サイトの任意のページで DevTools を開き、次を実行します。

window.myapp.enableAutoload();
// Replace 'myapp' with your PanelConfig.consoleNamespace value.

これ以降、そのブラウザでページを読み込むたびに次の処理が行われます。

  1. パネルバンドルを即座にフェッチする(オーバーライドを保存しているときと同じ経路)。

  2. Preact のシェルを閉じた状態でマウントする——パネル UI は表示されないまま。

  3. Alt+クリックの要素パスインスペクターを有効化する——任意の要素にホバーして クリックすると、詳細なセレクターブロックがクリップボードにコピーされる。

  4. これまでどおり window.myapp.{show,hide,toggle}DesignPanel() のコンソール ヘルパー——そして固定名の zdtp.{show,hide,toggle}() グローバル——を 使えるようにする。

オプトアウト

自分のブラウザでパネルの読み込みを止めるには次を実行します。

window.myapp.disableAutoload();

これにより :autoload フラグ、:visible フラグ、要素パス有効化キー、開閉状態 キーがクリアされ、Preact のシェルがアンマウントされます。次回のページ読み込みからは、 再びパネルなしの状態に戻ります。

自動記憶: パネルを開くと autoload が有効になる

どのような手段であれパネルを開くと——showDesignPanel()toggleDesignPanel()、 固定名グローバルの zdtp.show() / zdtp.toggle()、あるいはパネルヘッダーの 閉じる/開き直しボタンのいずれであっても——:autoload フラグが自動的に セットされます。すでにこれらのいずれかの方法でパネルを開いたことがあれば、 enableAutoload() を明示的に呼ぶ必要はありません。フラグは最初に開いた時点で セットされ、ページ読み込みをまたいで保持されます。

このとき書き込まれる値は '1' ではなく 'auto' です。この違いが何のためにあるかは 次のセクションで説明します。この挙動自体が不要なホストは、 autoRememberOnOpen: false で丸ごと止められます。

保存される値が「どう有効化されたか」を表す

:autoload は単なるオン/オフのビットではありません。そのが、 そのブラウザがどうやってオーナーモードに入ったかを記録しています。

保存される値書き込み元意味
'1'enableAutoload()明示的——オーナーが意図してオーナーモードを有効化した
'auto'パネルを開く操作すべて(自動記憶)推定——単にパネルが一度開かれただけ
キーなし、'0'、それ以外disableAutoload() がキーを削除するオーナーモードではない

どちらの値でも zdtp 自身の即時読み込みは有効になります。 パッケージの shouldAutoload()'1''auto' を区別せずに真を返すため、どちらの経路で オーナーモードに入っても、ここまでで説明した挙動はまったく同じです。値を 2 種類に 分けたことでパネルの振る舞いが変わることはありません。

分けている理由は、ホスト側が独自の遅延読み込み判定を書く場合にあります。 === '1' で判定すれば、即時読み込みの対象を「DevTools で enableAutoload() を 実行したオーナー」だけに絞り込めます。何か月も前にパネルのボタンをたまたま 1 回クリックしただけの訪問者に、以後ずっとバンドルをフェッチし続ける必要は なくなります。

自動記憶が既存の '1''auto'格下げすることはありません。明示的に オーナーモードを有効化したあとでパネルを開いても、値は '1' のまま保たれます。

Note

disableAutoload() は、値が何であってもキーごと削除します。「'auto' に格下げする」 という経路は存在せず、オプトアウトは常に完全なオプトアウトです。

落とし穴: 表に見える「開く」トリガーは一般訪問者のオプトインになる

パネルを開く操作はどれも :autoload を有効化するため、一般訪問者の目に触れる UI トリガーは、クリックした人にとって事実上のオプトインになってしまいます。 たまたまそれをクリックした訪問者のブラウザには :autoload = 'auto' がセットされ、 それ以降ページを訪れるたびにパネルバンドルが読み込まれます。

対処は 2 通りあり、どちらを選ぶかは「トリガーを隠せるかどうか」で決まります。

  • トリガーを自分で制御できる場合 — 本番ビルドからパネルを開く入り口を省くか 隠すか、認証で保護します。意図的なオプトインの手段としては DevTools からの enableAutoload() を使います。

  • トリガーを表に出したままにしたい場合 — すべての読者にパネルボタンを見せる 公開ドキュメントサイトでは、そもそも隠すという選択肢がありません。この場合は トリガーではなく自動記憶のほうを止めます(次のセクションの autoRememberOnOpen: false)。

公開サイトでパネルボタンを見せたままにする: autoRememberOnOpen: false

PanelConfig.autoRememberOnOpen は、パネルを開いたときに :autoload = 'auto' を 書き込むかどうかを制御します。デフォルトは true——ここまで説明してきた従来の 挙動です。false にすると、パネルを開いてもオーナーモードが永続化されなくなります。

import { configurePanel } from '@takazudo/zdtp';

configurePanel({
  storagePrefix: 'myapp-design-token-panel',
  consoleNamespace: 'myapp',
  // Public site: the panel button is visible to every reader, so a click
  // must NOT arm owner-mode autoload for them. enableAutoload() stays
  // available as the explicit, owner-only opt-in.
  autoRememberOnOpen: false,
  tabs: [
    // ...your token manifest
  ],
});

Astro ホストでは configurePanel を自分で呼ぶことはありません。すでに <DesignTokenPanelHost> に渡している PanelConfig オブジェクトに、同じフィールドを 持たせてください。

---
// src/layouts/Layout.astro
// myPanelConfig carries autoRememberOnOpen: false, exactly as above.
import DesignTokenPanelHost from '@takazudo/zdtp/astro/DesignTokenPanelHost.astro';
import { myPanelConfig } from '../lib/my-panel-config';
---

<DesignTokenPanelHost config={myPanelConfig} />

この設定を入れると、次のようになります。

  • 読者がボタンをクリックしてパネルを使い、タブを閉じる。:autoload には何も 書き込まれないため、次にページを開いてもバンドルはフェッチされません。

  • 自分は DevTools で window.myapp.enableAutoload() を一度実行する。これは '1' を 書き込む経路であり、この設定の影響を受けません。オーナーモードはここまでの 説明どおりに動きます。

Tip

autoRememberOnOpen: false が抑止するのは :autoload への書き込みだけで、それ以外の 永続化には手を触れません。そしてそのうち 2 つは、それ自体が即時読み込みのシグナルです。 トークンのオーバーライドを保存すれば -state エンベロープが書き込まれますし、パネルを開いたままページを離れれば :visible が立ったままになります。どちらの場合も、その 読者の次回の訪問ではバンドルが読み込まれます。これは意図した挙動です——どちらも 「その読者が実際にパネルを使っている」ことを意味するからです。とはいえautoRememberOnOpen: false は「オーナー以外には絶対に読み込ませない」設定ではない、 ということでもあります。なお、パネルを閉じれば :visible は再びクリアされます。

実例: 安全なオーナー専用ローダー

以下は、このドキュメントサイト自身が使っているパターンです(#422)。常に存在する 小さな <script> ブロックが localStorage をチェックし、オーナーフラグがすでに セットされているときだけパネルを動的に import します。初回訪問時にパネルが import されることはなく、フラグは前述の DevTools コンソール呼び出しによってのみ セットされます。

<!-- Your page layout — runs on every page, before </body> -->
<script>
  // Tiny stub — the full panel bundle is imported only when :autoload is set.
  // Replace storagePrefix with your PanelConfig.storagePrefix value.
  const storagePrefix = 'myapp-design-token-panel';
  const autoloadKey   = `${storagePrefix}:autoload`;
  const autoload      = window.localStorage?.getItem(autoloadKey);

  // '1' = the owner ran enableAutoload() deliberately.
  // 'auto' = the panel was merely opened once (auto-remember).
  // Drop the second test to serve eager loads to explicit owners only.
  if (autoload === '1' || autoload === 'auto') {
    // Owner mode: load the panel module. The module's own bootstrap logic
    // reads the gate signals, finds the :autoload value, and re-applies the
    // full owner-mode state (CLOSED mount + element-path armed).
    void import('@takazudo/zdtp');
  }
</script>

両方の値を見るのは、zdtp 自身のゲートと同じ判定です。=== '1' だけを見るのは より厳しいポリシーで、クリックではなくコマンドの入力によってオーナーモードに 入った人以外には、バンドルをページに載せません。

<DesignTokenPanelHost> コンポーネントを使う Astro サイトでは、このスタブは 不要です。ホストアダプターが :autoload シグナルを含めた遅延読み込みのゲートを すでに処理しているためです。このパターンが当てはまるのは、Astro 以外のホストや、 import のトリガーを明示的に制御したいカスタム構成の場合です。

Tip

<DesignTokenPanelHost> を使った Astro サイトなら、DevTools でwindow.myapp.enableAutoload() を一度実行するだけで十分です。あとはアダプターが、 それ以降のページ読み込みのたびに自動で処理します。

既存ブラウザに関する注意: すでに '1' を保持している

値による区別は今回から入ったものです。このリリースより前に自動記憶が働いた ブラウザには、素の '1' が保存されています。記録されなかった来歴をあとから 復元する手段はないため、これらのブラウザは今後ずっと「明示的なオーナー」として 読み取られます。

Warning

=== '1' の判定を入れた初日に、既存の自動記憶ユーザーが一気に外れることは 期待しないでください。値による区別が効くのはこのバージョン以降の書き込みだけです。 古い '1' は、対象のブラウザがストレージをクリアするか disableAutoload() を 実行するにつれて、少しずつ減っていきます。

autoRememberOnOpen: false についても同じです。これが止めるのはこれからの 書き込みだけで、すでに '1''auto' を保持している訪問者は、キーがクリア されるまでその値を持ち続けます。

まとめ

操作内容
オプトインDevTools で window.myapp.enableAutoload()(一度だけ)——'1' を書き込む
オプトアウトDevTools で window.myapp.disableAutoload()——キーを削除する
一般訪問者コストゼロ——バンドルも CSS も DOM もなし
オーナー(オプトイン後)バンドルが即座に読み込まれ、パネルは閉じた状態でマウント、Alt+クリックが有効
最初に開いたとき'auto' が書き込まれ、以降のページでパネルが再読み込みされる
パネルボタンを見せる公開サイトautoRememberOnOpen: false——パネルを開いても :autoload を書き込まない

関連ページ

Revision History

作成更新