SharePoint Framework のクライアント側 Web パーツで既存の JavaScript ライブラリを使用する

クライアント側の Web パーツを SharePoint Framework 上に構築する場合、既存の JavaScript ライブラリを利用して強力なソリューションを構築できます。 ただし、Web パーツによって使用中の SharePoint ページのパフォーマンスが低下しないように、いくつかの考慮事項に留意する必要があります。

パッケージとして既存のライブラリを参照する

SharePoint Framework クライアント側の Web パーツで既存の JavaScript ライブラリを参照する最も一般的な方法には、これをパッケージとしてプロジェクトにインストールする方法があります。

  1. たとえば、Angular をクライアント側の Web パーツで使用する場合、最初に npm を使用して Angular をインストールします。

    npm install angular --save
    
  2. Angular を TypeScript で使用するには、NPM を使用して型宣言をインストールします。

    npm install @types/angular --save-dev
    
  3. import ステートメントを使用して Web パーツで Angular を参照します。

    import { Version } from '@microsoft/sp-core-library';
    import {
      BaseClientSideWebPart,
      IPropertyPaneConfiguration,
      PropertyPaneTextField
    } from '@microsoft/sp-webpart-base';
    import { escape } from '@microsoft/sp-lodash-subset';
    
    import styles from './HelloWorld.module.scss';
    import * as strings from 'helloWorldStrings';
    import { IHelloWorldWebPartProps } from './IHelloWorldWebPartProps';
    
    import * as angular from 'angular';
    
    export default class HelloWorldWebPart extends BaseClientSideWebPart<IHelloWorldWebPartProps> {
      public render(): void {
        this.domElement.innerHTML = `
          <div class="${styles.helloWorld}">
            <!-- omitted for brevity -->
          </div>`;
    
          angular.module('helloworld', []);
    
          angular.bootstrap(this.domElement, ['helloworld']);
      }
    
      // omitted for brevity
    }
    

Web パーツのリソースをバンドルする

SharePoint Framework では、gulp や Webpack など、オープンソースのツールに基づいてビルドのツールチェーンを使用します。 SharePoint Framework プロジェクトを構築する場合、これらのビルド ツールがバンドルと呼ばれるプロセスですべての参照用リソースを単一の JavaScript ファイルに自動的に結合します。

出力ファイルを含む SharePoint Framework 配布フォルダーの横に表示される、gulp バンドル タスクを含むコマンド ウィンドウ

バンドルには、さまざまな利点があります。 まず、Web パーツで必要なすべてのリソースを単一の JavaScript ファイルで入手できます。 これによって、Web パーツが単一のファイルで構成されるため展開が容易になり、展開のプロセスで依存関係を見逃すことがなくなります。

Web パーツではさまざまなリソースを使用するので、正しい順序で読み込む必要があります。 ビルド中に Webpack によって生成される Web パーツのバンドルは、さまざまなリソースの読み込みを管理し、それらのリソースの間の依存関係を解決することもできます。

一般に、Web パーツのバンドルはエンドユーザーにとっても、小さいファイルを多数ダウンロードするのではなく、大きい 1 つのファイルで高速にダウンロードできるという利点があります。 多数の小さなファイルを 1 つの大きいバンドルに組み合わせることで、ページでの Web パーツの読み込みが速くなります

ただし、既存の JavaScript ライブラリを SharePoint Framework クライアント側の Web パーツとバンドルすることは、欠点がないわけではありません。

既存の JavaScript フレームワークを SharePoint Framework 内にバンドルする場合、参照されるすべてのスクリプトが、生成されたバンドル ファイルに組み込まれます。 次の Angular の例では、Angular を含めて最適化された Web パーツのバンドルは、170 KB を超えています。

強調表示されている Hello World バンドル JavaScript ファイルを示すエクスプローラー画面の展開フォルダーのスクリーンショット。

同じく Angular を使用する別の Web パーツをプロジェクトに追加してプロジェクトを構築すると、それぞれの Web パーツ用に、170 KB を超えるバンドル ファイルが 2 つになります。

強調表示されている 2 つの Hello World バンドル JavaScript ファイルを示すエクスプローラー画面の展開フォルダーのスクリーンショット。

これらの Web パーツを 1 つのページに追加すると、そのページ上でそれぞれの Web パーツについて、各ユーザーが Angular を複数回ダウンロードすることになります。 この方法は効率的ではなく、ページの読み込みも遅くなります。

外部リソースとして既存のライブラリを参照する

より効果的な方法としては、SharePoint Framework のクライアント側の Web パーツで、既存のライブラリを外部リソースとして参照して活用する方法があります。 これにより、Web パーツに含まれる特定のスクリプトに関する情報は、そのスクリプトの URL だけになります。 ページに追加すると、Web パーツは、指定した URL から必要なすべてのリソースを自動的に読み取ろうとします。

SharePoint Framework で既存の JavaScript ライブラリを簡単に参照することができ、特にコードを変更する必要はありません。 ライブラリは実行時に指定した URL から読み込まれるため、プロジェクトにパッケージとしてインストールする必要もありません。

たとえば、Angular を外部リソースとしてクライアント側の Web パーツで参照するには、npm を使用して TypeScript 型宣言をインストールすることから始めます。

npm install @types/angular --save-dev

config/config.json ファイルで externals プロパティに対して次のエントリを追加します。

"angular": {
  "path": "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js",
  "globalName": "angular"
}

完全な config/config.json ファイルは次のようになります。

{
  "entries": [
    {
      "entry": "./lib/webparts/helloWorld/HelloWorldWebPart.js",
      "manifest": "./src/webparts/helloWorld/HelloWorldWebPart.manifest.json",
      "outputPath": "./dist/hello-world.bundle.js"
    }
  ],
  "externals": {
    "angular": {
      "path": "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js",
      "globalName": "angular"
    }
  },
  "localizedResources": {
    "helloWorldStrings": "webparts/helloWorld/loc/{locale}.js"
  }
}

以下のように Web パーツで Angular を参照します。

import { Version } from '@microsoft/sp-core-library';
import {
  BaseClientSideWebPart,
  IPropertyPaneConfiguration,
  PropertyPaneTextField
} from '@microsoft/sp-webpart-base';
import { escape } from '@microsoft/sp-lodash-subset';

import styles from './HelloWorld.module.scss';
import * as strings from 'helloWorldStrings';
import { IHelloWorldWebPartProps } from './IHelloWorldWebPartProps';

import * as angular from 'angular';

export default class HelloWorldWebPart extends BaseClientSideWebPart<IHelloWorldWebPartProps> {
  public render(): void {
    this.domElement.innerHTML = `
      <div class="${styles.helloWorld}">
        <!-- omitted for brevity -->
      </div>`;

      angular.module('helloworld', []);

      angular.bootstrap(this.domElement, ['helloworld']);
  }

  // omitted for brevity
}

この時点でプロジェクトを構築し、生成されたバンドル ファイルのサイズを確認すると、そのサイズは 6 KB まで減少しています。

Hello Word JavaScript ファイルが強調表示された展開フォルダーを示すエクスプローラーのスクリーンショット。

同じく Angular を使用する別の Web パーツをプロジェクトに追加し、プロジェクトをもう一度作成すると、両方のバンドルのサイズはそれぞれ 6 KB になります。

2 つの Hello Word JavaScript ファイルが強調表示された展開フォルダーを示すエクスプローラーのスクリーンショット。

ここで、300 KB 以上を節約できたとは想定できません。 両方の Web パーツでは引き続き Angular が必要であり、ユーザーが Web パーツのあるページに最初にアクセスするときに読み込まれます。

Web パーツが 1 つあるページに対して、開発者ツールで強調表示されている Angular

両方の Angular Web パーツをそのページに追加しても、SharePoint Framework で Angular をダウンロードする回数は 1 回だけです。

Web パーツが 2 つあるページに対して、開発者ツールで強調表示されている Angular

既存の JavaScript ライブラリを外部リソースとして参照すると、実際には一般的に使用するスクリプトすべてを集中管理する場所が社内にあるか、または CDN を使用する場合にメリットがあります。 このようなケースでは、ユーザーのブラウザー キャッシュに特定の JavaScript ライブラリが既にある場合があります。 その結果、読み込む必要があるものは Web パーツのバンドルのみになり、ページの読み込みが高速になります。

Angular を表示せずにページ上の 2 つの Web パーツで使用している開発者用ツールのネットワーク タブ

前述の例では、CDN から Angular を読み込む方法を示していますが、パブリック CDN を使用する必要はありません。 この構成では、パブリック CDN や非公開でホストしているリポジトリから SharePoint ドキュメント ライブラリまで、任意の場所を指定できます。 Web パーツを使用しているユーザーに特定の URL へのアクセス権があれば、Web パーツは想定したとおり動作します。

CDN は、世界中のあらゆる場所にリソースを迅速に配布するため最適化されています。 パブリック CDN からスクリプトを参照するもう 1 つの利点は、過去にユーザーがアクセスした他の Web サイトで、同じスクリプトが使用されている可能性があることです。 つまり、スクリプトは既にローカルのブラウザー キャッシュにあるため、ユーザーの Web パーツ用にダウンロードする必要はなく、Web パーツのあるページの読み込みがさらに速くなります。

一部の組織では、企業ネットワークからのパブリック CDN へのアクセスを許可していません。 このような場合、一般的に使用される JavaScript フレームワークに非公開でホストしている保存場所を使用することもできます。 組織はライブラリをホストしているため、キャッシュ ヘッダーを制御してリソースを最適化し、パフォーマンスをさらに高めることもできます。

JavaScript ライブラリの形式

さまざまな JavaScript ライブラリがそれぞれ別の方法で構築され、パッケージ化されます。 一部はモジュールとしてパッケージされ、また別のものはプレーンなスクリプトとしてグローバル スコープで実行されます (このようなスクリプトは、非モジュール スクリプトとも呼ばれます)。 JavaScript ライブラリを URL から読み込む場合、SharePoint Framework プロジェクトに外部スクリプトを登録する方法はスクリプトの形式によって異なります。 モジュールの形式は AMD、UMD、CommonJS など複数ありますが、理解しておくべきことは、そのスクリプトがモジュールかどうかだけです。

モジュールとしてパッケージ化されたスクリプトは、特定のスクリプトのダウンロード元である URL を指定するだけで登録できます。 その他のスクリプトとの依存関係は、スクリプトのモジュール コンストラクト内で処理されます。

非モジュール スクリプトでは、少なくとも、スクリプトのダウンロード元である URL と、グローバル スコープでスクリプトを登録する変数の名前が必要です。 非モジュール スクリプトが他のスクリプトに依存している場合は、依存関係として追加することができます。 これを説明するため、いくつか例を見てみます。

Angular v1.x は非モジュール スクリプトです。 これは SharePoint Framework プロジェクトで、その URL と、同時に登録するグローバル変数の名前を指定して、外部リソースとして登録します。

"angular": {
  "path": "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js",
  "globalName": "angular"
}

プロパティで指定された名前がスクリプトで globalName 使用される名前に対応することが重要です。 これにより、依存している他のスクリプトにその名前が正しく公開されます。

ngOfficeUIFabric は、Office UI Fabric 向けの Angular ディレクティブであり、Angular に依存している UMD モジュールです。 Angular の依存関係は既にモジュール内で処理されているため、その URL を指定するだけで登録できます。

"ng-office-ui-fabric": "https://cdnjs.cloudflare.com/ajax/libs/ngOfficeUiFabric/0.12.3/ngOfficeUiFabric.js"

jQuery は、AMD スクリプトです。 以下のものを使用するだけで登録できます。

"jquery": "https://code.jquery.com/jquery-2.2.4.js"

非モジュール スクリプトとして配布されている jQuery プラグインの導入された jQuery を使用することを望んでいるとします。

次のコードを使用して両方のスクリプトを登録した場合、Web パーツの読み込みは高い確率でエラーになります。 両方のスクリプトが並行して読み込まれ、プラグイン自体を jQuery に登録できていない可能性があります。

"jquery": "https://code.jquery.com/jquery-2.2.4.js",
"simpleWeather": {
  "path": "https://cdnjs.cloudflare.com/ajax/libs/jquery.simpleWeather/3.1.0/jquery.simpleWeather.min.js",
  "globalName": "jQuery"
}

非モジュールの jQuery プラグインを使用して Web パーツを読み込むときに発生するエラー

前述のとおり、SharePoint Framework では、非モジュール プラグインの依存関係を指定できます。これらの依存関係は、globalDependencies プロパティを使用して指定されます。

"jquery": "https://code.jquery.com/jquery-2.2.4.js",
"simpleWeather": {
  "path": "https://cdnjs.cloudflare.com/ajax/libs/jquery.simpleWeather/3.1.0/jquery.simpleWeather.min.js",
  "globalName": "jQuery",
  "globalDependencies": [ "jquery" ]
}

globalDependencies プロパティで指定されたそれぞれの依存関係は、config/config.json ファイルの externals セクションで別の依存関係を指し示している必要があります。

ここでプロジェクトを構築しようとするとエラーが発生し、非モジュール スクリプトへの依存関係を指定できないというメッセージが表示されることがあります。

モジュールであるスクリプトへの依存関係を指定して、非モジュール スクリプトで SharePoint Framework を構築する場合に発生するエラー

この問題は、jQuery を非モジュール スクリプトとして登録するだけで解決できます。

"jquery": {
  "path": "https://code.jquery.com/jquery-2.1.1.min.js",
  "globalName": "jQuery"
},
"simpleWeather": {
  "path": "https://cdnjs.cloudflare.com/ajax/libs/jquery.simpleWeather/3.1.0/jquery.simpleWeather.min.js",
  "globalName": "jQuery",
  "globalDependencies": [ "jquery" ]
}

この方法では、simpleWeather スクリプトを jQuery の後に読み込み、その jQuery を、simpleWeather jQuery プラグインで必要なグローバルに使用できる変数 jQuery で有効にして、それ自体が登録されるように指定します。

注:

jQuery を登録するためのエントリが、外部リソース名に jquery を使用し、グローバル変数名として jQuery を 使用する方法に注目してください。 外部リソースの名前は、コード内の ステートメントで使用する import 名前です。 これは、TypeScript 型宣言と一致する必要がある名前でもあります。 プロパティを使用して globalName 指定されたグローバル変数名は、ライブラリの上にビルドされたプラグインなどの他のスクリプトに認識される名前です。 一部のライブラリでは、これらの名前は同じである可能性があります。必須ではありません。問題を回避するために、正しい名前を使用していることを慎重に確認する必要があります。

読み込もうとしているスクリプトがモジュールかモジュール以外のスクリプトかを手動で判断するのは困難です。 読み込もうとしているスクリプトが縮小されている場合は特にそうです。 スクリプトが公開されている URL でホストされている場合は、無料の Rencore SharePoint Framework スクリプト チェック ツールを使用して、スクリプトの種類を判断できます。 さらに、このツールを使用すると、スクリプトを読み込んでいるホストの場所が正しく構成されているかどうかを確認することができます。

非モジュール スクリプトに関する考慮事項

過去に開発された多数の JavaScript ライブラリとスクリプトが、非モジュール スクリプトとして配布されています。 SharePoint Framework では非モジュール スクリプトの読み込みをサポートしていますが、可能であれば使用を避けるようにしてください。

モジュール以外のスクリプトは、ページのグローバル スコープに登録されます。1 つの Web パーツによって読み込まれたスクリプトは、ページ上の他のすべての Web パーツで使用できます。 使用している jQuery のバージョンが異なる 2 つの Web パーツがある場合、どちらも非モジュール スクリプトとして読み込まれますが、先に登録された jQuery バージョンはすべて、最後に読み込まれた Web パーツによって上書きされます。

想像されるとおり、これによって予期しない結果が生じることがあります。そのページで別の jQuery バージョンを使用しているその他の Web パーツや、特定の順序で読み込んだ Web パーツなど、特定のシナリオでのみ発生する問題をデバッグすることは困難です。 モジュールのアーキテクチャでは、それぞれのスクリプトを分離して、互いに影響を与えないようにすることでこの問題を解決します。

バンドルを検討する場合

既存の JavaScript ライブラリを Web パーツにバンドルすると、大きな Web パーツ ファイルが発生し、その Web パーツを使用してページのパフォーマンスが低下する可能性があります。 一般的には、JavaScript ライブラリと Web パーツのバンドルは避けられますが、バンドルを活用できる場合もあります。

すべてのイントラネット上で動作する標準ソリューションをバンドルする場合、すべてのリソースを Web ページにバンドルすると、Web ページを想定どおりに機能させることができます。 ソリューションのインストール先は事前に判明していないため、Web パーツのバンドル ファイルにすべての依存関係を含めておくと、CDN やその他の外部の場所からリソースのダウンロードが組織で禁止されている場合でもソリューションが正しく機能します。

ソリューションを構成する Web パーツが多数あり、何らかの機能を共有し合っている場合は、共有する機能を別のライブラリとして構築し、それをすべての Web ページで外部リソースとして参照すると良いでしょう。 これにより、ユーザーは共通ライブラリを 1 回だけダウンロードして、それをすべての Web ページで再利用することができます。

概要

クライアント側の Web パーツを SharePoint Framework 上に構築すると、既存の JavaScript ライブラリを利用して強力なソリューションを構築できます。 SharePoint Framework では、これらのライブラリをユーザーの Web パーツとバンドルしたり、外部リソースとして読み込んだりすることができます。 一般的には、既存のライブラリを URL から読み込むことが推奨されますが、バンドルにメリットがある場合もあり、自社の要件を評価し、ニーズに最も適している方法を慎重に選ぶ必要があります。

関連項目