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

Updating SPFx package still showing the older web part

Something I noticed while working with SPFx,
some times I would release a new package to my app catalog by dragging it over an existing older version.

SharePoint would prompt me to overwrite, I would say yes.

Now, every page refresh I would randomly get the older file loaded or the latest one loaded. It was completely unpredictable and didn't seem to depend on anything specific I did.

What happens?

It seems when you overwrite a package, you don't get the dialog to trust the package. Now, that dialog is important, since while you visit it, it plants a cookie in your browser that marks for SharePoint to drop its package cache and reload the manifest.
If that cookie is missing... you would be getting a cached version of the manifest.
Since SharePoint Online is a beast with many WFE servers in load balanced setup, you sometimes get a server that cleared its cache (maybe the one that handled the replace action) and other times a server that still has the older one cached.

This situation is not a big deal in production, since in 20 minutes or so the cache clears itself.

But for dev - here is what you have to do to avoid it:
Simply delete the package before you upload a new one, and don't use the overwrite option.

Simple, efficient but very confusing...

Hope this helps!

Versioning strategy for SPFx

Background


As an ISV, one of the most important aspects of our products is - you guesed it - product versioning.

Versioning is important for a lot of things:

  • It tells users if they are running the latest bits of their software
  • It helps support reproduce issues and report them more accurately
  • It helps developers track bugs and issues, when they occur and when they were fixed
  • It tells the product manager how the product is moving along its roadmap
... and more!

One thing I am not a big fan of is how SPFx handles product releases and versions.

See, as an ISV in the cloud-world, we find it important from time to time to push updates to our apps to all our customers at once, without having to ask them to download and install a new version of the application.

We do that by updating the resources in our CDN, expiring our cache and that makes sure all clients get the latest and greatest builds automatically.

Imagine you have a spelling mistake, typo, or that an update is rolling out that causes a critical failure of your product. In these situations, we usually push updates from our servers to all our customers, and they don't have to worry about updating anything themselves.

(Remember the days you had to go to the app store on your phone and hit "update" on every app? Yuck!)

So, for that reason, I find the way SPFx produces builds a bit lacking.
See, whenever you are ready to release a build, you type gulp --ship to build your scripts in release mode.
That produces a bundled JS file that contains a hash in the file name.
Meaning - every little change you do will produce a different hash code.


data-view-plus.bundle_d41aab51ecdd17f15f7f921d87534405.js

Now, the manifest points to that specific file with that specific hash, and requires you to produce a new app package, and install that new package on your app catalog.

Although the bundle JS file is most likely hosted in your CDN, each new version you release points to a new different file, so no one gets updates automatically.

Moreover, you have no way of controlling when your clients upgrade, so you can never remove older files from your CDN, making it a complete mess and nightmare to maintain in an ever-growing pile of files, most of which no one will ever use.

This is why we chose to go a different route when releasing our SPFx versions.

Instead of using the hash - we use a package version in the JS file name.
As long as we make small changes that we want to push automatically, we keep the same file name and push the changes to our CDN.
We track the build number using a JS variable inside our code to be able to keep track on what build is the current client running, since we do not change the package version on every release.


data-view-plus.1.0.0.5.js

Every time we have a bigger change, that changes our package manifest (added a web part, added or changed a dependency library) - that requires a new app package to be released. So only on these circumstances we advance the package version (config\package-solution.json) and release a new package with a new bundle file name to match it.

This significantly reduces the amount of script files we have in our CDN, makes each file very easy to understand which build it belongs to (instead of those hash codes) and allows us to push minor updates without requiring our users to install a new package in their catalog.


So, how do we do it?

I'm afraid we have yet to automate this part... but the steps are not too complicated to follow, I promise.
From this point I assume you have your SPFx project all ready and set up, configured with a CDN of your choice.

Releasing a new package version

  1. Change the version in your config\package-solution.json file
  2. Advance your "BuildNumber" variable in your code (optional)
  3. Run 'gulp --ship'
  4. Visit the new files outputted to temp\deploy
  5. Edit the bundle JS file name, replace the hash with the version you put in step 1
  6. Edit the [guid].json file, it should have the bundle JS file name in it - replace with with the new file name you came up with in step 5
  7. Save all changes
  8. Run 'gulp package-solution --ship'
  9. Now, you package will be ready for you under SharePoint/Solution and it will use the file name you set in step 5
  10. Don't forget to copy your bundle JS file to your CDN, do not remove older versions from the CDN if you have them.

Releasing patches or minor updates

  1. Advance your "BuildNumber" variable in your code (optional)
  2. Run 'gulp --ship'
  3. Copy the content of the bundle JS file from either temp\deploy or from the dist folder into the CDN, overwrite the content of the latest version file you got there
Hint: how can you tell if your change requires a new package or not? Simple. Add the web part to a SharePoint page (classic or modern) - not the workbench. It will use the old web part definition. If it runs - it means your changes did not break the signature of the bundle. If you get a nasty error message, time to release a new version.

Do you manage versions in SPFx? Do it differently? I would love to hear, please leave a comment!
Also, know how to automate my process? Please share!

Thanks for reading,
Shai.

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.