Pnpjs: Nodejs app - node 10.15 complaining about JSON and global$1.fetch

Created on 22 Jan 2019  路  6Comments  路  Source: pnp/pnpjs

Category

  • [ ] Enhancement
  • [ ] Bug
  • [x ] Question
  • [ ] Documentation gap/issue

Version

Please specify what version of the library you are using: [ 1.2.8 ]

Please specify what version(s) of SharePoint you are targeting: [ 2016 ]

Following the setup and code in https://github.com/SharePoint-NodeJS/pnp-auth I have a working version on a windows server using nodejs v 8.11 with @pnp/js v1.2.7
This is my code
`import { bootstrap } from 'pnp-auth';
import { sp, Web } from '@pnp/sp';
import { AuthConfig } from 'node-sp-auth-config';

const authConfig = new AuthConfig({
configPath: './src/config/private.config.json',
encryptPassword: true,
saveConfigOnDisk: true
});
bootstrap(sp, authConfig);
export const init = () => {
let web = new Web("https://xxxxxxxxxx")
web.get()
.then(data => {
console.log(Your web title: ${data.Title});
})
.catch(function(error) {
console.log(error);
});
}`

Trying this same code on another server with node 10.15 I run into problems
I installed all packages anew (this is not a copy/paste of the working project)

1st error :
message:"Unexpected token < in JSON at position 1"
stack:"SyntaxError: Unexpected token < in JSON at position 1\n at JSON.parse ()\n at c:\Services\nodetest\node_modules\@pnp\odata\dist\odata.es5.umd.js:129:93\n at process._tickCallback (internal/process/next_tick.js:68:7)"

adding the following snippet (which I thought N/A) I get past that error but I get another
sp.setup({ sp: { headers: { "Accept": "application/json; odata=verbose" } } })
2nd error :
TypeError: global$1.fetch is not a function
sp.ts:30
message:"global$1.fetch is not a function"
stack:"TypeError: global$1.fetch is not a function\n at FetchClient.fetch (c:\Services\nodetest\node_modules\@pnp\common\dist\common.es5.umd.js:310:29)\n .....

Clearly I'm doing something wrong - question is what

All help greatly appreciated

code details needed question

Most helpful comment

Hi @dannyfoncke,

Combining pnp-auth's bootstrap method and sp.setup might be not a good idea. It's better using [object].configure for custom headers or fetchClientFactory:

import { bootstrap } from 'pnp-auth';
import { sp, Web } from '@pnp/sp';
import { AuthConfig } from 'node-sp-auth-config';

const authConfig = new AuthConfig({
  configPath: './config/private.json',
  encryptPassword: true,
  saveConfigOnDisk: true
});

bootstrap(sp, authConfig);

export const init = async () => {
  const { siteUrl } = await authConfig.getContext();
  const web = new Web(siteUrl).configure({
    headers: {
      'Accept': 'application/json; odata=verbose'
    }
  });
  const { Title } = await web.select('Title').get();
  console.log(`Your web title: ${Title}`);
}

or

import NodeFetchClient from 'pnp-auth/lib/NodeFetchClient';
import { sp, Web } from '@pnp/sp';
import { AuthConfig } from 'node-sp-auth-config';

const authConfig = new AuthConfig({
  configPath: './config/private.json',
  encryptPassword: true,
  saveConfigOnDisk: true
});

const configure = async (): Promise<{ siteUrl: string; }> => {
  const { siteUrl, authOptions } = await authConfig.getContext();
  const fetchClient = new NodeFetchClient(authOptions, siteUrl);
  sp.setup({
    sp: {
      headers: {
        'Accept': 'application/json; odata=verbose'
      },
      baseUrl: siteUrl,
      fetchClientFactory: () => fetchClient
    }
  });
  return { siteUrl };
}

export const init = async () => {
  const { siteUrl } = await configure();
  const web = new Web(siteUrl);
  const { Title } = await web.select('Title').get();
  console.log(`Your web title: ${Title}`);
}

All 6 comments

Hi @dannyfoncke,

Combining pnp-auth's bootstrap method and sp.setup might be not a good idea. It's better using [object].configure for custom headers or fetchClientFactory:

import { bootstrap } from 'pnp-auth';
import { sp, Web } from '@pnp/sp';
import { AuthConfig } from 'node-sp-auth-config';

const authConfig = new AuthConfig({
  configPath: './config/private.json',
  encryptPassword: true,
  saveConfigOnDisk: true
});

bootstrap(sp, authConfig);

export const init = async () => {
  const { siteUrl } = await authConfig.getContext();
  const web = new Web(siteUrl).configure({
    headers: {
      'Accept': 'application/json; odata=verbose'
    }
  });
  const { Title } = await web.select('Title').get();
  console.log(`Your web title: ${Title}`);
}

or

import NodeFetchClient from 'pnp-auth/lib/NodeFetchClient';
import { sp, Web } from '@pnp/sp';
import { AuthConfig } from 'node-sp-auth-config';

const authConfig = new AuthConfig({
  configPath: './config/private.json',
  encryptPassword: true,
  saveConfigOnDisk: true
});

const configure = async (): Promise<{ siteUrl: string; }> => {
  const { siteUrl, authOptions } = await authConfig.getContext();
  const fetchClient = new NodeFetchClient(authOptions, siteUrl);
  sp.setup({
    sp: {
      headers: {
        'Accept': 'application/json; odata=verbose'
      },
      baseUrl: siteUrl,
      fetchClientFactory: () => fetchClient
    }
  });
  return { siteUrl };
}

export const init = async () => {
  const { siteUrl } = await configure();
  const web = new Web(siteUrl);
  const { Title } = await web.select('Title').get();
  console.log(`Your web title: ${Title}`);
}

Thank you Andrew for the quick response.

Possibly my message wasn't well worded (English is not my native language)

I try to clarify

  • The code (see at the top) works (using Node 8.11, pnp packages version 1.2.7)
  • When using the exact same code with node 10.15, pnp package versions 1.2.8 it doesn't work
  • I added the sp.setup code because I knew the JSON error can be fixed that way (however I thought this was when connecting to SP2013) - but it shouldn't be needed ?! (and I'm connecting to SP2016)
  • When I add the sp.setup code I get the second error - which for me looks like the code thinks it is running in a browser ?

So bottom line of my thinking is that I don't need to change the code, but that there is somewhere a misconfiguration and/or misuse of pnp packages.....

I can't give any more details because this is really simple code which is (except for the use of node-sp-auth-config) identical to the code found in https://github.com/SharePoint-NodeJS/pnp-auth

I will check out your code though - keep you posted if that works

thanks again for your interest and replies

As promised I tried the code provided by Andrew : solution 1 and solution 2 give the same result

on execution of line : const { Title } = await web.select('Title').get();
this is the error:

(node:9244) UnhandledPromiseRejectionWarning: SyntaxError: Unexpected token < in JSON at position 1
warning.js:18
at JSON.parse ()
at c:\Services\nodetest\node_modules\@pnp\odata\dist\odata.es5.umd.js:129:93
at process._tickCallback (internal/process/next_tick.js:68:7)

That鈥檚 strange. Both samples work for me in Node 8 and 10. And we use similar setup on a pretty large number of different environments in production.
Are you sure you didn鈥檛 apply any changes while testing? Should be something else which is missing.
Also, I consider this issue to be more relevant to pnp-auth library rather that PnPjs. How about moving the discussion to its repository keeping two issues linked?

I have learned that the server has been installed with IIS and IISNode

In my code there is nothing linking the project to IISNode, nor is there any config in IISNode linking it to my project. Still, might there be a influence ?

As far as moving this discussion, I have no problem with that. I have no idea how to do that however.

Linked the issues. Closing this one.

Was this page helpful?
0 / 5 - 0 ratings