In this post I want to explain an approach of how to handle (generate builds, update customers) multiple editions of the same SharePoint Framework solutions. Use case for the approach: You are an ISV and developing some product that has multiple editions, let's say, trial, lite, full. You want to have separate package file (sppkg) for each edition and also reference different CDNs based on the edition. The approach I'll describe is not the only possible but it was successfully used for our own products. Thinking about the problem in details we can point several key features that should be implemented:
When we're creating a new version we should create 3 separate sppkg files
Each sppkg file should contain manifest that references different CDN endpoints
It should be easy to upgrade customer from trial to lite and then to full; or directly from trial to full
You should know current edition in the code to execute the logic based on the edition's restrictions
Let's look at each point separately and describe what should be done to implement needed behavior.
When we're creating a new version we should create 3 separate sppkg files
The path to the sppkg file is configured in config/package-solution.json file in paths.zippedPackage property. By default, it contains solution/<name-of-the-solution>.sppkg which means that the file will be created in sharepoint/solution folder. The first idea was to have different filename for each edition, like product-trial.sppkg, product-lite.sppkg and product-full.sppkg. But it will not work as you can't deploy both packages to App Catalog. You'll receive the exception that two different packages can't contain the same solution. So the other approach is to create subfolders for each version, like solution/trial/product.sppkg, solution/lite/product.sppkg and solution/full/product.sppkg
Each sppkg file should contain manifest that references different CDN endpoints
CDN endpoint is config/write-manifests.json file in cdnBasePath property. And also in config/deploy-azure-storage.json in container property - this should be also taken into consideration if you're going to deploy the assets to the Azure. So, we can change these properties to reference different CDN endpoints.
It should be easy to upgrade customer from trial to lite and then to full; or directly from trial to full
Currently app updates are done based on the value of solution.version property in config/package-solution.json file. If you look at Apps for SharePoint list in the App Catalog you'll see that each deployed package (or app) has App Version value. If you install a newer version of the package SharePoint will mark the app as needed for update. And later a user can get newer version of the app on specific site (or the app will be updated everywhere automatically if tenant-scoped deployment is enabled. The solution.version has 4-digit signature (as everything in Microsoft Universe): major.minor.build.revision. So, we can use revision to address each of our editions:
0 for trial
1 for lite
2 for full
It will allow us to update any customer from, let's say, trial to full by providing a solution package that has the same major, minor and build digits but 2 instead on 0 in revision digit. As 2 > 0 it will mark the app as needed for update.
You should know current edition in the code to execute the logic based on the edition's restrictions
The idea here is to have some configuration file that is referenced in the code and the content if which differs for each edition. In our product we created a file custom-config.json in web part folder that contains JSON with current edition:
And then the file is referenced in web part's code:
Combining all in one
We addressed all the points but still the process is totally manual. It would be great to automate needed changes. And it can be done with custom Gulp tasks. First of all, let's create a json file to contain settings for each edition. Needed settings are:
edition name
azure container
CDN path
revision number (0, 1 or 2 in our case)
package path
Let's name the file build-config.json and add it to config folder. The content of the file should be like that:
Now we can create a Gulp task that will take edition as a parameter and will modify configuration files base on edition settings. The task should be added to gulpfile.js before global initialization of the build (it means before line build.initialize(gulp)). You can read more about custom Gulp tasks in SPFx here. The steps in the task will address all the points addressed above:
Modify config/package-solution.json to change revision number in solution.version property and also change paths.zippedPackage property. It worth saying that right now gulp package-solution fails if zippedPackage contains path to the folder that doesn't exist. That's why we'll need to additionally 'ensure' path to the sppkg. In our case we'll check if there is trail|lite|full subfolder in sharepoint/solution and create it if needed.
Modify config/write-manifests.json to change CDN endpoint url
Modify config/deploy-azure-storage.json to change Azure Storage container, and
Modify custom-config.json file in web part's source code folder to set current edition
Full code of gulpfile.js is listed below:
Now you can run this task as
And then run out of the box
to package specific version. After you run these for tasks for each edition you'll have 3 sppkg files in separate subfolder and also referencing CDN endpoints with different custom-config.json content. And consequently edition-based behavior. Now you can deploy trial or lite edition to App Catalog and then easily upgrade to full. Hope this post will help developing SPFx 3d party products. Have fun!
Comments