Local SPFx Workbench against real SharePoint API

Local SPFx Workbench against real SharePoint API

When dealing with SharePoint Framework (SPFx), a developer can choose local or remote runtime debug strategy.

By default by running `gulp serve`, the local workbench is started. Local workbench opens on `https://localhost:4321/temp/workbench.html`, it is a page which mimics SharePoint modern UI, yet it's just a locally served page, it has no connection to SharePoint APIs.

Local mode provided the capability of mocking UI and styling based on some artificial data prepared beforehand or generated with specific libs. Local workbench uses hot module reload on changes, once started you just change the code and check for updates in browser's window.

Sometimes, real API's response data is required and mocking is too time-consuming and unproductive. SPFx has a solution for this. There is online version of the workbench, which can be found via `[SHAREPOINT_WEB_URL]/_layouts/15/workbench.aspx`. When `gulp serve --nobrowser` (`--nobrowser` key is handy when you get tired of auto-opening local workbench page) has been started web parts can be placed to online workbench while scripts can be hosted from a local machine.

Such mode allows acting with real data and REST API (or other APIs).

At this moment you might ask "Ok, online workbench saves the day, what the deal? Why do I need local workbench ever talking to the APIs?". Actually, it's a good question, but believe me, there are use cases (for example using web parts in production and developing and delivering new versions within one single tenant). Would be cool hearing about your use cases in the comment section below!

Anyway, it's super simple to configure "local" to work with "remote", let's take a look how.

Configuring SPFx solution to work with the proxy

As a prerequisite SPFx project should be created.

1. Install SharePoint REST Proxy in SPFx solution's project.

npm install sp-rest-proxy --save-dev  

sp-rest-proxy is a dev dependency, it provides authorized anonymous proxy gateway to SharePoint APIs with CORS enabled. So any page on a developer's machine can request SharePoint API seamlessly.

2. Create `proxy.js` file in a root or wherever in the project with the following content:

const CertStore = require('@microsoft/gulp-core-build-serve/lib/CertificateStore');
const RestProxy = require('sp-rest-proxy');

const CertificateStore = CertStore.CertificateStore || CertStore.default;

const settings = {
  configPath: './config/private.json',
  port: 4323,
  protocol: 'https',
  ssl: {
    cert: CertificateStore.instance.certificateData,
    key: CertificateStore.instance.keyData
  }
};

const restProxy = new RestProxy(settings);
restProxy.serve();

Download script ]

To make requests from the local workbench to proxy happen, the proxy's local server should be running on https/SSL. Here is the script we're using some sort of trick and reusing SPFx certificate, so proxy's SSL trust is tied up with workbench's cert. (You can trust/untrust SPFx cert with `gulp trust-dev-cert` and `gulp untrust-dev-cert` accordingly).

3. Create npm task to start proxy, e.g. `"proxy": "node ./proxy"`.

4. Run and configure proxy's connection to the environment by `node ./proxy` or currently created npm task `npm run proxy`.

This is required once you need to "bind" the proxy with remote SharePoint server and provide credentials. Follow the wizard prompts to finish this step. Check out project's page for more details.

5. Configure a task to start proxy and `gulp serve` at the same time, e.g. using concurrently or npm-run-all.

Setup with `concurrently`:

5.1 Install dependency:

npm install concurrently --save-dev  

5.2 Add npm task to package.json:

"scripts": {
  ...
  "serve": "concurrently --kill-others \"npm run proxy\" \"gulp serve\""
  ...
}

Now you can start both proxy and SPFx local server with one command:

npm run serve  

We are done with configuration. Now it's time to cover some coding aspects.

Detecting local mode

With proxy at our disposal, SPFx consumes real API in local mode. All we need to do is implement variability of switching between endpoints.

Let's assume your SharePoint Web is located at `https://contoso.sharepoint.com/sites/site/my_web`.

SPFx web part is generally agnostic to the future location of the web. Web URL can be get known in a runtime using `this.context.pageContext.web`'s object properties: `absoluteUrl` or `serverRelativeUrl`. REST requests are usually built using this variables.

The local mode, in the opposite, knows nothing about target environment. You're in charge of pointing HttpClient to request correct URLs. One of them is kind of static, it's a proxy's host URL, `https://localhost:4323`, web relative URL should be somewhere in the settings.

In the local mode, a web part should construct the following sort of endpoint for requests `https://localhost:4323/sites/site/my_web/_api/....` It should always deal with absolute URLs in this kind of setup.

Once this is clear, the question is how to detect local mode gracefully. Luckily SPFx has helpers for this situation (and there is no need to use `window.location.href.indexOf('https://localhost:') === 0`):

import { Environment, EnvironmentType } from '@microsoft/sp-core-library';

if (Environment.type === EnvironmentType.Local) {  
  // Local mode
} else {
  // Online mode
}

We can rely code logic on this condition and provide initial endpoint rather robustly.

Bonus section - configuring PnPjs

Oh, you might know, I'm a huge fan of PnPjs and prefer this library over building requests manually.

PnPjs works nicely with SPFx and I glad to inform you it works great with SPFx plus SharePoint REST Proxy. Once configured properly.

import { Web, sp } from '@pnp/sp';  
import { proxyUrl, webRelativeUrl } from './../settings';  
// settings.ts should be created with corresponding exports

...
let web: Web;  
if (Environment.type === EnvironmentType.Local) {
  // To let PnPjs know which base URL to use:
  sp.setup({
    sp: {
      baseUrl: `${proxyUrl}${webRelativeUrl}`
    }
  });
  // or a Web object should be created with explicit web URL
  web = new Web(`${proxyUrl}${webRelativeUrl}`);
} else {
  // On SharePoint page PnPjs should be configured with
  sp.setup({ spfxContext: this.context });
  // or a Web object should be created with explicit web URL
  web = new Web(this.context.pageContext.web.absoluteUrl);
}
// Then universal pnp code and dealing with SPFx specifics
/*
web.lists.get()  
  .then(...).catch(...);
*/
...

Example

I've published a simple example with the setup described above. The example can be found here.

Want know more? Ask me in Gitter.

Satish Kumar

SharePoint Online(Office 365) | SPFX | Power Apps | Power Automate | MS Power Platform | K2 Business Process Automation (K2 Five)

3 年

In react spfx solution, i am getting below error Cannot find module '@microsoft/gulp-core-build-serve/lib/CertificateStore' Also i have downloaded the "spfx-proxy-example" from github and ran npm install, its giving me "unable to resolve dependency tree". Please help

Santosh Timilsina

Data Analyst | Power BI | Power Apps Developer

4 年

Great!

回复
David Vargas

Senior Software Engineer @ Granite Solutions | Typescript | React | NodeJS

5 年

Awesome! Just what I needed.?

Kristoffer Kirkerud

Software Engineer at Polestar

6 年

Great guide!

Sara Shahinzadeh

Full-stack Developer at Fujitsu

7 年

I have some problem with CSS in Workbench and real environment. When I use ComboBox as a comonent I get a class with CSS-64 in real environment but CSS-77 in Workbench. How can I solve it to get same result as I get in Workbench. Maybe you need to know that I try the app on classic version due to modern version is not available on MS Project pages. Is there any solution you know or someone else knows?

回复

要查看或添加评论,请登录

Andrew Koltyakov的更多文章

社区洞察

其他会员也浏览了