Shadow DOMでIslands Architectureっぽく(状態管理編)
記事の内容
前回、Shadow DOMでIslands Architectureっぽく(CSS編)という記事を記載しました。今回はShadow DOMにある複数のアプリ間での共有したい状態の管理方法について記載します。
動作環境
簡単なカウンターアプリを作ってみました。

今回のアプリも前回と同様で
Next.jsのSSGしたページをGitHub Pagesに公開し、ページ内にNext.js、Shadow DOM上にReactとVue2が動作しています。
解説
複雑な説明になるので図にしました。
状態共有の仕組み図
上記の図でアンダーバーがあるテキスト箇所はリンクになっていますので、該当箇所を見ることができます。
今回は@multi-fw-demo/shared-stateというCustomEventをPub/Subした状態管理ライブラリを作成しました。
CustomEventによるPub/Subの実装にした意図として複数アプリケーションで別々のビルドファイルを扱うものになるのでimportして使用するモジュールのリソースが別物になってしまうのでCustomEventに逃す意図があります。
余談によくある状態管理ライブラリとの違いを記載します。
この仕組みは株式会社カケハシさんの登壇した資料の爆速でプロダクトをリリースしようと思ったらマイクロフロントエンドを選んでいたと被ったとサンプルのカウンターアプリを作った後で気づきました。
より実践的で戦略的な思想について
型とテストで守るカスタムイベント通信 - 実プロダクトでの実装事例
から色々学ぶことができました。
データフロー図
- ユーザーアクション: いずれかのアプリ(Vue2/React/Next.js)でカウンターボタンをクリック
-
ローカル更新: そのアプリの
SharedStateStoreインスタンスが状態を更新 -
グローバル通知:
window.dispatchEvent()でCustomEventを発火 -
クロスコンテキスト同期: すべてのShadowRoot内の
SharedStateStoreがwindow.addEventListener()でイベントを受信 - UI更新: 各フレームワークの仕組み(Vue2のリアクティブシステム、ReactのuseSyncExternalStore)でUIが自動更新
余談
状態管理ライブラリってただのPub/Subの実装やったんや
漠然と状態管理の実装して、元々の状態管理どんな実装しているのか気になったというのと、前回のブログでもいっていたのですがどうしてもAstroがわいてきてChatGPTに相談してみました。

初手でnanostoresというワード出したのもAstroのグローバルステートライブラリ推しっぽそうなので一番グローバルステートしてそう(どのアプリケーションでも使用できる意味合いで)という偏見で聞いてみました。
よくある状態管理ライブラリのPub/Sub実装
const listeners = []
function subscribe(callback) {
listeners.push(callback)
return () => {
const i = listeners.indexOf(callback)
if (i !== -1) listeners.splice(i, 1)
}
}
function publish(data) {
listeners.forEach(cb => cb(data))
}
ChatGPTの例を見てなるほどとなり、今まで状態管理ライブラリのコードを読んだことなかったのですが、確かにこの形のものが多かったです。
- zustand
https://github.com/pmndrs/zustand/blob/v5.0.9/src/react.ts#L30-L34
React.useSyncExternalStoreと記載されている処理の前後見るとなるほどなと把握できました - Nano Stores
-
Pub/Sub部分
- listeners、subscribeという記載見てこれもPub/Sub実装なんだなと分かりました
- Nano Stores React
-
useSyncExternalStoreしてる部分
- React側はもうそうゆう実装なんだと思いました
-
useSyncExternalStoreしてる部分
- Nano Stores Vue
-
shallowRefしてる部分
Vue3というかVue Composition API以降をあまり知らなかったのですがreactivityによる仕組みでrefの更新で再更新をかける方式- 自前で作った@multi-fw-demo/shared-stateはVue2だったので別の発見がありました
- Mixinによる状態変更でなんとかできてます
- 自前で作った@multi-fw-demo/shared-stateはVue2だったので別の発見がありました
-
shallowRefしてる部分
-
Pub/Sub部分
参考
ちょっと株式会社(chot-inc.com)のエンジニアブログです。 フロントエンドエンジニア募集中! カジュアル面接申し込みはこちらから chot-inc.com/recruit/iuj62owig
Discussion