Understanding About Pnpjs

A JavaScript libraries

In this article, we will discuss about Pnpjs. Which is a collection of open-source JavaScript libraries designed for SharePoint developments. It allows users to consume SharePoint REST API, graph API, and Office 365 REST APIs in a type-safe way.

It can be used with SharePoint Framework, Nodejs, and other JavaScript frameworks. The purpose of the Pnpjs is to simplify interaction with SharePoint REST API. It is commonly used in SPFx (SharePoint Framework) web parts, extensions, and standalone JavaScript applications for interaction.

Why do we use Pnpjs?

Pnpjs simplifies REST API calls, and it makes it easy to use complex queries and abstract complex REST API queries. It provides a consistent approach to interaction with SharePoint complex REST API queries.

As we have discussed, it is used for SharePoint development so there Is regular updates and support from SharePoint developer communities so it is community-driven.

Pnpjs has its core libraries which are described below.

  • @pnp/sp: Handles core SharePoint operations like CRUD (Create, Read, Update, Delete).
  • @pnp/graph: Interfaces with Microsoft Graph. which provides access to data stored across Microsoft 365 services. Custom applications can use the Microsoft Graph API to connect to data and use it in custom applications to enhance organizational productivity.
  • @pnp/logging: Provides logging functionalities. The purpose of logging is to create an ongoing record of application events. Log files can be used to review any event within a system.

Benefits of PnPjs

  • Productivity: Pnpjs Reduces the amount of code needed for common operations. Like for crud operations it simplifies REST API for interaction.
  • Maintainability: Pnpjs also provides a readable and clean codebase. Which makes it more understandable for those developers who are not familiar with this.
  • Performance: Pnpjs provides optimized queries which reduces network load.

Now, we will look into an example where we are fetching SharePoint list data using the fluent ui Datalist component and Pnpjs for fetching list data.

First, we need to install the required libraries for Pnpjs.

Installation of libraries

npm i @pnp/[email protected]
npm i @pnp/[email protected]
npm i @pnp/[email protected]

Note. Remember that we have defined specific versions of libraries for use. You can use them accordingly with version compatibility. Check here for Version Compatibility

So before we start with the example, we need to set up the Pnpjs configuration so put the code given below.

Src/services/PnpjsConfig.ts

/* eslint-disable no-var */
import { WebPartContext } from "@microsoft/sp-webpart-base";
import { LogLevel, PnPLogging } from "@pnp/logging";
import { spfi, SPFI, SPFx } from "@pnp/sp";
import { graphfi, GraphFI, SPFx as graphSPFx } from "@pnp/graph";
import { MSGraphClientV3 } from '@microsoft/sp-http';
import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/items";
import "@pnp/sp/batching";
import "@pnp/sp/comments";
import "@pnp/sp/site-users/web";
import "@pnp/sp/fields";
import "@pnp/sp/search";
var _sp: SPFI;
var _graph: GraphFI;
var _graphClient: MSGraphClientV3;
export const getSP = (context?: WebPartContext): SPFI => {
    if (context) {
        _sp = spfi().using(SPFx(context)).using(PnPLogging(LogLevel.Error));
    }
    return _sp;
}
export const getGraph = (context?: WebPartContext): GraphFI => {
    if (_graph === undefined && context) {
        _graph = graphfi().using(graphSPFx(context)).using(PnPLogging(LogLevel.Error));
    }
    return _graph;
}
export const getGraphClient = async (context?: WebPartContext): Promise<MSGraphClientV3> => {
    if (context) {
        const client: MSGraphClientV3 = await context.msGraphClientFactory.getClient('3');
        _graphClient = client;
    }
    return _graphClient;
}

Add the given file also for SharePoint services.

Src/services/SharePointServices.ts

/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unused-vars */
import { SPFI } from "@pnp/sp";
import { MSGraphClientV3 } from "@microsoft/sp-http";
import { getGraphClient, getSP } from "./PnpjsConfig";
import { Logger } from "@pnp/logging";
const EmployeeInformation = "Employee Information";
export class SharepointServices {
    private _sp: SPFI;
    private _graphClient: MSGraphClientV3;
    constructor() {
        this._sp = getSP();
        getGraphClient()
            .then((value: any) => {
                this._graphClient = value;
                console.log(this._graphClient);
            })
            .catch((error) => console.error(error));
    }
    public async getListdata(): Promise<any> {
        try {
            return await this._sp.web.lists.getByTitle(EmployeeInformation).items.getPaged();
        } catch (error) {
            Logger.error(error);
            return undefined;
        }
    }
}

Note. Remember that in this file we have given hard-coded value or name of SharePoint list you can change according to your list name.

Now, we have our set up for interaction with SharePoint data.

Go to your Components folder in your web, and go to yourwebpartName.tsx file and add the given code below.

src/web parts/YourWebpartname/Components/yourwebpartName.tsx

/* eslint-disable @typescript-eslint/no-explicit-any */
import * as React from "react";
import { SharepointServices } from "../../../services/SharepointServices";
import type { IDatalistProps } from "./IDatalistProps";
import {
  DetailsList,
  DetailsListLayoutMode,
  IColumn,
  SelectionMode,
} from "@fluentui/react";
export interface IDatalistState {
  items: any[];
  columns: IColumn[];
  // selectedDepartment: string | undefined;
}
export default class Datalist extends React.Component<IDatalistProps, IDatalistState> {
  constructor(props: IDatalistProps) {
    super(props);
    this.state = {
      items: [],
      columns: [
        {
          key: "RefinableString00",
          name: "ID",
          fieldName: "ID",
          minWidth: 80,
          maxWidth: 100,
          isResizable: true,
        },
        {
          key: "RefinableString00",
          name: "name",
          fieldName: "Name",
          minWidth: 80,
          maxWidth: 100,
          isResizable: true,
        },
        {
          key: "RefinableString00",
          name: "Address",
          fieldName: "Address",
          minWidth: 80,
          maxWidth: 100,
          isResizable: true,
        },
        {
          key: "RefinableString00",
          name: "Phone Number",
          fieldName: "Phone Number",
          minWidth: 80,
          maxWidth: 100,
          isResizable: true,
        },
        {
          key: "RefinableString00",
          name: "Age",
          fieldName: "Age",
          minWidth: 80,
          maxWidth: 100,
          isResizable: true,
        },
        {
          key: "RefinableString00",
          name: "Gender",
          fieldName: "Gender",
          minWidth: 80,
          maxWidth: 100,
          isResizable: true,
        },
        {
          key: "RefinableString00",
          name: "Citizens",
          fieldName: "Citizens",
          minWidth: 80,
          maxWidth: 100,
          isResizable: true,
        },
        {
          key: "RefinableString00",
          name: "DOB",
          fieldName: "DOB",
          minWidth: 80,
          maxWidth: 100,
          isResizable: true,
        },
        {
          key: "RefinableString00",
          name: "Dayship",
          fieldName: "Dayship",
          minWidth: 80,
          maxWidth: 100,
          isResizable: true,
        },
        {
          key: "RefinableString00",
          name: "Nightship",
          fieldName: "Nightship",
          minWidth: 80,
          maxWidth: 100,
          isResizable: true,
        },
      ],
    };
  }
  async componentDidMount(): Promise<void> {
    const spService = new SharepointServices();
    const items = await spService.getListdata();
    this.setState({
      items: items.results,
    });
  }
  public render(): React.ReactElement<IDatalistProps> {
    const { items, columns } = this.state;
    return (
      <DetailsList
        items={items}
        columns={columns}
        setKey="none"
        layoutMode={DetailsListLayoutMode.justified}
        selectionPreservedOnEmptyClick={true}
        selectionMode={SelectionMode.none}
        isHeaderVisible={true}
      />
    );
  }
}

Note. Remember that we are using Fluent UI DataList Component for UI . and in that DataList, you can customize columns and manage data according to your need.

Now go to your webpartNameWebpart.ts file: src/webpartNameWebPart.ts and add the code given below

Import these services which we have set up earlier.

import { getGraphClient, getSP } from '../../services/PnpjsConfig';

Then add the Code given below in the Class components of your web-part.ts file.

protected async onInit(): Promise<void> {
    getSP(this.context);
    await getGraphClient(this.context);
    return this._getEnvironmentMessage().then(message => {
        this._environmentMessage = message;
    });
}

Conclusion

In this article we have seen that Using PnPjs for SharePoint development significantly reduces the complexity of API calls, and improves code readability, PnPjs is generally recommended for its simplicity and developer productivity benefits. we have also seen an example for a better understanding and understanding that pnpjs is a really handy library that is easy to use.