Aller au contenu

Cas pratique

Créer une web part SPFx qui lit et écrit dans une liste SharePoint : tutoriel PnPjs avec le code complet

Par · ·

Pour qu’une web part SPFx lise et écrive dans une liste SharePoint, installez PnPjs (@pnp/sp), créez une instance avec spfi().using(SPFx(this.context)) dans onInit, puis appelez lists.getByTitle(…).items pour lire et items.add pour écrire. La web part agit avec les droits de l’utilisateur connecté : aucune inscription d’application n’est nécessaire.

Besoin d’un développeur SPFx pour aller plus vite ?Voir l’expertise SPFx

Pourquoi une web part plutôt qu’une simple vue de liste

Une liste SharePoint fait déjà beaucoup : colonnes typées, vues filtrées, droits, historique des versions. Pour beaucoup de besoins, une vue bien réglée suffit. Mais dès que vous voulez une saisie guidée sur la page d’accueil de l’intranet, un affichage propre à votre métier ou des règles que la vue standard ne sait pas exprimer, une web part SharePoint Framework (SPFx) devient l’outil adapté.

Bonne nouvelle : c’est inclus dans votre abonnement Microsoft 365. Pas de serveur à louer, pas de licence en plus. La web part s’exécute dans la page, avec l’identité de la personne connectée.

Ce tutoriel construit un exemple type : un petit suivi des demandes internes (demandes au service administratif, au support, aux services généraux). La web part affiche les 20 dernières demandes non terminées et permet d’en ajouter une. Le code a été compilé et empaqueté avec SPFx 1.23.2 et PnPjs 4.22.0 le 20 octobre 2026, sans erreur ni avertissement du linter.

Ce qu’il vous faut

Élément Version utilisée Source
SharePoint Framework 1.23.2 (dernière version stable sur npm) Compatibilité SPFx
Node.js 22 LTS Compatibilité SPFx
TypeScript 5.8 (fourni par le générateur) Compatibilité SPFx
PnPjs 4.22.0 (@pnp/sp) Documentation PnPjs
Chaîne de build Heft (remplace gulp depuis SPFx 1.22) Chaîne Heft

À jour au 23 octobre 2026. La dernière version stable reste SPFx 1.23.2. La version candidate 1.24.0-rc.0 est désormais publiée sur npm : elle passera React 18.x en standard et prendra en charge Node.js 24 et 26, pour une disponibilité générale visée en octobre 2026 (feuille de route SPFx, Microsoft). Si vous avez des solutions existantes, testez-les sur 1.24 avant de migrer : le passage à React 18 peut changer le rendu. Ce tutoriel reste sur 1.23.2, la version stable.

Côté SharePoint, créez une liste Demandes sur votre site, avec la colonne Titre existante et une colonne de type Choix nommée Statut (valeurs : Nouvelle, En cours, Terminée). Créez la colonne directement sous le nom « Statut », sans accent ni espace : le code utilise le nom interne de la colonne. Pour le vérifier, ouvrez les paramètres de la liste, cliquez sur la colonne et lisez la fin de l’adresse (Field=Statut).

Étape 1 : créer le projet

Depuis SPFx 1.22, les nouveaux projets utilisent Heft à la place de gulp. Les commandes gulp serve et gulp bundle des anciens tutoriels ne s’appliquent donc plus aux projets récents (Microsoft Learn).

npm install -g yo @microsoft/generator-sharepoint@1.23.2
mkdir suivi-demandes && cd suivi-demandes
yo @microsoft/sharepoint
# Type de composant : WebPart · Nom : Demandes · Modèle : No framework
npm install @pnp/sp@4.22.0 --save-exact

Le choix « No framework » garde l’exemple lisible. Le même code PnPjs fonctionne à l’identique dans un composant React.

Étape 2 : le code de la web part

Remplacez le contenu de src/webparts/demandes/DemandesWebPart.ts par le fichier ci-dessous. Trois points comptent :

  • Une seule instance PnPjs, créée dans onInit avec le contexte de la web part. La documentation PnPjs signale comme erreur courante le fait de la recréer dans chaque gestionnaire d’événement (PnPjs).
  • Des imports sélectifs (@pnp/sp/webs, lists, items) : vous n’embarquez que ce que vous utilisez, ce qui limite le poids du bundle.
  • Tout ce qui vient de la liste passe par escape avant d’être injecté dans la page. Un titre saisi par un utilisateur ne doit jamais devenir du HTML exécutable.
import { Version } from '@microsoft/sp-core-library';
import {
  type IPropertyPaneConfiguration,
  PropertyPaneTextField
} from '@microsoft/sp-property-pane';
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
import { escape } from '@microsoft/sp-lodash-subset';
import { spfi, SPFx, type SPFI } from '@pnp/sp';
import '@pnp/sp/webs';
import '@pnp/sp/lists';
import '@pnp/sp/items';

import styles from './DemandesWebPart.module.scss';

export interface IDemandesWebPartProps {
  listTitle: string;
}

interface IDemande {
  Id: number;
  Title: string;
  Statut: string;
  Created: string;
}

export default class DemandesWebPart extends BaseClientSideWebPart<IDemandesWebPartProps> {
  private _sp!: SPFI;

  protected async onInit(): Promise<void> {
    await super.onInit();
    // Une seule instance PnPjs, créée avec le contexte de la web part (jeton et URL du site).
    this._sp = spfi().using(SPFx(this.context));
  }

  public render(): void {
    this.domElement.innerHTML = `
      <section class="${styles.demandes}">
        <h2>Demandes en cours</h2>
        <form class="${styles.form}">
          <input name="titre" required maxlength="255" placeholder="Nouvelle demande" />
          <button type="submit">Ajouter</button>
        </form>
        <ul class="${styles.liste}"><li>Chargement…</li></ul>
      </section>`;

    const form = this.domElement.querySelector('form') as HTMLFormElement;
    form.addEventListener('submit', (event: Event) => {
      event.preventDefault();
      const champ = form.elements.namedItem('titre') as HTMLInputElement;
      this._ajouter(champ.value.trim())
        .then(() => { champ.value = ''; })
        .catch((erreur) => console.error(erreur));
    });

    this._charger().catch((erreur) => console.error(erreur));
  }

  private async _charger(): Promise<void> {
    const liste = this.domElement.querySelector('ul') as HTMLUListElement;
    try {
      const demandes: IDemande[] = await this._sp.web.lists
        .getByTitle(this.properties.listTitle)
        .items.select('Id', 'Title', 'Statut', 'Created')
        .filter("Statut ne 'Terminée'")
        .orderBy('Created', false)
        .top(20)();

      liste.innerHTML = demandes.length === 0
        ? '<li>Aucune demande en cours.</li>'
        : demandes.map((d) => `
            <li>
              <strong>${escape(d.Title)}</strong>
              <span>${escape(d.Statut)} · ${new Date(d.Created).toLocaleDateString('fr-FR')}</span>
            </li>`).join('');
    } catch (erreur) {
      console.error(erreur);
      liste.innerHTML = '<li>Impossible de lire la liste. Vérifiez son nom et vos droits.</li>';
    }
  }

  private async _ajouter(titre: string): Promise<void> {
    if (!titre) {
      return;
    }
    await this._sp.web.lists
      .getByTitle(this.properties.listTitle)
      .items.add({ Title: titre, Statut: 'Nouvelle' });
    await this._charger();
  }

  protected get dataVersion(): Version {
    return Version.parse('1.0');
  }

  protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
    return {
      pages: [
        {
          header: { description: 'Source des données' },
          groups: [
            {
              groupName: 'Liste SharePoint',
              groupFields: [
                PropertyPaneTextField('listTitle', { label: 'Nom de la liste' })
              ]
            }
          ]
        }
      ]
    };
  }
}

Dans DemandesWebPart.manifest.json, mettez la valeur par défaut de la propriété : "properties": { "listTitle": "Demandes" }. Le nom de la liste reste modifiable dans le volet de propriétés, sans redéployer.

Ajoutez enfin les classes form et liste dans DemandesWebPart.module.scss (une mise en forme simple suffit), puis supprimez les références aux images et aux textes de bienvenue du modèle si vous ne les utilisez plus.

Étape 3 : tester sur une vraie page

Lancez le serveur local :

npm run start

Le script exécute heft start, qui sert vos fichiers sur https://localhost:4321 et affiche dans la console une chaîne de paramètres (?debugManifestsFile=…&debug=true&noredir=true) à ajouter à l’adresse d’une page de votre site (Microsoft Learn). Ouvrez une page de test, ajoutez ces paramètres, autorisez les scripts de débogage : la barre d’outils de débogage SPFx apparaît et votre web part est disponible dans la boîte à outils de la page (Microsoft Learn).

Prenez l’habitude dès maintenant : le workbench SharePoint en ligne est déprécié depuis le 13 mai 2026 et sera retiré le 1er décembre 2026 (Microsoft Learn).

Étape 4 : empaqueter et déployer

npm run build

Dans un projet SPFx 1.23, ce script lance les tests et le linter, compile en mode production puis produit le paquet sharepoint/solution/suivi-demandes.sppkg. Un administrateur SharePoint le charge ensuite dans le site Applications (centre d’administration SharePoint, Plus de fonctionnalités > Applications > Ouvrir, puis Charger), et peut choisir Activer cette application et ajoutez-la à tous les sites (Microsoft Learn). Microsoft recommande de tester une solution avant de la déployer à grande échelle : commencez par un seul site.

Les pièges les plus fréquents

Symptôme Cause probable Correction
« Impossible de lire la liste » Nom de liste erroné, ou l’utilisateur n’a pas accès à la liste Vérifier le nom dans le volet de propriétés et les droits du site
Erreur sur le filtre Statut Le nom interne de la colonne n’est pas « Statut » Lire le nom interne dans l’adresse des paramètres de la colonne et l’utiliser dans select et filter
Erreur de seuil sur une grosse liste Plus de 5 000 éléments et filtre sur une colonne non indexée Indexer la colonne filtrée ; le seuil de 5 000 n’est pas modifiable dans SharePoint Online (Microsoft Learn, Support Microsoft)
gulp: command not found Tutoriel écrit pour l’ancienne chaîne Utiliser npm run start et npm run build (Heft)
Comportements étranges avec React Version de React différente de celle attendue SPFx 1.23 attend React 17.0.1 exactement, à installer avec --save-exact (Microsoft Learn)

PnPjs ou SPHttpClient ?

SPFx fournit SPHttpClient, qui appelle l’API REST SharePoint avec les cookies d’authentification de l’utilisateur, sans dépendance supplémentaire. Microsoft le présente comme suffisant pour des requêtes simples, et conseille d’envisager PnPjs dès que les écritures et les requêtes complexes arrivent, parce que les requêtes REST écrites à la main sont sources d’erreurs (Microsoft Learn).

La même page rappelle la contrepartie : PnPjs est un projet communautaire, sans SLA ni support Microsoft, et c’est une dépendance à mettre à jour. Notre règle : PnPjs dès qu’une web part écrit dans une liste, avec une version figée (--save-exact) et une mise à jour planifiée à chaque montée de version SPFx.

Et ensuite ?

Cette web part est la brique de base d’une application métier sur SharePoint : la liste porte les données et les droits, la web part porte l’ergonomie, et Power Automate peut prendre le relais pour les notifications et les validations. Posée sur la page d’accueil, elle devient un élément de votre intranet SharePoint.

C’est le même principe que nous avons utilisé pour une réalisation réelle dans un cabinet de conseil : une web part SPFx où l’utilisateur sélectionne des fiches dans SharePoint et obtient un document Word unique et mis en page (assemblage de documents Word). Pour situer ce type de projet parmi vos priorités, lisez aussi les 12 usages concrets de SharePoint pour une PME.

Vous avez une liste Excel partagée qui mériterait de devenir une vraie application ? Réservez un appel de 30 minutes : nous regardons ensemble votre fichier et ce qu’une liste SharePoint et une web part changeraient pour vos équipes.

FAQ

Questions fréquentes

Faut-il PnPjs pour lire une liste SharePoint depuis SPFx ?

Non. SPFx fournit SPHttpClient, qui appelle l’API REST SharePoint sans dépendance supplémentaire. Microsoft recommande toutefois d’envisager PnPjs dès que les requêtes se compliquent (écritures, lots), car l’écriture de requêtes REST brutes est source d’erreurs. PnPjs est open source : il n’y a pas de SLA ni de support Microsoft sur la bibliothèque.

Quelle version de Node.js faut-il pour SPFx 1.23 ?

Node.js 22 LTS, selon la table de compatibilité de Microsoft. La même table indique TypeScript 5.8 au maximum et React 17.0.1. La prochaine version, SPFx 1.24 — qui passera React 18.x en standard et prendra en charge Node.js 24 et 26 —, est en version candidate (1.24.0-rc.0) sur npm au 23 octobre 2026, Microsoft visant une disponibilité générale en octobre 2026. Tant qu’elle n’est pas stable, restez sur 1.23.

Ma liste dépasse 5 000 éléments : la web part va-t-elle planter ?

Elle peut échouer si la requête filtre sur une colonne non indexée. Le seuil d’affichage de liste de SharePoint Online est de 5 000 éléments et ne peut pas être modifié. Indexez les colonnes utilisées dans vos filtres et limitez le nombre d’éléments renvoyés.

Comment tester la web part maintenant que le workbench disparaît ?

Microsoft a déprécié le workbench SharePoint en ligne le 13 mai 2026 et le retire le 1er décembre 2026. Lancez heft start, puis ouvrez une vraie page de votre site avec les paramètres de débogage affichés dans la console : la barre d’outils de débogage SPFx apparaît sur la page.

Appel de 30 min offert

Trente minutes pour savoir ce que l’IA peut faire chez vous.

Un appel avec moi, pas avec un commercial. Vous repartez avec deux ou trois idées concrètes et chiffrées, que vous travailliez avec Ktifa ensuite ou non.

  • Réponse sous un jour ouvré
  • Aucun accès à votre tenant demandé pour l’appel
  • Pas de relance commerciale si ce n’est pas pour vous

Vous savez déjà que vous voulez en parler ?

Choisissez directement un créneau dans mon agenda.

Parlons de votre projet, 30 minutes offertes

1/4

Votre e-mail

En cliquant sur « Continuer », votre e-mail est enregistré pour que je puisse vous recontacter si vous n’allez pas au bout (intérêt légitime). Jamais revendu ; opposition possible à tout moment (en savoir plus).

Avant de partir

La checklist en 40 points avant de déployer Copilot.

Partages SharePoint, identités, licences, gouvernance, adoption. Les 16 premiers points sont en accès libre.