user1063287
user1063287

Reputation: 10879

How to import a third party JavaScript library (UIkit) into a SharePoint SPFx web part?

Short Version

I want to know the correct way to import UIkit into a SharePoint SPFx web part.

I can successfully import jQuery like this:

In config.json, I specify the link to the library:

"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"

I import the relevant ‘types’:

npm install --save-dev @types/jquery

In my_web_part.ts, I import the library and then use it:

import * as $ from 'jquery';

// .....

<div id="jquery-test">Hello, jQuery!</div>

$('#jquery-test').text('jQuery is working!');

But when I try and import UIkit in the same way, ie:

In config.json:

"uikit": "https://cdnjs.cloudflare.com/ajax/libs/uikit/3.21.5/js/uikit.min.js",
"uikit-icons": "https://cdnjs.cloudflare.com/ajax/libs/uikit/3.21.5/js/uikit-icons.min.js"

Import the relevant ‘types’:

npm install --save-dev @types/uikit

In my_web_part.ts:


import * as UIkit from 'uikit';

// ... 
<a href="#" uk-icon="heart"></a>

<div uk-slider="autoplay: true" id="my_slider">

<div class="uk-slider-container">

<!-- Slider items here -->

</div>

</div>

the result is that:

If I try and reference UIkit explicity like this, I can see that UIkit is not available:

UIkit.slider('#my_slider')

It is like UIKit is not even imported into the file.

Long Version

I have followed the instructions here:

https://learn.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/basics/add-an-external-library#load-a-script-from-a-cdn

My config.json file looks like this:

{
  "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
  "version": "2.0",
  "bundles": {
    "my-custom-html-interface-web-part-web-part": {
      "components": [
        {
          "entrypoint": "./lib/webparts/myCustomHtmlInterfaceWebPart/MyCustomHtmlInterfaceWebPartWebPart.js",
          "manifest": "./src/webparts/myCustomHtmlInterfaceWebPart/MyCustomHtmlInterfaceWebPartWebPart.manifest.json"
        }
      ]
    }
  },
"externals": {
    "jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js",
    "uikit": "https://cdnjs.cloudflare.com/ajax/libs/uikit/3.21.5/js/uikit.min.js",
    "uikit-icons": "https://cdnjs.cloudflare.com/ajax/libs/uikit/3.21.5/js/uikit-icons.min.js"
  },
  "localizedResources": {
    "MyCustomHtmlInterfaceWebPartWebPartStrings": "lib/webparts/myCustomHtmlInterfaceWebPart/loc/{locale}.js"
  }
}

I have installed the required 'types':

npm install --save-dev @types/jquery
npm install --save-dev @types/uikit

This is one of the many versions of code I have tried in my 'webpart.ts' file:


/* eslint-disable */

import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
import * as $ from 'jquery';
import * as UIkit from 'uikit';

export default class MyCustomHtmlInterfaceWebPart extends BaseClientSideWebPart<{}> {
  public render(): void {
    this.domElement.innerHTML = `
      <div id="jquery-test">Hello, jQuery!</div>
      <a href="#" uk-icon="heart"></a>
      <div uk-slider="autoplay: true" id="my_slider">
        <div class="uk-slider-container">
          <!-- Slider items here -->
        </div>
      </div>
    `;

    // jQuery usage
    $('#jquery-test').text('jQuery is working!');


    if (UIkit) {
      // UIkit usage
      (UIkit as any).slider('#my_slider', {})
      console.log("THIS IS GOOD");
    }
    else {
      console.log("THIS IS BAD"); // <-- this is logged, because it can't find UIkit  
    }
  }
}

I am new to SharePoint SPFx, TypeScript and ESLint so I am not clear what and where the actual problem is.

I created the project like this:

yo @microsoft/sharepoint   

And answered the prompts like this:

Solution Name: MyWebpartName 
Client-side component: WebPart 
Web part name: MyWebpartName 
Framework: No framework 

My package.json looks like this:

{
  "name": "my-custom-html-interface-web-part",
  "version": "0.0.1",
  "private": true,
  "engines": {
    "node": ">=18.17.1 <19.0.0"
  },
  "main": "lib/index.js",
  "scripts": {
    "build": "gulp bundle",
    "clean": "gulp clean",
    "test": "gulp test"
  },
  "dependencies": {
    "@microsoft/sp-component-base": "1.19.0",
    "@microsoft/sp-core-library": "1.19.0",
    "@microsoft/sp-lodash-subset": "1.19.0",
    "@microsoft/sp-office-ui-fabric-core": "1.19.0",
    "@microsoft/sp-property-pane": "1.19.0",
    "@microsoft/sp-webpart-base": "1.19.0",
    "tslib": "2.3.1"
  },
  "devDependencies": {
    "@fluentui/react": "^8.106.4",
    "@microsoft/eslint-config-spfx": "1.20.1",
    "@microsoft/eslint-plugin-spfx": "1.20.1",
    "@microsoft/rush-stack-compiler-4.7": "0.1.0",
    "@microsoft/sp-build-web": "1.20.1",
    "@microsoft/sp-module-interfaces": "1.20.1",
    "@rushstack/eslint-config": "2.5.1",
    "@types/jquery": "^3.5.30",
    "@types/uikit": "^3.14.5",
    "@types/webpack-env": "~1.15.2",
    "ajv": "^6.12.5",
    "eslint": "8.7.0",
    "gulp": "4.0.2",
    "typescript": "4.7.4"
  }
}

I use nvm with Node version 18.17.1.

I have checked the SPFx/Node compatability chart here and all looks OK:

https://learn.microsoft.com/en-us/sharepoint/dev/spfx/compatibility

I use these commands to build and test in workbench:

gulp clean
gulp bundle --ship
gulp package-solution --ship
gulp serve --nobrowser

And then I go to this URL to access the workbench:

https://<organisation-tenant>.sharepoint.com/_layouts/15/workbench.aspx

where the tenant uses SharePoint Online.

(The workbench behaviour seems really slow, buggy and inconsistent. I am not sure how often the workbench is being refreshed and there are always lots of errors in the chrome dev tools console, even before I add my webpart there).

Other References:

Add an external library to your SharePoint client-side web part
https://learn.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/basics/add-an-external-library

Use existing JavaScript libraries in SharePoint Framework client-side web parts
https://learn.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/guidance/use-existing-javascript-libraries

Upvotes: 0

Views: 101

Answers (1)

user1063287
user1063287

Reputation: 10879

I am just posting this answer as I seem to have got it working.

And I don't want to waste anyone's time if they were going to post a similar answer.

As I mentioned in the OP, I am very new to all these things:

  • SharePoint SPFx
  • TypeScript
  • ESLint

So, as a disclaimer, the following information may not be best practice, or accurate.

I just don't have the knowledge to know if it is or not.

The result of all the information below is that:

  • jQuery works
  • Uikit functionality works
  • Uikit icons work

in both the hosted workbench and production environment.

Learnings

  • UIkit and UIkit icons could NOT be imported into the webpart file if I referenced them in the externals object in config.json

  • I think this is because the UIkit library is an ES module, and not a UMD module

  • I therefore needed to npm install [email protected] (the version of UIkit I wanted to use) so that the SPFx build process would bundle UIkit into the format that it requires it (which I think is UMD)

  • This means that I have to take the 'bundling' approach, as opposed to the 'linking to a CDN' approach, which will increase file download size if I were to use UIkit in more than one webpart

  • I have to run a gulp clean, gulp build and gulp package-solution after each code change and open the hosted workbench in a new tab at https://<tenant-name>.sharepoint.com/_layouts/15/workbench.aspx because I found the workbench just doesn't reload the new code otherwise, or doesn't load the workbench UI properly (apparently there used to be a 'local' workbench that looked and performed better, but that does not exist anymore)

Setup

01) Contents of /config/config.json (i added the jQuery externals property):

{
  "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
  "version": "2.0",
  "bundles": {
    "custom-home-page-web-part": {
      "components": [
        {
          "entrypoint": "./lib/webparts/customHomePage/CustomHomePageWebPart.js",
          "manifest": "./src/webparts/customHomePage/CustomHomePageWebPart.manifest.json"
        }
      ]
    }
  },
"externals": {
  "jquery": {
    "path": "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js",
    "globalName": "jQuery"
  },
},
  "localizedResources": {
    "CustomHomePageWebPartStrings": "lib/webparts/customHomePage/loc/{locale}.js"
  }
}

02) I installed the jQuery 'types' with:

npm install --save-dev @types/jquery

03) I did not install the uikit types, because that package is over 6 months old, so I though the type information may not be in sync with the latest UIkit version

04) Contents of tsconfig.json (i added reference to new declaration files):

{
  "extends": "./node_modules/@microsoft/rush-stack-compiler-4.7/includes/tsconfig-web.json",
  "compilerOptions": {
    "target": "es5",
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "jsx": "react",
    "declaration": true,
    "sourceMap": true,
    "experimentalDecorators": true,
    "skipLibCheck": true,
    "outDir": "lib",
    "inlineSources": false,
    "noImplicitAny": true,

    "typeRoots": [
      "./node_modules/@types",
      "./node_modules/@microsoft"
    ],
    "types": [
      "webpack-env"
    ],
    "lib": [
      "es5",
      "dom",
      "es2015.collection",
      "es2015.promise"
    ]
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.d.ts"  // <---- I added this, it didn't work if i created a 'my_custom_types' folder in root package directory and referenced it in the 'typeRoots' property  
  ]
}

05) I created two 'declaration files' in /src:

  • uikit.d.ts with this content:
declare module 'uikit';
  • uikit-icons.d.ts with this content:
declare module 'uikit/dist/js/uikit-icons';

06) Contents of my webpart file (note the syntax used in the import statements etc):


/* eslint-disable */

import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
import { SPComponentLoader } from '@microsoft/sp-loader';

import * as $ from 'jquery';
import UIkit from 'uikit';
import Icons from 'uikit/dist/js/uikit-icons';

UIkit.use(Icons); 

export default class MyCustomHtmlInterfaceWebPart extends BaseClientSideWebPart<{}> {
  public render(): void {

    SPComponentLoader.loadCss('https://cdnjs.cloudflare.com/ajax/libs/uikit/3.21.11/css/uikit.min.css');

    this.domElement.innerHTML = `
      <div id="jquery-test">Hello, jQuery!</div>
      <a href="#" uk-icon="heart"></a>
      <div uk-slider="autoplay: true" id="my_slider">
        <div class="uk-slider-container">
          <!-- Slider items here -->
        </div>
      </div>
    `;

    // jQuery usage
    $('#jquery-test').text('jQuery is working!');

    // UIkit usage with 10-second timeout
    setTimeout(() => {
      if (UIkit) {
        // Test a simple UIkit notification to see if UIkit is loaded
        (UIkit as any).notification('UIkit is working!', { status: 'success' });

        // Try initializing the slider
        (UIkit as any).slider('#my_slider', {});
        console.log("THIS IS GOOD");
      } else {
        console.log("THIS IS BAD");  
      }
    }, 10000); // 10 seconds timeout
  }
}

Upvotes: 0

Related Questions