Upgrade to Pro — share decks privately, control downloads, hide ads and more …

どんなページでも動かす!JS_CSS汚染を避ける戦い

 どんなページでも動かす!JS_CSS汚染を避ける戦い

第1回 3rdparty.jsで発表した資料です。
https://3rdpartyjs.connpass.com/event/289558/

Ryota Kunisada

August 04, 2023
Tweet

More Decks by Ryota Kunisada

Other Decks in Technology

Transcript

  1. 個人的サードパーティスクリプトの分類 Embed • Google Map • 広告系 Widget • Intercom

    • HubSpot Analytics • Google Analytics • Google Tag Manager UI拡張 • Techtouch • Grammarly Intercomホームページより抜粋
  2. DOMアクセスは多い?少ない? Widget • チャットUIは画面内の 一部分で完結 • DOMへのアクセス を必要としない iframeを使うことで JS/CSS汚染を回避できる

    UI拡張 • 吹き出しが要素に追従 • ページ内の要素にイベントを設定して動作 DOMアクセスが頻繁に発生するため iframeを介すとpostMessageのやり取りが複雑に 今日はこちらの話がメインになります 🙏 Intercomホームページより抜粋
  3. サードパーティスクリプトの不具合の例 https://twitter.com/ckazu/status/1622428980304568325 • Merlin AI powered by ChatGPT というChrome拡張が .loader

    クラスのついた要素に 回転アニメーションを付与 • サードパーティスクリプトは 影響を考慮したCSS設計が必要
  4. プロトタイプ汚染を避けるには 🤔 3rd party script 1st party script ❌ プロトタイプ汚染された関数を呼び出すと意図しない動作に

    Native 3rd party scriptではネイティブの関数を使いたいが、汚染されてしまっている … Prototype.js 1.5系
  5. プロトタイプ汚染を避けるには 🤔 3rd party script 1st party script ❌ プロトタイプ汚染された関数を呼び出すと意図しない動作に

    Prototype.js 1.5系 @babel/plugin-transform-runtime で変換 core-jsでネイティブに近い動作を実現 Native
  6. transform-rutime を使って core-js に置き換える babel • 新しいバージョンでのJavaScriptの書き方を 古いバージョンのブラウザでも動作するようにトランスパイルする @babel/plugin-transform-runtime •

    babelが変換するコードを指定したヘルパーコードに置き換えることができる • core-jsをヘルパーコードとして指定できる core-js • JavaScriptのポリフィル実装。グローバル汚染せずに使うこともできる。
  7. CSSグローバル汚染 • CSSはグローバルに影響する • サードパーティスクリプトの動作を考慮してCSSを実装する人は存在しない <div id="app"> <p>main-app</p> </div> <div

    id="thirdparty-app"> <p>3rdparty-app</p> </div> p:not(#fakeId#fakeId) { color: red; } #thirdparty-app p { color: blue; } 適用されない
  8. CSSの詳細度を上げる :is() や :not() を使い、冗長なIDを設定して詳細度を上げることで打ち勝つ /* 2-0-1 */ p:not(#fakeId#fakeId) {

    color: red; } /* 3-0-1 */ #thirdparty-app p:not(#fakeId#fakeId) { color: blue; } IEサポートするなら 詳細度の対応が必要だった
  9. const thirdpartyApp = document.getElementById("thirdparty-app"); const shadow = thirdpartyApp.attachShadow({ mode: "open"

    }); const p = document.createElement("p"); p.textContent = "3rdparty-app"; shadow.appendChild(p); const style = document.createElement("style"); style.textContent = `p { color: blue }`; shadow.appendChild(style); ShadowRootを介して内部のDOMにアクセスする必要があるため、 Shadow DOM対応していないライブラリに注意