拡張テンプレート
拡張テンプレートは、PWA Kit v3 に導入された機能です。この機能の目的は、テンプレートをカスタマイズすることで、PWA Kit プロジェクトをより簡単に構築できるようにすることです。Retail React App などの既存のベーステンプレートをカスタマイズすることも、独自のテンプレートを作成することも可能です。PWA Kit コミュニティのメンバーがベーステンプレートを相互に共有することをお勧めします。
拡張テンプレートにより、テンプレート内のすべてのファイルを複製することなく、選択したテンプレートを変更できます。
拡張テンプレートはオプションの機能です。ただし、2023 年 6 月 15 日以降に生成された新しいプロジェクトでは、拡張テンプレートを使用するように自動的に構成されます。
PWA Kit v3 では、プロジェクトにベーステンプレートと overrides ディレクトリを含めることができ、どちらもプロジェクトの package.json
ファイルで構成できます。拡張テンプレートを使用するには、package.json
の ccExtensibility.extends
でベーステンプレートを宣言し、ccExtensibility.overridesDir
で overrides ディレクトリを宣言する必要があります。(構成の詳細については、次のセクションで説明します。)
ベーステンプレートは、別の PWA Kit プロジェクトがそのファイルの一部を上書きできるように事前構成された、完全に機能する PWA Kit プロジェクトを含む npm モジュールです。これは、「拡張性アプリ」または「拡張可能アプリ」と呼ばれることもあります。"
overrides ディレクトリは、ベーステンプレート内の対応するファイルを上書きするファイルを保存できる、プロジェクト内のディレクトリです。
すでに上書きディレクトリを定義し、Retail React App をベーステンプレートとして定義していると仮定しましょう。Retail React App のホームページコンポーネントを上書きするとします。Retail React App では、ホームページコンポーネントのコードは @salesforce/retail-react-app
パッケージ内の app/pages/home/index.jsx
にあります。そのファイルを上書きするには、package.json
の ccExtensibility.overridesDir
で宣言されたディレクトリに同じファイルを再作成する必要があります。つまり、新しいファイルのパスは <ccExtensibility.overridesDir>/app/pages/home/index.jsx
になります。
これで、index.jsx
が @salesforce/retail-react-app
パッケージ内のいずれかのファイルにインポートされるたびに、パッケージ内のファイルではなく、overrides ディレクトリ内のファイルが読み込まれるようになりました。ファイル名のベースが同じであるだけで、上書きが行えます。ファイル拡張子は異なる場合があります。
アプリを構築するにつれて、ベーステンプレートから overrides ディレクトリにファイルを徐々に追加できます。
上書きするファイル数が増えるほど、ベーステンプレートの変更に対応するために必要な作業が増えることになります。
拡張テンプレートの動作を確認するには、npx @salesforce/pwa-kit-create-app@latest --outputDir <path/to/new/local/project>
を実行して新しい PWA Kit v3 プロジェクトを生成します。
生成されたプロジェクトは Retail React App のベーステンプレートを使用しており、https://pwa-kit.mobify-storefront.com/ とほぼ同じ外観のアプリです。
拡張テンプレートに関するチュートリアルでは、いくつかの一般的なカスタマイズをサイトに追加する方法を学習します。
- コンポーネントのカスタマイズ: コンポーネントレベルの拡張性
- ページのカスタマイズ: ページレベルの拡張性
このセクションの手順では、拡張テンプレートの機能が有効になっていない状態で生成された既存のプロジェクトに対し、拡張テンプレートを有効にすることを前提としています。
最新バージョンの Retail React App にアップグレードするには、次のコマンドを実行します。
npm install @salesforce/retail-react-app@latest
このコマンドを実行した後は、サイトをテストして、期待どおりに動作することを確認することをお勧めします。
ベーステンプレートを定義するには、プロジェクトの package.json
ファイルに npm 依存関係として @salesforce/retail-react-app
(または別のテンプレート) を追加します。
その後、以下のキーと値を使用して ccExtensibility
キーを package.json
に追加します。
Retail React App 以外のベーステンプレートを使用している場合は、@salesforce/retail-react-app
を他のテンプレートのパッケージ識別子に置き換えることを忘れないでください。
overridesDir
の値をカスタムディレクトリ名に置き換えることもできますが、プロジェクト (およびサンプルコード) 間の一貫性を保つために overrides
を使用することをお勧めします。
メインプロジェクトとベーステンプレートの両方に同じ npm 依存関係をリストしないでください。プロジェクトの package.json
にリストされている依存関係が、ベーステンプレートの依存関係と異なることを確認します。これにより、@salesforce/pwa-kit-dev
は、依存関係の解決で 2 つを区別できるようになります。構成の説明に従って、メインプロジェクトの package.json
でベーステンプレートを定義します。メインプロジェクトは、それ自体から継承することはできません。
プロジェクトには、package.json
ファイルにリストされているベーステンプレートの npm 依存関係とバージョン競合があってはなりません。基になるテンプレートで @chakra-ui
が使用されている場合、プロジェクトにもそれが依存関係として含まれており、同じバージョンでなければなりません。この予防策により、同じパッケージのバージョンの競合によるバンドルの偶発的な肥大化 (機能の破損は言うまでもなく) を防げます。このルールには例外が 1 つあります。それは、特定の依存関係をインポートするベーステンプレート内のすべてのファイルに上書きを追加した場合です。この場合、上書きを介して依存関係をインポートするすべてのファイルが削除されているため、依存関係のベーステンプレートのバージョンはプロジェクトにインポートされません。
基になるテンプレートで使用されていない追加の npm 依存関係を追加しても問題ありません。 👌
Managed Runtime にデプロイされるすべての PWA Kit プロジェクトには、次のファイルが必要です。
<overridesDir>/app/main.jsx
<overridesDir>/app/ssr.js
<overridesDir>/app/routes.jsx
<overridesDir>/app/request-processor.js
config/default.js
(例外:package.json
でmobify
キーを使用してサイト構成データを保存している場合)
プロジェクト内の動作をカスタマイズするには、@salesforce/retail-react-app
でこれらのファイルを上書きするのが一般的です。
app/pages/home/index.jsx
: デフォルトの Salesforce マーケティングコンテンツをホームページから削除することは、ほとんどすべてのプロジェクトで最初のステップとなります。app/static/*
: これらのファイルは、サイトのブランドを決定するためにデスクトップおよびモバイルブラウザーで使用されるアイコンを提供するデフォルトです。自社のブランドに合わせて更新してください。app/constants.js
app/assets/svg/brand-logo.svg
: このファイルはジェネレータープロジェクトで上書きされます。この例に従い、プロジェクト内の他のアイコンを上書きします。
この「API としてのファイルシステム」設定の目的は、基になるファイルを見つけてコピーし、動作とロジックをカスタマイズできるようにすることです。コードを、多くのサブコンポーネントを調整する小さなファイルに分割すると、上書きする動作のみをターゲットにしやすくなります。
そうは言っても、ファイルの動作の一部だけを変更するために、ファイルを overrides ディレクトリにコピーしなければならない場合があります。テンプレートのバージョンを変更しても拡張プロジェクトでコードを手動で更新しなくてもすむように、可能な限り、基になるテンプレートのエクスポートをインポートして再エクスポートすることをお勧めします。
たとえば、生成されたプロジェクト の routes.jsx
ファイルでは、デフォルトのルートが import {routes as _routes} from '@salesforce/retail-react-app/app/routes'
経由でインポートされていることに注意しましょう。_routes
は、これらのデフォルトのルートが外部依存によって管理されていることを示す規則として意図されています。ファイル @salesforce/retail-react-app/app/routes.jsx
と同様、routes.jsx
のカスタム実装は、ルートをエクスポートします。つまり、これは /
(ホーム) ルートを追加します。React Router は、routes 配列内の指定されたパス名の最初の項目を見つけるため、新しいルートはデフォルトのルートよりも優先されます。
相対的インポートは、拡張テンプレートを使用するほとんどのプロジェクトにとって最良のアプローチです。ベーステンプレート内のファイル (@salesforce/retail-react-app
など) のインポート動作には、overrides ディレクトリ内のファイルを優先する特別なロジックがあります。このインポートロジックは、overrides ディレクトリ内のファイルには適用されません。したがって、ほとんどの実装では相対的インポートを使用することをお勧めします。
拡張テンプレートを使用する際に注意する問題の 1 つに、競合する 2 つの異なるファイルを誤ってインポートしてしまうというものがあります。PWA Kit プロジェクトは @salesforce/pwa-kit-dev
によってビルドされ、内部で webpack を使用しています。@salesforce/pwa-kit-dev
には、拡張テンプレートの「上書き」機能を有効にするプラグインがあります。このプラグインは、すべての webpack ファイルのリクエストを検査し、次の 2 つの質問をします。
- このファイルのリクエストはベーステンプレートからのものですか?
- このファイルは overrides ディレクトリ内に存在しますか?
両方の質問に対する答えが「はい」の場合、ファイルリクエストはビルド時に overrides ディレクトリ内のファイルを指すように書き換えられます。
このロジックは、overrides ディレクトリから発生する webpack ファイルのリクエストには作用しません。したがって、overrides ディレクトリとベーステンプレートの両方から同じファイルをインポートすることが可能です。この状況が、たとえば @saleforce/retail-react-app/my-file
と <overrides directory>/my-file
が同じバンドルにインポートされている場合に発生すると、webpack は、can’t find <export name> from <filename>
のような紛らわしいエラーをスローします。webpack がこのエラーをスローするのは、どのインポートがバンドルに含める対象となるのか、バンドルが認識していないためです。
同等のファイルが上書きに存在する場合は、1 つの顕著な例外を除き、ベーステンプレートからファイルをインポートしないようにすることが重要です。特殊ファイルセクションのコード例で前に説明し、constants.js
で示したように、基になるテンプレートをインポートし、そのすべてのエクスポートを再エクスポートし、必要な数のエクスポートを上書きまたは追加することをお勧めします。
app/components/_app/index.jsx
コンポーネントを上書きする必要がある場合、Header
、Footer
、DrawerMenu
などの多くのグローバルコンポーネントが存在します。_app/index.jsx
上書きが設定された後、ベーステンプレートがこのコンポーネントをインポートしようとすると、ファイルリクエストは <ccExtensibility.overridesDir>/app/components/_app/index.jsx
に再ルーティングされます。しかし、ここに落とし穴があります。Header
と Footer
は app/components/_app/index.jsx
によってインポートされるため、_app/index.jsx
でもインポートを更新する必要が出てくるのです。それ以外の場合、_app/index.jsx
はベーステンプレートから Header
と Footer
をインポートします。
ccExtensibility.extends
からの ECMAScript インポートは、@salesforce/pwa-kit-dev
がその名前のファイルを複数の場所でチェックし、ccExtensibility.overridesDir
が優先されるという点で「マジカル」です。
一方で、<ccExtensibility.overridesDir>/*
からのインポートには魔法のような動作はなく、目的のファイルをターゲットにする必要があるため、次のように <ccExtensibility.overridesDir>/app/components/header/index.jsx
を <ccExtensibility.overridesDir>/app/components/_app/index.jsx
に明示的にインポートする必要があります。
このようにパッケージからインポートはしないでください。overrides ディレクトリ内のヘッダーがバイパスされるためです。
routes.jsx
は特殊ファイルであることに注意してください。これは、アプリケーション全体の webpack 用語での「entryPoint」を形成します。routes.jsx
で何かが正しく設定されていない場合、pwa-kit-dev
のルートベースのチャンクが適切に解決されないため、コンパイル段階でアプリ全体が失敗します。このため、デフォルト @salesforce/retail-react-app/app/routes.jsx
とローカル routes.jsx
からのインポートを overridesDir
に混合することで、ルートを適切に拡張する方法の例を含めます。
このインポートは「ツリーの最上部」にあるため、これらのファイルを上書きしてから footer.jsx
を上書きする場合は、_app/index.jsx
に戻って、相対的テンプレートインポートを指すようにそのインポートを変更する必要があります。
テンプレート拡張システムの既知の制限事項は、retail-react-app/constants
を魔法のように取り込むことにより、たとえばベーステンプレート (@salesforce/retail-react-app
) がこのファイルをインポートするたびに、同じ値がエクスポートされることが期待されることです。
overrides 内のファイルが、ベーステンプレート内の同等の ECMAScript エクスポートと同じ ECMAScript エクスポートのエクスポートに失敗すると、以下のような予期しないエラーが発生する場合があります。
constants.js
ファイルを overrides ディレクトリに次のように追加すると、エラーが発生します。
エラーメッセージの例です。
このエラーの理由は、CAT_MENU_DEFAULT_ROOT_CATEGORY
が @salesforce/retail-react-app/components/_app/index.jsx
で予期されたエクスポートであり、それを上記の唯一のエクスポート CUSTOM_MESSAGE
で上書きする過程で、constants.js
によってエクスポートされるとき、基礎となる「API コントラクト」(ファイルが指定された値に依存する機能、この場合は CAT_MENU_DEFAULT_ROOT_CATEGORY
) が上書きによって破られてしまうためです。
正しいアプローチは次のようになります。このアプローチにより、必須かつ予期されるエクスポートとしての CAT_MENU_DEFAULT_ROOT_CATEGORY
の省略が回避され、エクスポートされた API の一貫性が維持されます。
このアプローチは、追加の変更の場合にのみ機能します。次の例では、基になる retail-react-app/constants.js
ファイルのエクスポートにない CUSTOM_MESSAGE
エクスポートを追加します。
このアプローチは、DEFAULT_LOCALE
が retail-react-app/constants
によってエクスポートされ、その値を変更する次のシナリオにおいて機能します。
テンプレートフックは、Retail React App テンプレートを操作するための新しい方法で、これまではコマンド npx pwa-kit-create-app
(現在は npx @salesforce/pwa-kit-create-app
に名前変更) を介して利用可能でした。
テンプレート拡張機能の一部として、新しい「テンプレートフック」が @salesforce/retail-react-app
に追加されました。これは、次のリストに列挙されているコンポーネントの小さなサブセットのグローバルな追加をサポートします。デフォルトでは、これらの各コンポーネントは null
を返し、完成した PWA Kit 実装プロジェクトに不必要な肥大化を避けるために意図的に空になっています。ベース @salesforce/retail-react-app
は、これらのコンポーネントに機能を追加することはありません。テンプレートフックは常に null
を返します。これは、顧客の実装がこれらの場所でテンプレートに「フック」して、必要以上のファイルを上書きすることなくプロジェクトをカスタマイズできるようにするためです。
@salesforce/retail-react-app@1.0.0
の時点で、次のテンプレートフックが利用可能です。
app/components/_app/partials/above-header.jsx
app/pages/product-list/partials/above-page-header.jsx
PWA Kit v3 のリリース時点では、公開されている拡張可能なベーステンプレートは @salesforce/retail-react-app
のみです (今後さらに多くのテンプレートが追加される予定です)。
ベーステンプレートとして使用するには、PWA Kit プロジェクトを npm に公開し、そのすべての ECMAScript インポートにパッケージ名と一致する値を接頭辞として付ける必要があります。たとえば、@salesforce/retail-react-app
は npm で公開されており、そのインポートには @salesforce/retail-react-app
という接頭辞が付きます。この接頭辞はパッケージのルートディレクトリへの参照であり、パッケージがベーステンプレートとして適切に動作するために必要です。
PWA Kit プロジェクトを拡張可能なベーステンプレートとして使用するには、すべてのインポートに <npm package name>
を使用する必要があります。たとえば、@salesforce/retail-react-app
は package.json
に ccExtensibility
を追加します。これにより、ローカル IDE 参照 (@salesforce/retail-react-app/app/components/_app
など) が適切に解決されます。
- Retail React App テンプレートをコピーして編集する代わりに、拡張テンプレートを使用します。
- 変更を加えたら、プロジェクトを定期的にテストして、発生した問題を特定して修正します。
- カスタマイズした機能を非本番環境でテストしてから、本番環境にデプロイします。
- 必要に応じて上書きを反復処理し、動作を調整します。
このセクションでは、テンプレートの機能拡張の使用中に発生する可能性がある一般的なエラーに対して推奨される解決策を示します。
プロジェクト内のファイルを変更した後に、サイトをプレビューしても更新内容が表示されません。
原因: ローカルサーバーを再起動していません。
推奨される解決策: npm start
を実行してから、もう一度サイトをプレビューします。
これは、バージョン 3 より前のバージョンの PWA Kit を使用している場合にのみ適用されます。
原因: 必要な ccExtensibility
構成が package.json
ファイルにありません。
推奨される解決策: package.json
でこの構成を完了します。
原因: 必要なファイルが overrides ディレクトリ (overridesDir
) にありません。
推奨される解決策: 必要なすべてのファイルがプロジェクトの overrides
ディレクトリに含まれていることを確認します。必須のプロジェクトファイルを参照してください。
原因: ベーステンプレートとプロジェクトの間に競合するバージョンの依存関係があります。
推奨される解決策: ベーステンプレートとプロジェクトの両方で、同じバージョンの共有依存関係が使用されていることを確認します。バージョンの競合を参照してください。