Chargement dynamique des packages dans SharePoint Framework

Lors de la création de composants SharePoint Framework, il est courant de se référer à des bibliothèques tierces, comme Office UI Fabric React, en ce qui concerne les contrôles d’interface utilisateur ou au Moment.js pour la gestion du temps. Chacune de ces bibliothèques s’ajoute à la taille du fichier JavaScript groupé du composant. À titre d’exemple, Moment.js ajoute environ 250 Ko au Bundle obtenu.

Notes

Un fichier groupé JavaScript est un fichier JavaScript qui combine un ou plusieurs fichiers JavaScript ou des feuilles de style. Lorsque vous regroupez une solution SPFx, par défaut, l’ensemble de votre code et les bibliothèques que vous importez dans votre projet sont groupées dans un fichier *.js. Le fractionnement d’un fichier groupé consiste à générer plusieurs fichiers *.js plutôt qu’un, afin de pouvoir les charger individuellement.

Selon le composant, ces bibliothèques tierces sont utilisables ou non dans toutes les phases du cycle de vie du composant. Elles peuvent être utilisées uniquement en mode d’édition ou dans le volet de propriétés. Elles peuvent aussi être nécessaires une fois qu’un utilisateur clique sur un lien ou un bouton dans le composant.

Si le composant SPFx ressemble plutôt à une application monopage (SPA), l’optimisation de la taille peut être sans importance. En revanche, s’il s’agit d’un composant WebPart ajouté à une page ou utilisé plusieurs fois sur une page, comme un composant WebPart de recherche, il est important de réduire la quantité de script chargée et la quantité de script exécutée afin de réduire le temps de chargement de la page.

Pour optimiser la vitesse de chargement d’une page par un composant SPFx, vous pouvez tirer parti du fractionnement de fichier groupé en plusieurs parties de code JavaScript. Ensuite, chargez individuellement ces packages groupés de manière dynamique selon vos besoins.

Fractionner plusieurs composants WebPart à charger individuellement

Un projet SPFx avec plusieurs composants WebPart ou extensions contient le fichier ./config/config.json semblable à ce qui suit :

{
  "$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": {}
}

Dans la configuration ci-dessus, les deux composants WebPart sont inclus dans le même groupe JavaScript. Cela signifie que lorsqu’un utilisateur ajoute l’un des composants WebPart à une page, les deux y sont chargés. L’exemple de scénarios dans lesquels les deux composants WebPart se trouvent sur la même page en même temps est excellent car il illustre que le temps de téléchargement est réduit du fait du chargement d’un fichier au lieu de deux.

Toutefois, si les composants WebPart sont utilisés séparément, il est préférable de les fractionner en deux fichiers pour réduire ce que la page doit télécharger pour exécuter uniquement l’un d’entre eux.

Pour ce faire, modifiez config/config.json pour que chaque composant WebPart soit regroupé en tant que fichier JavaScript distinct :

{
  "$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": {}
}

Analyser votre fichier groupé

Pour découvrir comment lancer l’optimisation, reportez-vous à l’article relatif à l’optimisation des builds SharePoint Framework pour la production, qui indique comment obtenir une carte visuelle de la partie du code ou de la bibliothèque tierce qui occupe de l’espace dans votre fichier groupé.

Charger des composants tiers de manière dynamique

Lorsqu’une solution SharePoint Framework est groupée, la chaîne d’outils de la build utilise webPack pour générer le ou les fichiers groupés. L’une des fonctionnalités du webpack permet d’importer de manière dynamique certaines parties d’une application. Vous pouvez implémenter ceci dans les projets SharePoint Framework avec une refactorisation de code mineure.

Importation normale

Dans le code suivant, la bibliothèque Moment.js va être incluse dans le fichier groupé JavaScript de la solution. Ce code est toujours chargé sur la page même si la méthode GetTime() n’est jamais appelée.

import * as moment from moment

export default class MyClass {
  public GetTime(dateString:string){
    return moment(dateString).format("LL");
  }
}

Importation dynamique

Cependant, dans le code suivant, la bibliothèque moment.js est chargée de façon asynchrone lorsque la méthode GetTime() est appelée, ce qui permet de réduire le temps de chargement initial et le temps d’exécution. Notez le commentaire de code webpackChuckName supplémentaire

export default class MyClass {
  public async GetTime(dateString:string) {
    const moment = await import(
      /* webpackChunkName: 'my-moment' */
      'moment'
    );
    return moment(dateString).format("LL");
  }
}

Notes

Remarque : si votre fichier config/tsconfig.json comporte "module": "commonjs" et non "module": "esnext", vous devez adopter la solution de contournement suivante afin que la bibliothèque dynamique soit fractionnée en dehors du fichier groupé.

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");
  }
}

Vérification du fractionnement de code et de l’importation dynamique

Pour vérifier qu’une importation dynamique est en cours, ouvrez le dossier ./dist après exécution de la tâche gulp bundle et recherchez la bibliothèque chargée dynamiquement en tant que fichier JavaScript séparé. Dans l’image suivante, la bibliothèque Moment.js est fractionnée dans son propre fichier.

Fichiers groupés multiples

Tous les fichiers ou toutes les bibliothèques n’ont pas besoin d’être importés de manière dynamique. Au lieu de cela, envisagez de regrouper des blocs de code ensemble dans un groupe unique pour certains scénarios ou fonctionnalités.

Par exemple, créez un fichier **MyStuff.ts faisant référence à un certain nombre de bibliothèques, puis chargez dynamiquement le fichier MyStuff. Dans ce cas, les bibliothèques tierces et de partie gauche seront regroupées dans my-stuff.js.

// MyStuff.ts

import { Something } from 'third-party;'
import * as Foo from 'left-party';

// Other file
await import(
  /* webpackChunkName: 'my-stuff' */
  './MyStuff'
);

Chargement dynamique du volet de propriétés spécial

Un autre scénario d’utilisation de cette fonctionnalité est d’importer dynamiquement du code utilisé uniquement dans le volet de propriétés. Dans ce cas, vous devez uniquement télécharger ce code dans le navigateur lorsque le volet de propriétés du composant WebPart est actif.

Dans votre fichier de composant WebPart principal, créez une méthode appelée loadPropertyPaneResources(). Cette méthode s’exécute avant l’affichage du volet de propriétés d’un composant WebPart. Elle charge de manière dynamique les ressources nécessaires pour le volet de propriétés uniquement.

  1. Créez un fichier (par exemple, HelloWorldWebPartPropertyPaneStuff.ts).
  2. Déplacez l’ensemble du code lié au volet de propriétés vers ce fichier
  3. Créez la méthode suivante dans la classe de composant WebPart principal.
protected loadPropertyPaneResources(): Promise<void> {
  return import(
    /* webpackChunkName: 'HelloWorldWebPartPropertyPaneStuff' */
    './HelloWorldWebPartPropertyPaneStuff'
  ).then(component => {
    this._propertyPaneHelper = new component.HelloWorldWebPartPropertyPaneStuff(this);
  });
}

Résumé

Lors de la création de solutions SPFx constituées de plusieurs composants ou si vous utilisez des bibliothèques tierces, envisagez des importations dynamiques. Analysez tout d’abord la taille du fichier groupé résultant et utilisez les stratégies présentées dans cette page pour fractionner le code en plusieurs groupes dans lesquels chacun d’eux est chargé uniquement lorsque c’est nécessaire. Cette action permet de réduire le temps nécessaire à l’utilisateur final pour charger et exécuter la page.