SharePoint Application Pages with React and Office Fabric UI interface

Let’s imagine that we have SharePoint on-prem. For some reason we want to ignore modern SharePoint development framework SPFx. We want to create SharePoint WSP solution with some pages – for example Application Pages.
I’m not a designer expert – I don’t want to spend my lifetime looking for icons to use, tweaking colors to make sure that we are web friendly etc. Sometimes the look and feel of an application takes longer to create than actually functionality behind the scene. It is so easier if we take Office Fabric UI and our SharePoint page will look like all other OOTB pages from Office 365.

“The Office UI Fabric is The front-end framework for building experiences for Office and Office 365. It is a responsive, mobile-first, front-end framework, designed to make it quick and simple for you to create web experiences using the Office Design Language. It’s easy to get up and running with Fabric – whether you’re creating a new Office experience from scratch or adding new features to an existing one.

We can simply import css file of Fabric UI Styles to our page and we could use styles from it – responsive UI, brand icons, colors, localization, theme generator, animations etc.

Another things are Fabric UI Components like Button, Checkbox, Rating, Slider, Breadcrumb, SearchBox, DetailsList, PeoplePicker, DatePicker, ColorPicker, MessageBar, ProgressIndicator, Dialog, Modal etc. List of all components you can see here.
But if you want to go with them, you have to use React (you can use AngularJS or Swift too) because they are built with the React framework. That is not bad side, that is good side! SPFx use React too, so your code could look very similar to them.

I want to share with you my idea / my solution how to use Office UI Fabric Components with React and TypeScript inside any type of SharePoint on-prem pages within WSP solution.

Lets start with WSP side of our example. Create two new folders inside SharePoint “Layouts” Mapped Folder: css folder for styles and js folder for scripts. Inside css folder add empty main.css file and inside js folder create empty main.js file.

2018-04-03_2036

Then create new Application Page with empty div inside it. Add references to newly created css and js files (some lines below are encoded because of WordPress editor).

<asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
    <SharePoint:CssRegistration Name="/_layouts/15/DummyProject/css/main.css" After="SharepointCssFile" runat="server" />
</asp:Content>
 
<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
    &lt;div id="xnet-react-app"&gt;&lt;/div&gt;
    &lt;script type="text/javascript" src="/_layouts/15/DummyProject/js/main.js" /&gt;
</asp:Content>

That’s all from Visual Studio for our WSP. You could deploy solution to SharePoint server at that time.

Now follows client-side scripting inside modern JavaScript runtime – Node.js. Download and install it from official page.

I will use create-react-app NPM package for creating React Project. You have to install it globally:

npm install -g create-react-app

After that you could create new React App inside your WSP solution folder. Create it on the same folder level as Package, Features, Layouts folders are. Create it with next command:

create-react-app my-react-app --scripts-version=react-scripts-ts

Then go with CMD to my-react-app folder and install next NPM packages which we will use it inside our React App:

npm install --save office-ui-fabric-react
npm install --save node-sass-chokidar
npm install --save npm-run-all

npm install --save-dev gulp
npm install --save-dev gulp-rename
npm install --save-dev gulp-run
npm install --save-dev jquery

npm install --save-dev @types/jquery
npm install --save-dev @types/node
npm install --save-dev @types/prop-types
npm install --save-dev @types/sharepoint

We will use office-ui-fabric-react package for Fabric UI Components, node-sass-chokidar for scss file conversion to css files, gulp for creating custom tasks for copying css and js files to WSP Layout folder and to SharePoint Server hive folder (C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\TEMPLATE\LAYOUTS). There is gulp-rename and gulp-run packages too. If we want, we could import JQuery too. There is also npm-run-all package for running npm commands from gulp task.

There are also some packages with type definitions. For example @types/sharepoint for Microsoft SharePoint. With it we could use _spPageContextInfo simple object.

Open project folder with VS Code and create files and folders marked below:

2018-04-03_2114

Open “package.json” file and define next eight npm commands inside scripts property:

"scripts": {
    "build-css": "node-sass-chokidar src/ -o src/",
    "watch-css": "npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive",
    "start-js": "react-scripts-ts start",
    "start": "npm-run-all -p watch-css start-js",
    "build-js": "react-scripts-ts build",
    "build": "npm-run-all build-css build-js",
    "test": "react-scripts-ts test --env=jsdom",
    "eject": "react-scripts-ts eject"
}

As you can see we use node-sass-chokidar and npm-run-all as I mentioned before. We will use that scripts a little later inside our gulp tasks.

Open “.vscode/settings.json” file and tell VS Code that you want to hide .css files with next statement (bold below):

{
    "files.exclude": {
        "**/.git": true,
        "**/.svn": true,
        "**/.hg": true,
        "**/CVS": true,
        "**/.DS_Store": true,
        "**/*.css": true
    }
}

Inside “gulp.config.js” add next paths:

module.exports = function () {
    var config = {
        srcScssPath: "./src/*.scss",
        srcTsPath: "./src/*.tsx",
        srcJsPath: "./build/static/**/*.js",
        dstJsPath: "../../Layouts/DummyProject/",
        srcCssPath: "./build/static/**/*.css",
        dstCssPath: "../../Layouts/DummyProject/",
        spPath: "C:\\Program Files\\Common Files\\microsoft shared\\Web Server Extensions\\16\\TEMPLATE\\Layouts\\DummyProject\\"
    };
    return config;
}

With paths above we define that we have scss and tsx files inside src folder. When we build our React App project with npm start command, bundled and minified css and js files are created inside build/static subfolder. So we define that js files from that folder will be copied to Layouts/DummyProject subfolder of our WSP project and to SP hive (srcJsPath -> dstJsPath & spPath). Same with css files (srcCssPath -> dstCssPath & spPath).

In “gulpfile.js” create next tasks:

var gulp = require("gulp");
var run = require("gulp-run");
var rename = require("gulp-rename");

var config = require("./gulp.config")();

gulp.task("transpile-tsx", function(){
    return run("npm run build-js").exec();
});

gulp.task("copy-files-tsx", ["transpile-tsx"], function() {
    return gulp.src(config.srcJsPath)
    .pipe(rename({
        basename: "main",
        extname: ".js"
    }))
    .pipe(gulp.dest(config.dstJsPath))
    .pipe(gulp.dest(config.spPath));
});

gulp.task("transpile-scss", function(){
    return run("npm run build").exec();
});

gulp.task("copy-files-scss", ["transpile-scss"], function() {
    return gulp.src(config.srcCssPath)
    .pipe(rename({
        basename: "main",
        extname: ".css"
    }))
    .pipe(gulp.dest(config.dstCssPath))
    .pipe(gulp.dest(config.spPath));
});

gulp.task("transpile", function(){
    return run("npm run build").exec();
});

gulp.task("copy-files", ["transpile"], function() {
    gulp.src(config.srcCssPath)
    .pipe(rename({
        basename: "main",
        extname: ".css"
    }))
    .pipe(gulp.dest(config.dstCssPath))
    .pipe(gulp.dest(config.spPath));

    return gulp.src(config.srcJsPath)
    .pipe(rename({
        basename: "main",
        extname: ".js"
    }))
    .pipe(gulp.dest(config.dstJsPath))
    .pipe(gulp.dest(config.spPath));
});

gulp.task("default", ["copy-files"], function() {
    gulp.watch(config.srcTsPath, ["copy-files-tsx"]).on("change", reportChange);
    gulp.watch(config.srcScssPath, ["copy-files-scss"]).on("change", reportChange);
});

function reportChange(event) {
    console.log("File " + event.path + " was " + event.type + ", running tasks...");
}

As you can see we have copy-files-tsx task for copying js files from build/static subfolder to Layouts project files and SP hive. Js files are renamed to main.js because in build/static subfolder have some suffixes appended. Js files are transpiled before that from TypeScript (.tsx files) inside transpile-tsx task with build-js script created before inside package.json file.

Same with scss files – we have copy-files-scss task for copying css files from build/static subfolder to Layouts project files and SP hive. Css files are renamed too. Css files are transpiled before that inside transpile-scss script from package.json.

With copy-files and transpile task we traspile and copy both type of files – TSX and SCSS.

We have default task which is called with simple “gulp” command. That command trigger copy-files task and watch for changes in TSX and SCSS files. When changes are made, copy-files-tsx and copy-files-scss tasks are called.

Replace content of “tsconfig.json” file with that compiler options (some are changed from default values like false for “noUnusedLocals” etc.):

"compilerOptions": {
    "outDir": "build/dist",
    "module": "esnext",
    "target": "es5",
    "lib": ["es6", "dom"],
    "sourceMap": true,
    "allowJs": true,
    "jsx": "react",
    "moduleResolution": "node",
    "rootDir": "src",
    "forceConsistentCasingInFileNames": true,
    "noImplicitReturns": true,
    "noImplicitThis": false,
    "noImplicitAny": false,
    "strictNullChecks": true,
    "suppressImplicitAnyIndexErrors": true,
    "noUnusedLocals": false,
    "experimentalDecorators": true
}

Replace content of “tslint.json” file with that too:

{
  "$schema": "https://dev.office.com/json-schemas/core-build/tslint.schema.json",
  // Display errors as warnings
  "displayAsWarning": true,
  // The TSLint task may have been configured with several custom lint rules
  // before this config file is read (for example lint rules from the tslint-microsoft-contrib
  // project). If true, this flag will deactivate any of these rules.
  "removeExistingRules": true,
  // When true, the TSLint task is configured with some default TSLint "rules.":
  "useDefaultConfigAsBase": false,
  // Since removeExistingRules=true and useDefaultConfigAsBase=false, there will be no lint rules
  // which are active, other than the list of rules below.
  "lintConfig": {
    // Opt-in to Lint rules which help to eliminate bugs in JavaScript
    "rules": {
      "class-name": false,
      "export-name": false,
      "forin": false,
      "label-position": false,
      "member-access": true,
      "no-arg": false,
      "no-console": false,
      "no-construct": false,
      "no-duplicate-case": true,
      "no-duplicate-variable": true,
      "no-eval": false,
      "no-function-expression": true,
      "no-internal-module": true,
      "no-shadowed-variable": true,
      "no-switch-case-fall-through": true,
      "no-unnecessary-semicolons": true,
      "no-unused-expression": true,
      "no-use-before-declare": true,
      "no-with-statement": true,
      "semicolon": true,
      "trailing-comma": false,
      "typedef": false,
      "typedef-whitespace": false,
      "use-named-parameter": true,
      "valid-typeof": true,
      "variable-name": false,
      "whitespace": false
    }
  }
}

I took that tslint.json file from SPFx template so you will not have so many error / warning messages different from SPFx project.

Go to public/index.html file and replace line 28 with that:

&lt;div id="my-react-app"&gt;&lt;/div&gt;

From src folder delete next files because you will not need them:

  • App.test.tsx
  • logo.svg
  • registerServiceWorker.ts

Then create App.scss and index.scss files. Now you must have that files in src folder: 2018-04-03_2155

From “src/index.tsx” file delete next two statements:

import registerServiceWorker from './registerServiceWorker';
registerServiceWorker();

Change line 8 in that way that content of file is now like that below:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import App from './App';
import './index.css';
 
ReactDOM.render(
  <App />,
  document.getElementById('my-react-app') as HTMLElement
);

From “src/app.tsx” file delete that two lines:

const logo = require('./logo.svg');
<img src={logo} className="App-logo" alt="logo" />

Thats all for our React App inside SharePoint Application Page. Open app.tsx file and make React Component for your page like you want.

You could test your React App locally (without SharePoint backend) with that command:

npm start

If you modify tsx or scss files, all changes are up-to-date asap in browser.

If you want to test your React App inside SharePoint Application Page use that command:

gulp

Same here – if you modify tsx or scss files, all changes are up-to-date asap in your SharePoint Application Page, without need to long-running process of deploying your WSP solution to SharePoint Server.

I will create SharePoint 2016 project template for WSP and template for React App inside it in next few days on my GitHub and I will post that on my blog here.

Cheers!
Gašper Rupnik

{End.}

Advertisements

One thought on “SharePoint Application Pages with React and Office Fabric UI interface

Add yours

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Powered by WordPress.com.

Up ↑

%d bloggers like this: