Friday, June 23, 2017

SPFx workbench certificate error in Chrome after v58

Anyone using the workbench in chrome either already noticed or will very soon that the workbench is no longer working as of update 58 of chrome.

If you use the local workbench - no problem. you will see a clear certificate error, and you will be able to proceed with an "unsafe" certificate.

But, if you try to use the online workbench (at /_layouts/15/workbench.aspx ) things will be a bit more tricky...

See, you won't get a certificate error right away. Instead your online workbench (which is on your SharePoint site's certificate, which is perfectly valid) will load up correctly and will show the message as if you are not running gulp serve:


Why? If you open the dev tools you will see under network that all the requests to localhost were blocked due to the same issue with the bad certificate.

There are 2 things you can do:

Temporary fix:

Browse to the local workbench in chrome, select to proceed with the unsafe certificate. This will allow chrome to access your localhost.
Now, your online workbench should also start working as expected.
This should last until you close your browser.

Permanent fix:

It seems a new certificate was created that works with Chrome, as a part of the "sp-build-web" npm package v1.0.1
(Thanks Ian, @iclanton read more here)

SPFx GA points to v1.0.0 which doesn't include the new certificate.

To make the fix permanent, here are the exact steps I took (after a lot of tries and other variations that just led to more trouble...):
  1. edit package.json and change ONLY the sp-build-web version to 1.0.1 (Not to the latest, as gulp serve will stop working if you do)
  2. delete node_modules folder (npm install will fail if you don't delete the entire folder)
  3. run npm install
  4. run gulp untrust-dev-cert (you should be prompted to delete a certificate)
  5. run gulp trust-dev-cert (you should be prompted to install a certificate)
  6. run gulp serve
Now, your local or online workbench should work as expected.

This took way longer than I expected, since any single different thing I tried resulted in either a broken project or npm install failure...

Good luck!

Thursday, June 22, 2017

Using KnockoutJS in the new SPFx - containerless control flow removed

Many of you probably know how excited and happy I am with the SharePoint Framework (aka SPFx). Finally, a worthy client side framework for SharePoint extensibility.

SPFx promises a lot, and delivers even more with a very powerful engine that drives it.

One of the things it promises is giving developers the freedom to choose their client side development story, which platforms frameworks and libraries they want to use and how.

However, it is clear that ReactJS is the framework of choice for Microsoft, having the most complete Office Fabric components library (and probably the only one that is maintained by Microsoft pretty regularly), so by all means: when ever you can go react - don't look back.

While building our DataViewPlus web part (DVP), I had a requirement that prevented me from using react.
You see, react uses controls that are compiled into JavaScript objects, thus limiting the rendered HTML to what your developer had when he built the web part.

In our DVP web part, we wanted to give users the ability to customize, change, extend the html of the rendering templates or even provide their own HTML template for the rendered web part. Similar to what you could do with the SharePoint Designer data view, only without the nasty xsl language.

For that reason, I think KnockoutJS (KO) was the perfect fit for my project.

One of the features in KO that I love using is container-less commands. So, unlike other MVVM frameworks that had to output a tag to the page in order to do bindings - KO allows you to use HTML comments to do the bindings.
For example:
<!-- ko if: someExpressionGoesHere -->

I want to make this item present/absent dynamically

<!-- /ko -->

See, this is very useful in KO and I use it a lot. I think you can't really do much with KO without using at least some containerless statements. Once you grow beyond your hello world project, you will pretty quickly find yourself using a containerless if or foreach statement.

I noticed during my development stages with SPFx, using the workbench I had no problems with it at all and my web part worked perfectly.

However as soon as I built to production (gulp --ship) I noticed none of my KO templates rendered to the page.

After a bit of digging (and a lot of console.log...) I noticed all my KO HTML templates were loaded correctly with one small difference: All my HTML comments were removed!

It seems during production build, the html-loader plugin kicks in and calls UglifyjsWebpackPlugin.
This plugin by default remove all comments from the output, except important comments that contains:
/*!, /**!, @preserve or @license

Luckily, SPFx allows us to intervene with its build steps and make some changes in the way webpack works. (More on webpack in a future post)
There are several ways we can go about fixing this issue with the comments.
One is to replace the html-loader that SPFx uses with a KO friendly version.
Another would be to edit the configuration of the UglifyjsWebpackPlugin in the node_modules folder, which I don't recommend since you will have to re-do it every time you do npm install on a new machine.

So I dug deep into its code and found that the loader is checking for parameters in a query string format provided to it, and one of these parameters that we can pass is called "removeComments"!

So, by editing my gulpfile.js I was able to tell SPFx not to remove any comments from HTML template files I was loading.

Here is my new gulpfile.js:
'use strict'; const gulp = require('gulp'); const gutil = require('gulp-util'); const build = require('@microsoft/sp-build-web'); build.configureWebpack.mergeConfig({ additionalConfiguration: (config) => { config.module.loaders.forEach((loader) => { if (loader.loader === "html-loader") { gutil.log("Got html loader " + JSON.stringify(loader)); loader.loader += "?removeComments=false"; } }); return config; } }); build.initialize(gulp);
I must note that it should also be possible to configure this to only keep KO comments, but that would require changing the way the loader is configured which might be more tricky (if not impossible) via the gulpfile.js

So, my conclusion is, although the guys @MSFT did an amazing job with SPFx and opening it to other frameworks, and while KO is actually included in the yeoman generator - there is still an advantage on working with ReactJS over KO or other frameworks, simply because that's what the developers are using so it makes sense it is more stable and tested more.
However, like you just saw, this framework is powerful enough that even when you need to use other less popular frameworks you can still make do and apply some tweaks and fixes yourself as needed.

Hope this helps you guys if you happen to choose KO for your SPFx web parts.

Please leave a comment and let me know which framework you are using with SPFx, and what is your experience with these platforms.

Wednesday, March 22, 2017

Using Office UI Fabric JS in SPFx

SPFx and Office UI Fabric JS not playing nice

I recently started digging into SPFx web parts in a more serious way than the "hello-world" level web parts we did so far during the learning period of this great new platform for SharePoint add-ins.

My web part had some requirements that prevented me from using react in any way, but at the same time I had a requirement to use Office UI Fabric Components.

I was using KnockOut to render my UI, and naturally, I turned to OFfice UI Fabric JS and their great components.

Only then I discovered that the fabric.components.css had a version conflict with the SPFx and its built in react version of components, and they would mess each other's layout.

Buttons would not be aligned properly, drop downs from react would not open at all, popups and panels would look strange and almost every control I used had some deformity to it.

CSS conflict issues

I reported it to the SPFx, and they published a great article of explaining the issue in great detail, but basically there is nothing much that can be done since CSS is mostly global and there is no good way to scope it without the possibility of conflicts (I've had a very long discussion on this topic with our product dev manager, the great Kevin Vieira, as well, I was not convinced with any of the solutions we came up with).

Solution: renamed prefix

The only way I could think would allow us to use office ui fabric js without worrying that other versions or other vendors could interfere was to rename the fabric into our own unique name.

Meaning, changing the ms-class prefix into something else, like kw-class, and also changing the JS global fabric object to something like kwfabric.

Now, that seemed to be a lot of work to do, plus you will have to host your own version somewhere and won't be able to use the Microsoft CDNs directly.

So, I've decided we will host these files for everyone to use on our own apps.kwizcom.com server, and will generate the files for you with your own prefix on the fly, so you won't have to do it manually.

You are all welcome to use this to generate your own css/js files, or use them directly from our CDN. Our CDN is hosted in Azure and geo-replicated so it should have pretty goo response times, but KWizcom takes no responsibility if you want to us it.

By the way, since I am hosting the files on our servers, I was able to also fix quite a few bugs in the office ui fabric js script file, so our version might be a bit different than the one hosted by Microsoft.

So, here is how you use our version of fabric, assuming your chosen prefix is "kw" (you should use your own unique prefix):
* note: I limited the prefix to 4 letters max.

In SPFx project:

SPComponentLoader.loadCss(`https://apps.kwizcom.com/libs/office-ui-fabric-js/1.4.0/css/fabric.css?prefix=kw`);

SPComponentLoader.loadCss(`https://apps.kwizcom.com/libs/office-ui-fabric-js/1.4.0/css/fabric.components.css?prefix=kw`);

SPComponentLoader.loadScript(`https://apps.kwizcom.com/libs/office-ui-fabric-js/1.4.0/js/fabric.js?prefix=kw`, {globalExportsName:'kwfabric'});

In HTML:

<link href="https://apps.kwizcom.com/libs/office-ui-fabric-js/1.4.0/css/fabric.css?prefix=kw" rel="stylesheet" type="text/css"></link>

<link href="https://apps.kwizcom.com/libs/office-ui-fabric-js/1.4.0/css/fabric.components.css?prefix=kw" rel="stylesheet" type="text/css"></link>

<script src="https://apps.kwizcom.com/libs/office-ui-fabric-js/1.4.0/js/fabric.js?prefix=kw" type="text/javascript"></script>

You will use them with your provided prefix, for example: instead of ms-Button, use kw-Button and in JavaScript instead of fabric, use the kwfabric object.