modernize-flp-sandbox について
旧 FLP sandbox から New Sandbox へ移行する UI5 開発者向けのスキルです。中核の変換を自動化し、テスト基盤を確認して、関連する問題は別途報告します。
主な機能
- 01旧 sandbox ファイルの分析
- 02HTML と設定の変換
- 03フックモジュールの作成・書き換え
- 04OPA テスト配線の更新
- 05移行上の不足事項の報告
活用シーン
- 01UI5 アプリの New Sandbox への移行
- 02複数 sandbox シナリオの統合
- 03OPA テスト配線の復旧
- 04非推奨 ushell サービス利用の検出
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ ui5/ plugins-coding-agents --skill modernize-flp-sandboxインストール後、Claude Code で/modernize-flp-sandboxを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/native-replacements.mdoperations.mdsandbox-config-surface.md詳細
新しいサンドボックスへの移行スキル
UI5 アプリケーションをレガシー FLP サンドボックスから New Sandbox に移行します。 分析、変換、検証を行い、結果を報告します。このスキルはコア移行を完全に自動で実行しますが、関連する懸念事項(下記のスコープを参照)については、実行前に利用者に確認します。
今すぐ references/operations.md を読み込んでください。これは、すべての HTML/JSON/フックモジュール変換に関する運用リファレンスです。
今すぐ references/sandbox-config-surface.md を読み込んでください。これは、New Sandbox が許可、ブロック、または無言で上書きする内容についての信頼できる説明です。
§6 のすべてのルールでは、制約を本文中で繰り返す代わりに、このファイルを参照します。
スコープ — 3 つのレイヤー
-
コア移行 — アプリを New Sandbox で起動するために必要な操作です。無条件に実行し、実行できない場合は移行に失敗します。トリガー:§6a、§6b、§6c、§6f。
-
テストインフラストラクチャ — テストのセマンティクスを変更せずに、テストスイートを再び実行できるようにします。安全な書き換え(リソースルートの再バインド、OPA のブートストラップ抽出)は無条件に適用します。テストロジックに関わる変更は、検出して報告し、要望があった場合に提案します。トリガー:§6d、§6e、§6g、§6h、§6j、§6l。
-
関連する移行と注意事項 — 移行によって明らかになったものの、移行そのものには含まれない懸念事項です。検出して報告するだけで、書き換えは適用しません。
- QUnit 1.x → 2.x のパターン(§6i)— 注意事項。
- シェル機能のテスト(§6j、§6l)— 注意事項。
- 非推奨の ushell サービス(§6k)— コアのパスで検出し、「手動での対応が必要」として報告します(実行時の重大なブロック要因)。
1. アプリのルートを検出する
ユーザーがパス引数を指定した場合は、そのパスを使用します。それ以外の場合は、CWD から検出します。
- CWD および親ディレクトリで
package.jsonとwebapp/を検索します。 - 見つからない場合は、ユーザーに次のように伝えます:"UI5 アプリのルートを検出できませんでした。アプリのディレクトリ内で実行するか、パスを指定してください:
/modernize-flp-sandbox ~/path/to/app"
APP_ROOT に解決済みの絶対パスを設定します。
2. クリーンな状態を確保する(移行前)
ファイルに触れる前に、ロールバックできる状態を確保します。
git リポジトリが検出された場合:
cd $APP_ROOT
git stash push -m "modernize-flp-sandbox: pre-migration backup $(date +%Y%m%d-%H%M%S)"
ロールバック用に stash の参照を保存します。stash するものがなければ、すでに作業ツリーはクリーンです。
git リポジトリがない場合:
mkdir -p $APP_ROOT/webapp/test/.migration-backup
cp $APP_ROOT/webapp/test/flpSandbox*.html $APP_ROOT/webapp/test/.migration-backup/ 2>/dev/null
cp $APP_ROOT/webapp/test/fioriSandboxAppConfig.json $APP_ROOT/webapp/test/.migration-backup/ 2>/dev/null
3. 分析する
$APP_ROOT/webapp/test/ 以下のすべての HTML ファイルを(再帰的に)読み込み、パターンの一覧を作成します。
レガシーサンドボックスの HTML ファイルを検出する — 次のいずれかが含まれているファイルはレガシーです。
id="sap-ushell-bootstrap"(サンドボックスのブートストラップスクリプトタグ)window["sap-ushell-config"]の代入sandbox2.jsを参照するsrc=(中間形式の New Sandbox における旧形式のブートストラップ。SandboxBootTask.jsより前の形式です。他のレガシーパターンと同様に扱います)
OPA テストページ(SandboxBootTask/boot-manifest を受け取りません): レガシー検出に該当し、さらに次のすべてを含むファイルです。
QUnit.configまたはQUnit.config.autostartの代入、あるいはwindow.QUnit = {sap/ui/qunit/、sap/ui/test/、またはsap/ui/thirdparty/qunitのエントリーを含むsap.ui.require(
これらのファイルはサンドボックス HTML として移行しません。代わりに、次の処理を行います。(a)§6g に従ってブートストラップを兄弟 JS ファイルに抽出します。(b)§6i で QUnit 1.x を検出し、同意が得られた場合はサブスキルに引き継ぎます。§6g の HTML 編集では、次の処理を行います。
<script src="../ushellConfig.js">と<script src="...sandbox.js" id="sap-ushell-bootstrap">を削除します。- インラインの QUnit/OPA ブートストラップを、スクリプトタグによる直接読み込み(qunit-2.css、qunit-2.js、qunit-junit.js)と
<script src="AllJourneys.js">に置き換えます。 - インラインコンテンツから
AllJourneys.jsを作成します(§6g を参照)。 data-sap-ui-preload="async"をdata-sap-ui-async="true"に、data-sap-ui-compatVersionをdata-sap-ui-compat-versionに、data-sap-ui-resourcerootsをdata-sap-ui-resource-rootsに更新します。SandboxBootTask.js、boot-manifest、または<div id="canvas">は追加しません。 外部化された ushell 設定の検出:webapp/test/配下のすべての HTML にある各<script src="...">について、参照先ファイルに ushell 設定オブジェクトへの 代入 が含まれているか確認します。window["sap-ushell-config"] = …/globalThis[…]/self[…]Object.assign(<global>["sap-ushell-config"], …)<global>["sap-ushell-config"].<prop> = …(初期化後のプロパティ書き込み)
設定を 読み取る だけのファイルは該当しません。該当する各ファイルを externalUshellConfigFile として記録します。移行時はインラインの場合と同じ方法で設定を解析し、参照しているすべての HTML から <script> の読み込みを削除し、Step 9 でファイルを削除します。
各レガシー HTML ファイルについて記録する項目:
- ファイル名、モックサーバーの有無、RTA/LREP の有無、カスタムプラグインの有無、非推奨サービスの有無
locate-reuse-libs.jsの有無(Gap-Report 用のフラグ)- 既存の
data-sap-ui-libs、data-sap-ui-resourceroots/data-sap-ui-resource-roots、data-sap-ui-theme、data-sap-ui-languageの値(引き継ぎ、ケバブケースに変更)
既存の New Sandbox アーティファクトを確認する:
fioriSandboxAppConfig.json— 存在するか(作成または上書きします)sandbox/ディレクトリ — 各*.jsファイルを次のように分類します。legacy:Container.createRendererInternalまたはattachRendererCreatedEventを含む、またはexecute:を含まないファイル。インプレースで書き換えるための情報を取得します(§6c)。トップレベルの名前空間宣言をpreservedDeclarations[]として取得します(正規表現:^\s*sap(\.[a-zA-Z0-9_]+)+\s*\?\?=\s*\{\}およびglobalThis.sap/window.sapチェーン。見つからない場合は、最初のsap.ui.define(または IIFE までをそのままコピーします)。modern:{ execute: ... }をエクスポートするファイル。そのまま再利用します。- **複数のレガシーファイル:**すべて書き換えます。
beforeFlpStartに接続するのは 1 つだけです。Initを含む名前を優先し(Mockは除外)、Gap-Report に注記します。
- FakeLREP ファイル(
webapp/test/配下の*Lrep*.json/*LRep*.json)—rta参照用に正確なファイル名を記録します。
OPA テストの接続を確認する:
- OPA テストランナー HTML(既定値は
webapp/test/integration/opaTests.qunit.html。見つからない場合は、レガシーのモックサーバー HTML を参照するwebapp/test/integration/配下の*qunit.html)—"../flpSandboxMockServer"に一致する値を記録します。§6d のトリガーになります。 - OPA Common ヘルパーファイル(既定値は
webapp/test/integration/pages/Common.js。見つからない場合は、iStartMyAppInAFrame(/getFrameUrl(とsap.ui.require.toUrl(の両方を含むwebapp/test/integration/配下の*.js)— §6e のトリガーになります。
非推奨の ushell サービス使用状況をスキャンする:
webapp/ 配下(test/、resources/、*.min.js を除く)の *.js から、references/sandbox-config-surface.md §5 に記載された 12 個の非推奨サービスのいずれかを <name> とする getService(<name>) / getServiceAsync(<name>) を検索します。ファイル、行、サービス名、バインドされた変数を記録します。Gap-Report(§8)に記載し、§6k でフォローアップします。
UI5 フレームワークのバージョンを確認する:
ui5.yaml と ui5-local.yaml から framework.version を読み取ります。New Sandbox には 1.147 以上が必要です。それより低い場合は、自動で更新します。
- 1.147 以上の最新の安定版 SAPUI5 バージョンを検索します。
ui5.yamlをその場で更新します。- 次のようにログに記録します。"Auto-bumped ui5.yaml framework version from
<old>to<new>(New Sandbox requires >= 1.147)." - Gap-Report に注記します。
3a. フックの依存関係グラフのスキャン
beforeFlpStart フックから到達可能な推移的 AMD グラフ内の eager な sap/ushell/* インポートを特定します(ハード制約 H2 — references/sandbox-config-surface.md §1 を参照)。詳細と書き換え手順は references/operations.md §6f にあります。
この手順ではインベントリのみを作成します。 実際の処理は §6c でフックを生成した後、§6f で行います。
次の項目を記録します。
hookEntryModule— 既存のfioriSandboxAppConfig.jsonのbeforeFlpStartから解決するか、§3 のレガシーフックから検出します(通常はwebapp/test/sandbox/fioriSandboxInit.js)。hookGraphRoots[]— フック本体を調べ、フックが直接必要とする追加モジュールを記録します。
4. シナリオウィザード(複数の flp*.html が見つかった場合のみ)
レガシーサンドボックス HTML が 1 つだけ見つかった場合は、スキップします。
新しいサンドボックスでは fioriSandboxAppConfig.json を 1 つだけ使用するため、複数の HTML ファイルに独立した設定を持たせることはできません。解決策として、実行時にシナリオを選択する URL パラメーターを使い、1 つの HTML に統合します。
非対話モード: $APP_ROOT/webapp/test/wizard-answers.json を確認します。存在する場合は、その値を直接使用します(CI/スクリプトによる移行向け)。形式:
{
"scenarios": [
{ "file": "flpSandbox.html", "id": "default", "description": "Live backend" },
{ "file": "flpSandboxMockServer.html", "id": "mockserver", "description": "Mock server" }
],
"defaultScenario": "mockserver",
"targetHtml": "flpSandbox.html",
"paramName": "scenario"
}
ユーザーに質問します:
- 「各ファイルはどのシナリオを表していますか?」(例:「mockserver」、「cdm」、「default/no-mock」)
- 「どのシナリオをデフォルトにしますか?」(推奨:オフラインで動作する
mockserver) - 「どの HTML ファイル名を残しますか?」
- 「URL パラメーター名は何にしますか?」(デフォルト:
scenario。プロジェクト固有の名前にすると競合を避けられます)
記録: 対象 HTML、シナリオ一覧、デフォルトのシナリオ ID、パラメーター名、不要な HTML ファイル。
URL の規則: flpSandbox.html?scenario=mockserver。パラメーターがない場合は、デフォルトのシナリオを使用します。選択した名前を README に記載します。
5. 移行前チェックリスト
ファイルを書き込む前に、APP_ROOT が設定されている(§1)、ロールバックが確保されている(§2)、インベントリが作成されている(§3)、必要な場合はウィザードの回答が用意されている(§4)ことを確認します。すべて問題なければ、§6 に進みます。
6. 移行
すべての変換を実行します。書き込みに失敗した場合は、ロールバック(§10)に進みます。
対象範囲 — 変更するファイル:
- §3 で検出されたすべての
flp*.html→ 完全な変換(§6a–§6c) - OPA テストページの HTML → ブートストラップの抽出(§6g)
- OPA テストランナーの HTML → リソースルートの再割り当て(§6d)
- QUnit テストスイートのインデックス → journey URL の書き換え(§6g)
- OPA Common-helper → URL パラメーターの注入(§6e)
webapp/test/fioriSandboxAppConfig.json→ 作成/上書き(§6b)webapp/test/sandbox/*.jsのレガシーフック → インプレースで書き換え(§6c)beforeFlpStartAMD グラフ内のファイル →references/native-replacements.mdを自動適用(§6f)webapp/test/integration/内の OPA テストコードとアプリコード → 機械的な書き換え(§6h–§6l)
対象外: unitTests.qunit.html、unit/、*.qunit.js。
opaTests.qunit.html が flpSandboxMockServer.html を参照している場合は、移行(§6a)と OPA 参照の再割り当て(§6d)をまとめて行います。
各サブセクションでは、対象/実施条件/対象レイヤーを説明します。完全なアルゴリズムは references/operations.md に記載されています。
6a. レガシー HTML ファイルをインプレースで変換する
レイヤー: コア。すべてのレガシーサンドボックス HTML に対して無条件に実行します。
レガシーの ushell-config 書き込み、sap-ushell-bootstrap スクリプトタグ、不要なブートストラップ属性を削除します。SandboxBootTask.js(または CDN 版)、ブートマニフェスト属性、<div id="canvas"> を追加します。バリアント間でリソースルートを統合し、常に sandbox ルートを追加します。
→ references/operations.md §6a
6b. fioriSandboxAppConfig.json を作成または更新する
レイヤー: コア。references/sandbox-config-surface.md §2 に記載されたキーのみを対象とします。
解析したレガシー設定から JSON を作成します。アプリケーションキーを最初の - で分割し、semanticObject と action にします。rootPath からクエリー文字列を削除し、末尾にスラッシュを付けます。ウィザードを実行した場合は、バリアント間でタイルを集約します。必要な場合に限り、beforeFlpStart、rta、plugins を追加します。
→ references/operations.md §6b
6c. フックモジュールを作成または書き換える
レイヤー: コア。beforeFlpStart をサポートし、applyUshellConfig の前に実行します。契約:globalThis["sap-ushell-config"] に触れないこと、sap/ushell/* を先行して require しないこと(references/sandbox-config-surface.md §8 を参照)。
単一シナリオのフック(モックサーバーのみ)または複数シナリオのフック(URL パラメーターによる切り替え)を生成します。名前空間宣言を保持したまま、レガシーフックをインプレースで書き換えます。モックサーバーが不要な場合は、最小限の何もしないフックにフォールバックします。
→ references/operations.md §6c
6d. OPA リソースルートの再バインド
レイヤー: テストインフラ。無条件(セマンティクスの変更なし)。
OPA テストランナーの HTML 内で、旧モックサーバーの HTML を指している data-sap-ui-resource-roots を移行先を指すように書き換えます。
→ references/operations.md §6d
6e. Common.js へのシナリオ URL パラメーターの挿入
レイヤー: テストインフラ。Wizard によって複数の HTML が統合された場合のみ。
iframe の URL の # ハッシュより前にシナリオパラメーターを挿入します(これにより、window.location.search で取得できます)。
→ references/operations.md §6e
6f. フックグラフの ushell 依存関係の解決
レイヤー: コア。ハードランタイムブロック H2 — フックの推移的な AMD グラフから sap/ushell/* を先行して require することはできません。
hookEntryModule(§3a)から AMD のクロージャーをたどります。各 sap/ushell/* の該当箇所を、簡単に置き換え可能/アーキテクチャ上の移設が必要/手動対応が必要に分類します。references/native-replacements.md のレシピを自動適用するか、Gap-Report の項目を出力します。
→ references/operations.md §6f
6g. OPA ブートストラップの兄弟 JS ファイルへの抽出
レイヤー: テストインフラ。機械的な抽出。
インラインの <script> ブロックを兄弟 .js ファイル(デフォルトでは AllJourneys.js)に抽出します。QUnit 1.x のグローバル変数と jQuery.sap.getUriParameters を最新の同等機能に変換します。テストスイートのインデックスを、URLSearchParams 形式のジャーニー URL に更新します。
→ references/operations.md §6g
6h. 旧 ushell-config の値へのバインディングの検出
レイヤー: テストインフラ(機械的に自動修正できる場合は自動修正し、それ以外は報告)。
旧設定では自由形式だったものの、New Sandbox では別の方法で導出される値をコード内にハードコードしている箇所を特定します。カテゴリは、A タイルから導出(自動修正)、B ユーザープロファイル(自動修正)、C パーソナライズ(自動修正)、D デフォルトで固定(報告のみ)です。references/sandbox-config-surface.md §3+§4 を参照してください。
→ references/operations.md §6h
6i. QUnit 1.x → 2.x パターン(引き継ぎ)
レイヤー: アドバイザリー。実際の書き換えは modernize-flp-sandbox-qunit サブスキルで行います。
検出して報告し、サブスキルの実行を提案します。これを表面化する理由:§6a で data-sap-ui-async="true" を追加すると、このモードでは QUnit 1.x のグローバル変数(module、ok、equal)が ReferenceError をスローします。根本原因はサンドボックスの移行とは独立しており、移行によって顕在化するだけです。
→ references/operations.md §6i
6j. FLP シェルコントロールへの対応(報告)
レイヤー: テストインフラ(報告のみ)。FLP シェルコントロールを直接対象とする OPA テストを検出します。新しい UI5 ではシェルが Web Components 経由でレンダリングされるため、sap.m.* シェルコントロールに一致するテストは、エラーを示さずに失敗します。
パターン:S1 = sap.m コントロールとシェル専用 ID、S2 = type:"Back" マッチャー、S3 = Web Component ではないシェルヘッダー呼び出し。
→ references/operations.md §6j
6k. アプリコード内の非推奨 ushell サービス(検出)
レイヤー: コア検出。非推奨のサービスはすべて、getService()/getServiceAsync() の実行時にハードランタイムブロックになります(references/sandbox-config-surface.md §5 を参照)。アプリは起動しません。
アプリコードをスキャンし、該当箇所を記録して、「手動対応が必要」として Gap-Report に表示します。書き換えは行いません。
→ references/operations.md §6k
6l. FLP シェル機能を利用する OPA テスト(検出+確認)
レイヤー: test-infra(検出+確認)。FLP シェルに依存するジャーニーテストを検出します。認識可能な iframe 切り替えパターンが存在する場合にのみ、修正の適用を提案します。同意なしに変更することはありません。
シグナル:シェル制御セレクター(§6j)、非推奨のサービス呼び出し(§6k)、慣例に基づく名前のページオブジェクトメソッド。
プローブ:P1 = startMyAppInAFrame フラグ、P2 = iStartMyAppInAFrame ヘルパー、P3 = 独自の iframe URL ビルダー。
→ references/operations.md §6l
8. レポート
必ず Gap-Report を出力してください。
== New Sandbox Migration Report ==
App: <app name from package.json>
Path: <APP_ROOT>
Status: ✓ SUCCESSFUL | ✗ FAILED
── Automatically applied ──────────────────────────────────────────────
✓/✗ webapp/test/<filename>.html (HTML transformed)
✓/✗ webapp/test/fioriSandboxAppConfig.json (created)
✓/— webapp/test/sandbox/<hookModule>.js (created / reused / rewrote-legacy)
✓/— rta: "<fakeLRep filename>" (written to config)
✓/— opaTests.qunit.html (resource root rebound)
✓/— Common.js (scenario URL param injected)
✓/— Hook-graph: <N> trivial replacement(s) auto-applied
── Manual action required ─────────────────────────────────────────────
✗ <ServiceName> (deprecated — hard runtime error): <file>:<line>
→ <successor from sandbox-config-surface.md §5>
✗ Custom FakeLrep connector at <path>
→ May have sap/ushell dependencies incompatible with beforeFlpStart.
✗ Hook-graph — architectural-relocatable: <module> uses <sap/ushell/X>
→ [diff sketch]
✗ Hook-graph — manual-required: <module> uses <sap/ushell/X> at load time
→ [textual sketch]
✗ <Layer-2 step> — pattern not recognised
→ [description]
── Advisory (no migration blocker) ───────────────────────────────────
ℹ <N> QUnit 1.x pattern(s) in <M> file(s)
ℹ Shell-control test patterns: <N> in <M> files (S1: ?, S2: ?, S3: ?)
ℹ locate-reuse-libs.js: script tag removed — deprecated pattern, safe.
ℹ <other non-standard patterns>
[On failure: "Rolled back. Partial attempt saved to webapp/test/.migration-attempt/"]
検出結果のないセクションはレポートから省略されます。
9. レガシーファイルのクリーンアップ(必須 — 省略禁止)
- ウィザードを使用しない場合: レガシー HTML はその場で変換されるため、削除する追加ファイルはありません。
- ウィザードを使用した場合: 古い HTML ファイルをすべて削除します(対象ファイルを除く)。
- 常に: 各
externalUshellConfigFile[]を削除します。
rm <obsolete-file-1> <obsolete-file-2> ...
確認: ls webapp/test/flp*.html — 移行済みの対象ファイルだけが残っていることを確認します。
10. ロールバック
§6 の実行中に失敗した場合:
途中までの作業を保存:
mkdir -p $APP_ROOT/webapp/test/.migration-attempt
cp $APP_ROOT/webapp/test/*.html $APP_ROOT/webapp/test/.migration-attempt/ 2>/dev/null
cp $APP_ROOT/webapp/test/fioriSandboxAppConfig.json $APP_ROOT/webapp/test/.migration-attempt/ 2>/dev/null
復元:
- Git の場合:
git checkout -- webapp/test/ && git stash pop - Git を使用していない場合:
cp $APP_ROOT/webapp/test/.migration-backup/* $APP_ROOT/webapp/test/
ステータスを FAILED として Gap-Report を出力します。