SharePoint Framework コンポーネントの作成時には、ユーザー インターフェース コントロールの Office UI Fabric React や時間処理の Moment.js など、サード パーティ製のライブラリを参照することがよくあります。 これらの各ライブラリによって、コンポーネントにバンドルされる JavaScript ファイルのサイズが増加します。 例として、Moment.js は結果のバンドルに最大 250 KB を追加します。
注:
JavaScript バンドル は、1 つ以上の JavaScript ファイルまたはスタイル シートを組み合わせた JavaScript ファイルです。 SPFx ソリューションをパッケージ化すると、既定では、すべてのコードとプロジェクトにインポートするライブラリが 1 つの *.js ファイルにバンドルされます。 バンドルを分割することは、個別に読み込まれるように、1 つではなく複数の *.js ファイルを生成する操作です。
コンポーネントによっては、これらのサードパーティ製のライブラリがコンポーネントのライフサイクルのすべての部分で使用される場合と使用されない場合があります。 編集モードまたはプロパティ ウィンドウでのみ使用される場合もあれば、ユーザーがコンポーネント内のリンクやボタンをクリックしたときに必要になる場合もあります。
SPFx コンポーネントがシングル ページ アプリケーション (SPA) のようなものであれば、サイズの最適化は重要ではないこともありますが、ページに追加される Web パーツやページで複数回使用される検索 Web パーツなどの場合は、ページにロードされるスクリプトの量と実行されるスクリプトの量を少なくすることがページの読み込み時間に大きく影響します。 これは、モバイルの操作に大きな影響を与える可能性があります。
SPFx コンポーネントのページへの読み込み速度を改善するために、複数の JavaScript パーツにバンドルを分割することの利点を活用できることがあります。分割した個別のバンドル パッケージは必要に応じて動的に読み込むようにします。
複数の Web パーツに分割して個別に読み込まれるようにする
複数の Web パーツまたは拡張機能を含む SPFx プロジェクトには、次のようなファイル ./config/config.json が含まれています:
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"my-spfx": {
"components": [
{
"entrypoint": "./lib/webparts/part1/part1.js",
"manifest": "./src/webparts/part1/part1.manifest.json"
},
{
"entrypoint": "./lib/webparts/part2/part2.js",
"manifest": "./src/webparts/part2/part2.manifest.json"
}
]
}
},
"externals": {},
"localizedResources": {}
}
上記の構成では、両方の Web パーツが同じ JavaScript バンドルに含まれています。 そのため、ユーザーが一方の Web パーツをページに追加しても、両方が読み込まれることになります。 両方の Web パーツが同時に同じページにあるシナリオの場合、2 つではなく 1 つのファイルをダウンロードする読み込み時間が短縮されるため、これは問題ありません。
ただし、それらの Web パーツが個別に使用される場合は、2 つのファイルに分割して、そのうちの1つだけを実行するためにページがダウンロードする必要があるものを減らしたほうが良くなります。
これは、それぞれの Web パーツが個別の JavaScript ファイルとしてバンドルされるように config/config.json を変更することで実現できます:
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"my-spfx-1": {
"components": [
{
"entrypoint": "./lib/webparts/part1/part1.js",
"manifest": "./src/webparts/part1/part1.manifest.json"
}
]
},
"my-spfx-2": {
"components": [
{
"entrypoint": "./lib/webparts/part2/part2.js",
"manifest": "./src/webparts/part2/part2.manifest.json"
}
]
}
},
"externals": {},
"localizedResources": {}
}
バンドルを分析する
どこから開始、最適化するかの概要を確認するには、運用環境用のビルドSharePoint Framework最適化に関する記事を参照してください。これは、コードまたはサードパーティライブラリのどの部分がバンドル内の領域を占めるかを視覚的にマップする方法を示しています。
サードパーティ製のコンポーネントを動的に読み込む
SharePoint Framework ソリューションをパッケージ化すると、ビルド ツールチェーンは、バンドルを生成するために webpack を使用します。 webpack の機能の 1 つとして、アプリケーションのパーツを動的にインポートできる機能があります。 これは、マイナー コード リファクタリングを使用して SharePoint Framework プロジェクトに実装できます。
通常のインポート
次のコードでは、Moment.js ライブラリがソリューションの JavaScript バンドルに含まれています。 このコードは、メソッド GetTime() が呼び出されない場合でも、常にページに読み込まれます。
import * as moment from moment
export default class MyClass {
public GetTime(dateString:string){
return moment(dateString).format("LL");
}
}
動的インポート
ただし、次のコードでは、GetTime() メソッドが呼び出されたときに Moment.js ライブラリが非同期に読み込まれるため、初期読み込みと実行時間が短縮されます。 追加の webpackChuckName コードのコメントに注意してください
export default class MyClass {
public async GetTime(dateString:string) {
const moment = await import(
/* webpackChunkName: 'my-moment' */
'moment'
);
return moment(dateString).format("LL");
}
}
注:
注: config/tsconfig.json ファイルに "module": "commonjs" があり "module": "esnext" がない場合は、バンドルからダイナミック ライブラリを分割するために、次に示す回避策が必要になります。
declare var System: any;
export default class MyClass {
public async GetTime(dateString:string){
const moment = await System.import(
/* webpackChunkName: 'my-moment' */
'moment'
);
return moment(dateString).format("LL");
}
}
コードの分割と動的インポートを検証する
動的インポートが行われていることを確認するには、gulp バンドル タスクの実行後に ./dist フォルダーを開き、動的に読み込まれたライブラリを別の JavaScript ファイルとして探します。 次の画像では、Moment.js ライブラリが独自のファイルに分割されています。

すべてのファイルまたはライブラリを動的にインポートする必要はありません。 代わりに、特定のシナリオまたは機能のコード ブロックのように 1 つのバンドルにグループ化することを検討してください。
たとえば、多数のライブラリを参照するファイル **MyStuff.ts を作成してから、MyStuff を動的に読み込みます。 この場合、サードパーティ と レフトパーティ のライブラリは my-stuff.js にバンドルされます。
// MyStuff.ts
import { Something } from 'third-party;'
import * as Foo from 'left-party';
// Other file
await import(
/* webpackChunkName: 'my-stuff' */
'./MyStuff'
);
特別なプロパティ ウィンドウの動的な読み込み
この機能のもう 1 つの使用例は、プロパティ ウィンドウでのみ使用されるコードを動的にインポートすることです。 この場合、このコードは、Web パーツのプロパティ ウィンドウがアクティブなときにのみブラウザにダウンロードする必要があります。
メインの Web パーツ ファイルで、loadPropertyPaneResources() という名前のメソッドを作成します。 このメソッドは、Web パーツのプロパティ ウィンドウが表示される前に実行されます。 これにより、そのプロパティ ウィンドウに必要なリソースの動的な読み込みが可能になります。
- 新しいファイル HelloWorldWebPartPropertyPaneStuff.ts を作成する
- そのファイルに、すべてのプロパティ ウィンドウに関連するコードを移動する
- 次のメソッドをメインの Web パーツ クラス内に作成する
protected loadPropertyPaneResources(): Promise<void> {
return import(
/* webpackChunkName: 'HelloWorldWebPartPropertyPaneStuff' */
'./HelloWorldWebPartPropertyPaneStuff'
).then(component => {
this._propertyPaneHelper = new component.HelloWorldWebPartPropertyPaneStuff(this);
});
}
要約
複数のコンポーネントで構成される SPFx ソリューションを構築する場合、またはサードパーティ製のライブラリを使用している場合は、動的インポートを検討してください。 まず、結果として得られたバンドル サイズを分析し、このページで説明されている戦略を使用して、各コードが必要な場合にのみ読み込まれる複数のバンドルにコードを分割します。 これにより、エンド ユーザーがページを読み込んで実行するのにかかる時間が短縮されます。