Visualforce アプリケーションコンテナの探索

学習の目的

この単元を完了すると、次のことができるようになります。
  • Salesforce Classic で実行される Visualforce ページと Lightning Experience で実行される同ページの 3 つの相違点を説明する。
  • Lightning Experience で機能させるために更新する必要がある 2 つの一般的なコードパターンについて説明する。
  • Lightning Experience で実行するときに、Visualforce ページのデフォルト値に行う 2 つの変更点を挙げる。

Visualforce アプリケーションコンテナの探索

Lightning Experience の Visualforce と Salesforce Classic の Visualforce の最大の違いは実行する環境です。Salesforce Classic では、Visualforce がページ、要求、環境を「所有」します。つまり、Visualforce アプリケーションのコンテナになります。他方 Lightning Experience では、Visualforce が、より大きな Lightning Experience というコンテナ内でラップされた iframe の内側で実行されます。

このような実行コンテキストの変更により、Visualforce ページから Salesforce アプリケーション全般にさまざまな影響が生じる可能性があります。この単元ではこれらの変更について説明しますが、いくつかの点についてはそれぞれ別の単元に譲り、ここでは詳細に立ち入りません。

メモ

メモ

この単元は他の単元以上に「未完成」です。この理由は明らかです。ここで取り上げる問題の影響は、各人のコードによって大きく異なるためです。当社では「とりあえず機能」させようと懸命に取り組んできましたが、ここに記載の内容のほとんどは多くのケースに該当しないものでしょう。けれども、Visualforce のあらゆる使用法を予測することはできません。ここでは、Lightning Experience が Visualforce に影響を及ぼす一般的な側面について概説します。実際の影響について詳しいことがわかり次第、具体的な問題への対処法について詳しく解説していきます。

外側の Lightning Experience コンテナ

まず外側のコンテナである Lightning Experience アプリケーションから見ていきます。Lightning Experience コンテナは「単一ページアプリケーション」 (SPA) で、/lightning URL からアクセスします。/lightning ページが読み込まれ、そのコードが開始され、アプリケーションコードが環境を取り仕切ります。

単一ページアプリケーションがそのリソース (通常は静的 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

Lightning Experience で実行する Visualforce ページは、HTML iframe の内側に表示されます。iframe は、ブラウザ「ウィンドウ」を Lightning Experience のメインの参照コンテキストと効率的に区別する、組み込み参照コンテキストを作成します。さらに、Visualforce とその親の Lightning Experience アプリケーション間に境界線を作成します。

Visualforce ページを iframe の内側で実行する利点は、最上位のコンテキストへのアクセスや変更を必要としないページの場合、iframe の内側で実行すると Salesforce Classic のページとして実行する場合とほぼ同じになります。そのため、すべての Visualforce ページを、Lightning Experience の大きく異なるバックグラウンド要求環境に合わせて変更する必要がありません。この点は、Visualforce をサポートするために「とりあえず機能させる」戦略の重要な部分です。

当然ながら、最上位の参照コンテキストにアクセスする必要のあるページには何らの変更が必要です。この変更方法については、次のセクションで具体的に説明します。

ページが Salesforce 以外のサービスと通信している場合、iframe に境界を設定することで、組織の CORS 設定、リモートサイト設定、クリックジャック設定、コンテンツセキュリティポリシーなどを更新する必要が生じる場合もあります。こうした更新は Salesforce 外のセキュリティポリシーや設定に左右されるため、具体的な変更方法を説明することはできません。ここでは注意を喚起することにとどめます。

新しいコンテナの影響

Visualforce ページを Lightning Experience アプリケーション内の iframe に埋め込む新しい Visualforce コンテナによる影響は、セキュリティと範囲の 2 種類に大別されます。

繰り返しになりますが、Visualforce のページの多く、というより大半は、この問題の影響を受けません。他方、影響を受けるページについては「転ばぬ先の杖」が必要です。問題について認識していれば、問題が生じたときにその原因をすばやく突き止めることができます。

セキュリティ上の影響

影響が及ぶ可能性のあるセキュリティ上の要素は次のとおりです。
  • セッションのメンテナンスおよび更新
  • 認証
  • クロスドメイン要求
  • 埋め込みの制限

このうちクロスドメイン要求への影響については簡単に説明したとおりです。つまり、ブラウザのフルウィンドウのコンテンツがさまざまなサーバやサービスへの要求に基づく場合、これらの要求が想定外のコンテキストに表示されると動作が行き詰る可能性があります。こうした場合に必要に応じてすべきことは、Lightning Experience コンテキスト内でまとめられるべき要求をサービスが処理できるように準備しておくことです。前述のとおり、この具体的な処理法は多岐にわたるため、ここでその方法を説明することはできません。

ここで特に述べておきたい点が、セッションのメンテナンスです。ここで言う「セッション」とは基本的に、要求のたびにユーザ名とパスワードを入力しなくても良いように、ブラウザが要求時に再利用する何らかのトークンです。多くの場合、$Api.Session_ID グローバル変数を使用して現在のセッションにアクセスする必要があります。

この場合の注意点は次のとおりです。要求のドメインに応じて、$Api.Session_ID は異なる値を返します。これは、.salesforce.com から .visual.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 ページを実行中、バックグランドでさまざまなマイナーチェンジが行われます。こうした変更により、大半のページが Lightning Experience コンテナで「とりあえず機能」するようになるため、バックグラウンドの処理をありがたいと思うことがあります。他方、高度なアプリケーションフローに取り組んでいるときや、厄介な問題のトラブルシューティングを行っているときなどは、実際に行われている処理を知りたいと思うでしょう。

バックグランドでの変更の中にはシンプルで、意識すれば明白なものもあります。たとえば、Lightning Experience で実行される Visualforce ページでは常に Salesforce Classic の標準のヘッダーとサイドバーが抑制されます。また、目に見えない変更ながら、同様に大きな影響を及ぼすものもあります。

<apex:page> showHeader および sidebar 属性は常に false

これらの属性は、Visualforce ページ上の Salesforce Classic のヘッダーとサイドバーに影響します。Lightning Experience でページを実行するときは、Lightning Experience のナビゲーション要素が優先されるため、Salesforce Classic のヘッダーとサイドバーは常に抑制されます。Lightning Experience のヘッダーやサイドバーは抑制できないため、このヘッダーやサイドバーに対応する属性はありません。

Salesforce Classic と Lightning Experience でページを共有する場合も、Salesforce Classic でページを実行するときに使用する値にこれらの属性を設定できます。

メモ

メモ

Salesforce Classic の標準スタイルシートを含めるか抑制するかを決定する <apex:page> の standardStylesheets 属性は、Lightning Experience の影響を受けません。つまり、Lightning Experience ではデフォルトの true に設定されますが、変更可能です。

sforce.one JavaScript ユーティリティオブジェクト

sforce.one は、SF 映画に出てくる Salesforce 酒場* で働くドロイドか何かのように聞こえますが、実際は、独自の JavaScript コードで使用可能な多数の便利な関数を備えたユーティリティオブジェクトです。

sforce.one は、Lightning Experience または Salesforce アプリケーションで実行するページに自動的に挿入され、JavaScript デバッガコンソールや Web 開発者のリソースリストに表示されます。このオブジェクトを追加するために必要な作業は何もなく、このオブジェクトを抑制する方法もありません 。(残念ながら、sforce.one を Salesforce Classic の Visualforce ページに挿入する方法もありません)。

sforce.one は主としてナビゲーションイベントの起動に使用されます。詳細は、この後の単元「ナビゲーションの管理」で説明します。

____________________

* Salesforce 酒場は実在しません。