Visualforce アプリケーションコンテナの探索
学習の目的
Visualforce アプリケーションコンテナの探索
このような実行コンテキストの変更により、Visualforce ページから Salesforce アプリケーション全般にさまざまな影響が生じる可能性があります。この単元ではこれらの変更について説明しますが、いくつかの点についてはそれぞれ別の単元に譲り、ここでは詳細に立ち入りません。
外側の Lightning Experience コンテナ
単一ページアプリケーションがそのリソース (通常は静的 HTML シェルと多数の JavaScript) を読み込むプロセスは、興味深いものであると同時に複雑です。JavaScript フレームワーク (AngularJS、React など) で作業をしたことがある場合は、Lightning Experience が /lightning として起動するしくみの基本事項をある程度理解していることになります。そして、はっきり言ってしまれば、全容を知る必要はありません。Lightning Experience は制御できるものではありませんし、その実装は常に進化しています。
ここで認識しておくべき重要なことは、Lightning Experience、あるいは /lightning が要求を統括するということです。Visualforce ページではありません。そのため、Lightning Experience が課す制約内でページを機能させることが必要になります。Lightning Experience は親コンテキストで、Visualforce ページは子コンテキストです。子は親に従わなければなりません。
制約のうち Visualforce を表示するフレームのサイズなど一部は、Lightning Experience から直接的に課されます。こうした制約はわかりやすく対応もしやすいため、これらの制約から説明します。
他の制約は暗黙的で、Lightning Experience ではなく、ページを実行するブラウザーから適用されます。これらの制約の多くは、セキュリティおよび JavaScript 実行の制約と関係しています。ページの大半はセキュリティの制約の影響を受けることがなく、制約に反したとしても初期の段階で明確なエラーメッセージが示されます。JavaScript のエラーは検出や診断が難しいのですが、一定の原則があります。この原則については後ほど説明します。
Visualforce の iframe
Visualforce ページを iframe の内側で実行する利点は、最上位のコンテキストへのアクセスや変更を必要としないページの場合、iframe の内側で実行すると Salesforce Classic のページとして実行する場合とほぼ同じになります。そのため、すべての Visualforce ページを、Lightning Experience の大きく異なるバックグラウンド要求環境に合わせて変更する必要がありません。この点は、Visualforce をサポートするために「とりあえず機能させる」戦略の重要な部分です。
当然ながら、最上位の参照コンテキストにアクセスする必要のあるページには何らの変更が必要です。この変更方法については、次のセクションで具体的に説明します。
ページが Salesforce 以外のサービスと通信している場合、iframe に境界を設定することで、組織の CORS 設定、リモートサイト設定、クリックジャック設定、コンテンツセキュリティポリシーなどを更新する必要が生じる場合もあります。こうした更新は Salesforce 外のセキュリティポリシーや設定に左右されるため、具体的な変更方法を説明することはできません。ここでは注意を喚起することにとどめます。
新しいコンテナの影響
繰り返しになりますが、Visualforce のページの多く、というより大半は、この問題の影響を受けません。他方、影響を受けるページについては「転ばぬ先の杖」が必要です。問題について認識していれば、問題が生じたときにその原因をすばやく突き止めることができます。
セキュリティ上の影響
- セッションのメンテナンスおよび更新
- 認証
- クロスドメイン要求
- 埋め込みの制限
このうちクロスドメイン要求への影響については簡単に説明したとおりです。つまり、ブラウザーのフルウィンドウのコンテンツがさまざまなサーバーやサービスへの要求に基づく場合、これらの要求が想定外のコンテキストに表示されると動作が行き詰る可能性があります。こうした場合に必要に応じてすべきことは、Lightning Experience コンテキスト内でまとめられるべき要求をサービスが処理できるように準備しておくことです。前述のとおり、この具体的な処理法は多岐にわたるため、ここでその方法を説明することはできません。
ここで特に述べておきたい点が、セッションのメンテナンスです。ここで言う「セッション」とは基本的に、要求のたびにユーザー名とパスワードを入力しなくても良いように、ブラウザーが要求時に再利用する何らかのトークンです。多くの場合、$Api.Session_ID グローバル変数を使用して現在のセッションにアクセスする必要があります。
この場合の注意点は次のとおりです。要求のドメインに応じて、$Api.Session_ID は異なる値を返します。これは、.salesforce.com から .force.com など、セッション中にホスト名の境界を越えるたびにセッション ID の値が変わるためです。通常、Salesforce ではドメイン間のセッションハンドオフが透過的に処理されますが、セッション ID を渡す場合は、正しいドメインから $Api.Session_ID に再度アクセスして、有効なセッション ID にする必要がある場合もあります。
Lightning Experience と Visualforce ページは、保持されるブラウザーコンテキストが異なるだけでなく、提供されるドメインも異なります。そのため、すべて 1 つのブラウザーウィンドウに表示されていても、Visualforce の iframe の内側と、(Lightning Experience の別の部分となる) iframe の外側とではセッション ID が異なります。通常の使用時は Salesforce と Lightning Experience がこの処理を透過的に行います。他方、セッション ID を使い回している場合は (通常は好ましいことではありません)、その処理法を見直す必要があるものと思われます。
範囲への影響
- DOM へのアクセスおよび変更
- JavaScript の範囲、表示、アクセス
- JavaScript のグローバル変数 (window.location など)
このリストを見て厄介そうだと思っても、心配することはありません。この根本的な考え方をわかりやすい言葉で言うなら、「他人のものには手を出すな」ということです。特に、自身の JavaScript コード (やスタイルシートルール) が、ページの参照コンテキストの要素 (DOM ノードや JavaScript 変数など) に影響することはありますが、その親の Lightning Experience コンテキストなど別の参照コンテキストの要素にアクセスすることはできません。他のコンテキストにあるものには触れないようにします。
実際、この種の過ちを犯しがちなコードパターンは、window.location を操作して別のページに移動することです。こうした過ちがあまりにも多いため、当社ではこの問題について詳述してきました。このモジュールに達するまでに、うんざりするほど聞いてきたことでしょう。
最後にもう一言加えると、経験豊富な JavaScript 開発者であれば、「親の参照コンテキストにはアクセスできない」という問題には contentWindow や window.parent などを使用して対処する方法を心得ていると考えるかもしれませんが、それは思い違いです。その方法では同じ発生元のポリシーに抵触するおそれがあります (前述のとおり、Visualforce と Lightning Experience は提供されるドメインが異なります)。このポリシーに抵触しなくとも、明白なブロッキングバグを些細な断続的なバグに置き換えることにしかなりません。時間を有効活用するためには、バグを修正して回るのではなく、物事を正しいやり方で行います。
この場合の正しいやり方とは、主としてナビゲーションのために Visualforce ページに用意されている API をコールすることです。フレームの境界を超えて適用する必要がある場合は、window.postMessage を使用して他のフレームの受信コードにメッセージを送信します。
Lightning Experience における Visualforce のデフォルトと環境の変更
バックグラウンドでの変更の中にはシンプルで、意識すれば明白なものもあります。たとえば、Lightning Experience で実行される Visualforce ページでは常に Salesforce Classic の標準のヘッダーとサイドバーが抑制されます。また、目に見えない変更ながら、同様に大きな影響を及ぼすものもあります。
<apex:page> showHeader および sidebar 属性は常に false
Salesforce Classic と Lightning Experience でページを共有する場合も、Salesforce Classic でページを実行するときに使用する値にこれらの属性を設定できます。
sforce.one JavaScript ユーティリティオブジェクト
sforce.one は、Lightning Experience または Salesforce アプリケーションで実行するページに自動的に挿入され、JavaScript デバッガーコンソールや Web 開発者のリソースリストに表示されます。このオブジェクトを追加するために必要な作業は何もなく、このオブジェクトを抑制する方法もありません 。(残念ながら、sforce.one を Salesforce Classic の Visualforce ページに挿入する方法もありません)。
sforce.one は主としてナビゲーションイベントの起動に使用されます。詳細は、この後の「ナビゲーションの管理」単元で説明します。
____________________
* Salesforce 酒場は実在しません。
リソース
- セッションセキュリティ設定の変更
- Visualforce 開発者ガイド
- Mozilla Development Network: HTML Inline Frame 要素 (<iframe>)
- Mozilla Development Network: Content Security Policy の利用方法