この記事はバージョン Spring ’26 において執筆しています。
現在の動作と異なる場合がありますので、ご認識おきください。
なぜLWRで外部スクリプトが動かないのか
Lightning Web Runtime (LWR) を採用したExperience Cloudサイト(特にBuild Your Ownテンプレート)で、開発者が一度は直面する「壁」があります。それは、「Google MapsやStripe、チャットボットなどの外部スクリプトを読み込んでも、コンポーネントを操作できない」という問題です。
従来のAuraサイトとは異なり、LWRはWeb標準のShadow DOMを厳格に適用しています。通常の <script> タグで読み込まれたライブラリは、ページ全体(Document)のコンテキストには存在しますが、各LWCコンポーネントが持つ「カプセル化されたShadow Tree」の内部にはアクセス権限を持ちません。
結果として、外部ライブラリが document.getElementById('my-map') のようにDOMを検索しても、その要素はShadow DOMの壁の向こう側にあり、「要素が見つかりません」というエラーで沈黙することになります。
この記事では、この問題を解決するSalesforce固有のアプローチである <x-oasis-script> と、Spring ’26以降の Experience Delivery (SSR) 環境で開発者が陥りやすい「致命的な落とし穴」について、アーキテクチャ視点で解説します。
解決策:<x-oasis-script> (Privileged Script Tag) とは
このShadow DOMの制約を打破するために用意されているのが、特権スクリプトタグ <x-oasis-script> です。
このタグを使用して外部スクリプトを読み込むと、そのスクリプトはLWCのShadow DOM境界をバイパスする特権を持ちます。つまり、コンポーネント内部の要素であっても、まるでLight DOMにあるかのようにアクセスが可能になります。
実装は非常にシンプルです。LWCのテンプレート(HTML)内で、通常の script タグの代わりに使用します。
コード例 1: HTMLでの基本実装
<template>
<x-oasis-script
src="https://www.example.com/libs/example-library.js"
onload={handleScriptLoad}>
</x-oasis-script>
<div class="map-container" lwc:dom="manual"></div>
</template>
これにより、クライアントサイドレンダリング(CSR)の環境下では、外部スクリプトの問題は概ね解決します。しかし、話はここで終わりません。これから普及が進むExperience Delivery環境では、新たな考慮が必要です。
【最重要】Experience Delivery (SSR) 環境での致命的な落とし穴
ここが本記事の核心です。Spring ’26以降、LWRサイトのパフォーマンスを劇的に向上させる Experience Delivery (SSR: Server-Side Rendering) の導入が進みます。
SSR環境では、LWCコンポーネントは最初にNode.jsベースのサーバー上で実行され、HTML文字列としてクライアントに返されます。ここで重大な問題が発生します。
SSRにおける技術的制約
- ブラウザAPIの欠如: サーバー環境には
windowやdocumentオブジェクトが存在しません。 - ライフサイクルの罠:
constructorやconnectedCallbackはサーバーサイドでも実行されます。ここで不用意に外部スクリプト(通常windowオブジェクトに依存している)を参照すると、サーバーエラーが発生し、ページのレンダリング自体が失敗します。
『experience_delivery.pdf』の仕様に基づき、SSR環境でコンポーネントを「ポータブル(移植可能)」に保つためのガード処理が必須となります。
コード例 2: SSRセーフなJavaScript実装
ブラウザAPIに依存する外部ライブラリや処理は、import.meta.env.SSR フラグを使用してサーバー実行時から除外する必要があります。また、非ポータブルなモジュールの読み込みには動的インポート(Dynamic Import)を活用します。
// myComponent.js
import { LightningElement } from 'lwc';
export default class MyComponent extends LightningElement {
isLibLoaded = false;
// SSR環境(サーバー)でもクライアントでも実行されるライフサイクル
async connectedCallback() {
// 重要: サーバーサイド実行時はブラウザAPI依存コードをガードする
if (import.meta.env.SSR) {
// サーバーサイドでの処理(ログ出力など安全な処理のみ)
console.log('Server side rendering: Skipping external script logic.');
return;
}
// ここから下はクライアントサイド(ブラウザ)でのみ実行される
try {
// ブラウザ環境でのみ必要な非ポータブルなモジュールを動的にインポートする
// ※これはSSRでのビルドエラーを防ぐための重要なテクニックです
const { someBrowserSpecificFeature } = await import('some/browser-library');
someBrowserSpecificFeature();
} catch (error) {
console.error('Dynamic import failed:', error);
}
}
// ヒント: renderedCallback はクライアントサイドでのみ実行されるため
// DOM操作やwindowオブジェクトへのアクセスはここに書くのが最も安全です
renderedCallback() {
if (!this.isLibLoaded) {
this.checkExternalScript();
}
}
checkExternalScript() {
// windowオブジェクトへのアクセスも安全
if (window.ExampleLibrary) {
this.isLibLoaded = true;
this.initializeMap();
}
}
initializeMap() {
// DOM操作ロジック...
}
}
この「SSRガード」を忘れると、ローカルプレビューでは動くのに、本番のExperience Delivery環境にデプロイした瞬間にページがクラッシュする、という事態に陥ります。
実装のベストプラクティス:LWCと外部スクリプトの連携
外部スクリプトは非同期で読み込まれるため、LWC側では「いつスクリプトが利用可能になったか」を検知する仕組みが必要です。
ロード検知と初期化フロー
onloadイベント:<x-oasis-script>のonloadハンドラを利用します。- グローバルオブジェクトの監視: スクリプトによっては
onloadが発火しても初期化が完了していない場合があります(例: Stripeなど)。その場合、windowオブジェクトをチェックします。
コード例 3: 堅牢な初期化ロジック
// myComponent.js (続き)
handleScriptLoad() {
// スクリプトタグのロード完了イベント
console.log('Script tag loaded.');
// SSRガードを入れた上で初期化を試みる
if (!import.meta.env.SSR) {
this.initializeLibrary();
}
}
initializeLibrary() {
// ライブラリがwindowオブジェクトにアタッチされているか最終確認
// (TypeScriptを使用している場合は window['MyLib'] のようにアクセス)
if (typeof window.MyLib !== 'undefined') {
const container = this.template.querySelector('.map-container');
// ライブラリを使用してDOMを描画
window.MyLib.createMap(container, {
zoom: 10,
center: { lat: 35.6895, lng: 139.6917 }
});
} else {
// ロードタイミングのズレを考慮し、少し待って再試行するなどのフォールバック
setTimeout(() => this.initializeLibrary(), 100);
}
}
セキュリティ設定:CSP (Content Security Policy) の壁
技術的に正しいコードを書いても、Salesforceのセキュリティ設定でブロックされれば動作しません。特にLWRサイトは厳格な CSP (Content Security Policy) が適用されます。
- 信頼済みURLの登録: [設定] > [信頼済み URL] で、外部スクリプトのドメイン(例:
*.googleapis.com)を登録し、「スクリプト」の許可を与える必要があります。 - CSPモードの選択: Salesforce Spring ’26 Release Notes にある通り、CSP違反の影響を確認しやすくなっています。厳格なCSP(Strict CSP)で動作しないレガシーなライブラリを使用する場合は、LWRの設定で「Relaxed CSP(緩和されたCSP)」の使用を検討するか、ライブラリ側がNonce(ナンス)に対応しているかを確認してください。
まとめ:System of ActionとしてのLWRサイト
LWRサイトにおける外部スクリプトの扱いは、単なる「表示」の問題ではありません。 Shadow DOMを正しくバイパスし、SSR環境でも落ちない堅牢なコードを実装することで、LWRサイトは決済、地図連携、対話型AIなどを備えた「System of Action(行動するシステム)」へと進化します。
Experience Deliveryの導入により、パフォーマンス(Core Web Vitals)は向上しますが、その分開発者には「サーバーサイドでの実行」を意識したコーディングが求められます。import.meta.env.SSR を活用し、次世代の高速なエクスペリエンス構築に備えてください。
参考URL
Salesforce Spring ’26 Release Notes
Improve LWR Site Performance with Experience Delivery



読者の声