Thursday, August 31, 2017

Controlling SPFx bundle file name in production builds

As promised, sharing the code as discussed in my SPFx advanced development session , in this blog post and in this GitHub discussion.


As you might know already, when building an SPFx component in production (gulp --ship) you could not control the produced file name of your bundle JS file.

The file would be generated as:
{product}.bundle-{hash}.js

That caused a lot of grief for our caching mechanism and our version management and product release strategy, preventing us from taking control over our cache strategy, using other java script optimization tools (due to the bundle file name) and publishing minor fixes without requiring our clients to install a new package.

It seems currently there is no supported way to control that, and that the production file name is being set hard coded in the copyAssetsTask.

After a lot of trials, I finally managed to find a way to control it, but it involves hacking into the build process in a way that I am pretty sure will not be future-upgrade proof.

So, until such time as the good people at Microsoft exposes this to us in a supported way, here is what you can do today.

Remove the hash from SPFx bundle file name

1. Load package-solution.json so that you can get the version number from it:
const packageJson = require('./config/package-solution.json');

2. Add this code in your gulp file, just before build.initialize(gulp);
var original_renameWithHash = build.copyAssets._renameWithHash.bind(build.copyAssets);
build.copyAssets._renameWithHash = function (gulpStream, getFilename, filenameCallback) {
var original_GetFileName = getFilename;
getFilename = function (hash) { return original_GetFileName(hash)
.replace('_' + hash, '.' + packageJson.solution.version); };
return original_renameWithHash(gulpStream, getFilename, filenameCallback);
};

Remove the .bundle from SPFx bundle file name

This one, was suprisingly simple to do.
Thanks to @iclanton pointing out, all you need to do is edit the config/config.json file, and change the outputPath property.

Adding a post build task

As a part of my trial an errors, I tried adding a post build task. It didn't help in this case since it runs before the bundle process begins but here is how you do it just in case you might need to:

//Add post build task. This still runs before bundle task
let renameFilesProductionTask = build.subTask'rename-files-production',
function(gulp, buildOptions, done) {
var production = (process.argv.indexOf('--ship') !== -1);
if(production)
this.log('Built in production!');
done();
});
build.rig.addPostBuildTask(renameFilesProductionTask);


I hope this helps. I will update this post once I learn if there is a better way to achieve this.

Thanks.

Thursday, August 24, 2017

Setting up automatic deployment to azure web app

This is something we have been working on for a long time, far too long. There are so many samples and options out there it was very difficult for us to set up, and now that we finally have our environment up and running I thought I'd share our experience.

Our set up

First, let me describe our current set up.

See, with SharePoint hosted add-ins, Provider hosted add-ins, click once applications and other services (like licensing, captcha, etc) - we had to set up a web app on azure.

That web app serves as a CDN for our JS/CSS/HTML/Images and a few asp.net apps, and we had to set it up to be globally available, so using a traffic manager we have a few servers around the world handling local traffic.

Now, we set up one extra server for what we call a "fast ring" release cycle.
That's where we publish our beta versions for testing, and after a short cooling period we push them to the production servers.

So, basically each app we release requires us to publish to 1 fast ring server, and later to a few production servers in what you can imagine is a very time consuming and error prone publishing process.

Also, every server we added to the mix required the developer to publish to that server as well.

So automating this was a high priority for us from the beginning.

Automation options

I've continuously discussed and read about azure automated deployments, and was very happy to see there were a lot of options to publish to azure but neither answered all of our needs.

Synced library (DropBox, OneDrive, etc)

This option was by far the easiest to set up. You basically register one of these services to be the source of your web app.
Surprisingly, no OneDrive for business support - only personal OneDrive. Actually, this is more than a surprise, it is flat out ridiculous since the target audience here is clearly a business user with a very high likelihood to be a O365 subscriber!

But that wasn't what threw me off.

You would get a sub folder in your service, and map it to a server.
So, I could build a "production" folder and "fast ring" folder and map them to their servers. Easy enough.
Then, I would have to sync that client to my dev machine, and "publish" my web apps into that local folder.
That would in turn sync the changes into the cloud, and at that point it gets tricky.
There isn't a way for azure to detect changes and start the update automatically.
You would have to visit each and every web app and click the "sync" button to have them sync their content with the storage service.
I'm sure I could write a script or some code that would automate this, but I was trying to avoid writing any code for something like this - so moving on.

Azure continuous deployment from visual studio online

In azure, under the web app there is a way to set up a connection to a project in Visual Studio online.
Since all our source code is stored in visual studio online anyways in Git repositories - I really had my hopes up.
Setting this up was just impossible.
Since we have an MSDN azure subscription where all our services are set up, and our O365 tenant is on a different subscription, our visual studio online was associated with our O365 tenant so that we can use those logins.
It seems it made it impossible to associate that visual studio online account with our azure MSDN subscription, so I tried and tried and it seemed to be impossible so I gave up.

Visual studio online "Build & Release"

Finally, I went to visual studio online and noticed there is a way to configure it to build your project on their servers and set it up to publish and release to many remote services, including azure.

I honestly struggled with setting up the build on the server. I got it to work on some projects, others threw errors and I was about to give up. I'm sure its possible and I will definitely work on it again until I get it working like I want it, but even though - getting it to publish a click once project for example would be complex, using our code signing tools and many of our pre/post build custom events and so on - it might be too complex to do.
But, I came up with a simpler way of doing it.
We would build our projects locally, and publish them locally.
Web applications - as a deployment package file. this produced a zip file, that we would check in the source control.
Next we can publish that zip file package to azure, and set up a trigger for the publish task on that zip file so that it would run automatically whenever the zip file changed.

For click once - we basically check in the "publish" folder, and did the same thing - put a trigger on it, and set up a task to publish that entire folder every time it changes.

This allows us to still build and publish using our dev machines, and have visual studio online job only handle publishing the content to the web servers in azure.

Next, we decided our "master" branch would be our production. Created a "fast ring" branch that would be published to the fast ring and we were done.

That was by far the easiest to set up (connecting to azure subscription took 2-3 minutes, but at least it worked), and was automatically triggering whenever we pushed a new version.

The only downside is, that I couldn't set it up to build the package on the server, but like I said - still working on it.

So, if you are working in visual studio online, obviously I would recommend this approach. But if you are not - you should check it out anyways, since the build & release tasks there support getting your source code from many sources (GitHub, Remote Git repo, Subversion) has a ton of build and publish tasks you can add and supports publishing to many services (not just Azure).

Also cool - is that I now get an email saying if a publish went through OK or failed. So I do have some monitoring on whats going on moving forward, which is great.

Definitely the easiest one to set up, and I wish we had done this a year ago.

If you have experience with something like that, please share your thoughts in the comments below, also questions are always welcome.

Tuesday, August 1, 2017

SPFx: An ISV Insight to Microsoft's latest customization model

As promised, here is my blog post about this session from @spsnyc

Thanks for all the great reviews, the comment I got the most was that it had too much great info.

My greatest challenge writing this session was focusing on a few advanced topics that were not widely covered by other SPFx sessions.

There is an influx of SPFx sessions on every conference these days, and I find the majority of them (maybe rightly so) focus on beginner level introduction to SPFx.

What I wanted to do with this session is something different.

Focus on a few important more advanced topics that were not widely covered by other speakers.

This led me to build this level 300-400 session that focuses on these key points:

  • Publishing versions
  • Pushing updates through CDN
  • Sharing code between projects
  • Building a custom PropertyPane property
I cover these points in a deeper level, and accompany them with complete source code example of my solution.

Here is the slide show:


* I highly recommend downloading and viewing the slideshow in PowerPoint to view my speaker notes and comments on each slide.

Here is the code samples:

https://github.com/KWizCom/SPFxDemo

Please feel free to give me more comments and suggestions on what would you like to hear about, so I could update my session accordingly.

Also consider following the github project since I will publish updates to the source examples to it.

Thanks.

Updates and related posts: