0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Python × WASM】完全オフラインの文章解析アプリ開発で立ち塞がった「Shadow DOM」の壁と、ゴルディアスの結び目を断つUI実装術

0
Last updated at Posted at 2026-03-15

はじめに:クラウドAI全盛期における「パラノイア(恐怖)」

ChatGPTやClaudeなど、強力なクラウドAIの登場により、私たちのテキスト処理の生産性は劇的に向上しました。しかし、その影で強いパラノイア(恐怖)を抱えている人々がいます。

「未発表の小説アイデアや、クライアントとのNDA(秘密保持契約)に縛られた極秘原稿を、外部サーバーにアップロードして本当に大丈夫なのか?」

一度クラウドに送信されたデータが、将来の学習モデルにどう使われるか、完全にコントロールすることは不可能です。「削除」ボタンを押しても、裏でログが残っているのではないかという疑心暗鬼。機密を扱う小説家やプロライターにとって、これは死活問題です。

そこで我々のチームは、「通信0 bytes(完全オフライン)」 で動作し、絶対に情報漏洩しない文章解析ツール『Zero-Leak Manuscript Analyzer』の開発を決意しました。

技術選定:Python + marimo + Pyodide (WASM)

要件は「ブラウザ内で完全に処理が完結し、外部サーバーと一切通信しないこと」。
これを実現するために選んだ技術スタックが、Python + marimo + Pyodide (WASM) です。

marimo は次世代のPythonノートブック環境であり、Pyodideを通じてブラウザ上のWebAssembly(WASM)環境で直接Pythonコードを実行(エクスポート)できます。

このアーキテクチャの最大のメリットは、インフラ費用(サーバー維持費)が一生「0円」 であること。そして何より、ユーザーに対して 「物理的にデータが外に出ない」という絶対的なセキュリティの証明(USP) を提示できることです。

我々はPythonの標準ライブラリ(reモジュール等)のみを駆使し、基本統計、NGワード検知、表記ゆれチェック、SEO構造分析を行う堅牢なロジックを組み上げました。

しかし、真の地獄は「フロントエンド(UI)のカスタマイズ」に潜んでいました。

直面した最大の壁:ダークテーマと「Shadow DOM」の罠

このアプリは、サイバーセキュリティツールのような「重厚な安心感」を演出するため、深いネイビーを基調としたダークモードUIを採用しました。

問題が起きたのは、入力欄(mo.ui.textmo.ui.text_area)のスタイリングです。
背景が暗いため、文字色(フォアグラウンド)を白系(#e2e8f0)に設定していました。しかし、入力欄自体は白背景にしたかったため、そこに入力されるテキストも白くなってしまい「視認不可」になる事態が発生したのです。

そこで、入力テキストを黒色にするため、CSSで以下のように指定しました。

Sample_CSS-1
marimo-text { color: #111827 !important; }

するとどうでしょう。入力欄の文字は黒くなりましたが、入力欄の外側にある「ラベル(🚫 NGワードなど)」の文字まで真っ黒に潰れ、ダークな背景に同化して消えてしまったのです。

「ならばラベルだけ白にすればいい」と考え、次のように書きました。

Sample_CSS-2
marimo-text label { color: #e2e8f0 !important; }

……効きません。

なぜか?
marimoのUIコンポーネントは、Shadow DOM によってカプセル化されているからです。

グローバルな <style> から指定したCSSは、Shadow DOMの境界を越えられません。かといって、親要素である marimo-textcolor を指定すると、CSSの継承によってShadow DOM内部にある「ラベル」と「入力欄」の両方に同じ色が波及してしまいます。

試みたCSSハック 入力テキスト ラベル 結果
marimo-text { color: #111827 } ⬛ 黒(読める) ⬛ 黒(見えない) ❌ 絶望
marimo-text { color: #e2e8f0 } ⬜ 白(見えない) ⬜ 白(読める) ❌ 絶望
marimo-text label { color: #e2e8f0 } ❌ 当たらない ❌ 絶望

ラベルと入力欄が同じShadow DOMの檻の中にいる限り、外部のCSSから両者を個別に制御することは不可能だったのです。

さらに残酷なことに、複数行入力であるmarimo-text-areaの内部は単なる<textarea>ではなく、リッチエディタである CodeMirror で構成されています。

入力のたびに数十個の<span>タグが動的に生成されるため、Shadow DOMの外側から文字色を完全制圧することは、まさに「悪夢」のような作業でした。

ラベルと入力欄が同じShadow DOMの檻の中にいる限り、外部のCSSから両者を個別に制御することは不可能だったのです。

ブレイクスルー:ゴルディアスの結び目を断つパラダイムシフト

数時間のCSSとの泥沼の格闘の末、我々は一つの決断を下しました。
「CSSで戦うことを諦め、DOM構造そのものを変える」

そもそも、なぜラベルがShadow DOMの中に囚われているのか?
それは、コンポーネントの引数として label="..." を渡しているからです。

Sample_code-1
# Before(問題のある構造:ラベルがカプセル化され、CSSが両方に波及する)
ng_words_input = mo.ui.text(
    label="🚫 NGワード", 
    placeholder="例: 機密,未発表", 
    full_width=True
)

それならば、引数でラベルを渡すのをやめ、Shadow DOMの外側(Light DOM)に独立したHTML要素としてラベルを配置すればいいのです。

Sample_code-2
# After(解決した構造:label= パラメータを完全削除し、外側に分離)

# 【セルA: UIコンポーネントの定義】
ng_words_input = mo.ui.text(
    placeholder="例: 機密,未発表", 
    full_width=True
)

# 【セルB: レイアウトの構築】
# ※定義と配置を別セルに分けるのが、marimoのReactive Loopを防ぐ鉄則です
mo.vstack([
    mo.Html("<span class='ma-input-label'>🚫 NGワード(カンマ区切り)</span>"),
    ng_words_input,
], gap=0)

このパラダイムシフトにより、CSSの制御は劇的にシンプルになりました。

Sample_CSS-3
/* Shadow DOM 外の純 HTML なので、確実に白を適用できる ✅ */
.ma-input-label {
    color: #cbd5e1 !important;
}

/* Shadow DOM 内は「入力欄のみ」になったため、黒を指定しても副作用ゼロ ✅ */
marimo-text, marimo-text-area {
    color: #111827 !important;
}

DOMの構造を図解するとこうなります。

【従来:CSSが両方に伝播】
Shadow DOM ホスト要素
  └── Shadow DOM 内部
        ├── <label>ラベルテキスト</label>   ← 黒になる ❌
        └── <input>入力欄                ← 黒になる ✅

【解決後:完全に分離】
Light DOM(我々が完全制御)
  └── <span class="ma-input-label">ラベル</span>  ← 白になる ✅

Shadow DOM ホスト要素
  └── Shadow DOM 内部
        └── <入力欄のみ>                 ← 黒になる ✅

複雑に絡み合ったCSSのハック(ゴルディアスの結び目)を解こうとするのではなく、DOM構造を変更するという剣で一刀両断にした瞬間でした。

まとめ:技術の泥沼にはまったら「視座」を上げる

フレームワーク(今回であればmarimo)が提供する便利な機能(label= 引数)に依存しすぎると、かえって制約に縛られ、身動きが取れなくなることがあります。

「CSSが効かない」と目の前のコードとにらめっこするのではなく、「なぜ効かないのか(Shadow DOMの非対称性)」という一段高いアーキテクチャの視座に立つことで、驚くほどシンプルな解決策(ラベルを外に出す)が見つかります。

こうして完成した『Zero-Leak Manuscript Analyzer』は、一切の通信を行わない絶対的な安全性と、プロの執筆環境にふさわしい美しいダークUIを両立させることができました。

WASMやPyodideを使った完全フロントエンドアプリの開発は、制約が多い分、パズルを解くような極めてエキサイティングな体験です。この記事が、同じようにShadow DOMの壁にぶつかったエンジニアの突破口になれば幸いです。

最後までお読みいただき、ありがとうございました!

おまけ:成果物(デモ)

開発した 文章解析・推敲ツール がこちらです。
リンク先のサムネイル等で、UIを確認してみてください。

▼ Zero-Leak Manuscript Analyzer(絶対秘密保持・ローカル原稿アナライザー)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?