Environment Update During Builds
In this article, we will learn how to make environment-based changes dynamically. I was using CDN in my application and as you know the URL changes for each environment so before creating a build I must make changes everywhere.
This was boring, so I thought of automating it. I started Googling it and found plugins that can do these changes on Json files but what happens if there is something in code (i.e. typescript files.)?
Before we go in detail, you should know SPFx uses “webpack” as a module bundler and “gulp” for tasks. For more details about these, you can Google it. In the latest version of SPFx 1.10.0, they use webpack 4+. Webpack 4+ has few inbuilt plugins like define plugin. This define plugin will help us in defining global constants. For modifications in the JSON file, we will create a task which is like gulp task and add in the SPFx pipeline.
This code has to be added in gulp file before “build.Initialize(gulp);”.
-
- var cdnurl = "";
- var tinymcecdnurl=""
- var gulpenvsetting="local";
-
- const getCDNUrl = build.subTask('getcdnurl', (gulp, buildConfig, done) => {
-
- const targetval = buildConfig.args['target-env'];
-
- if (targetval) {
- gulpenvsetting = targetval;
- }
-
- if (gulpenvsetting == "local") {
- cdnurl = "https://publiccdn.sharepointonline.com/<<url>>";
- }
- else if (gulpenvsetting == "qa") {
- cdnurl = "https://publiccdn.sharepointonline.com/<<url>>";
- }
- else if (gulpenvsetting == "prod") {
- cdnurl = "https://publiccdn.sharepointonline.com/<<url>>";
- }
- tinymcecdnurl = cdnurl + '/tinymce/tinymce.min.js';
- done();
- });
-
-
- const replaceCDNUrlsInConfig = build.subTask('replacecdnurl', (gulp, buildConfig, done) => {
-
-
- for (const key in buildConfig.properties.externals) {
- var external = buildConfig.properties.externals[key];
-
- if (external.path) {
- external.path = external.path.replace(dummyurl, cdnurl);
- }
- else {
- buildConfig.properties.externals[key] = external.replace(dummyurl, cdnurl);
- }
-
- }
- done();
- });
-
-
- build.configureWebpack.mergeConfig({
- additionalConfiguration: (generatedConfiguration) => {
- for (var i = 0; i < generatedConfiguration.plugins.length; i++) {
- var plugin = generatedConfiguration.plugins[i];
- if (plugin instanceof webpack.DefinePlugin) {
-
- plugin.definitions.tinymcecdnurl = JSON.stringify(tinymcecdnurl);
- break;
- }
- }
- return generatedConfiguration;
- }
- });
-
- build.rig.addPreBuildTask(getCDNUrl);
- build.rig.addPostBuildTask(replaceCDNUrlsInConfig);
I have already added comments in the code which will help you out. As you can see, I have pasted the actual code and not the whole file. Variables are defined at the top in gulp as per standard, but you can define anywhere. Each function can be defined as a task in gulp, so we define two functions, one for initializing environment variables based on a single parameter and another function that changes the properties. We can do other operations based on our requirements.
Now, if you see in the end, I have added this function as a task in the SPFx pipeline. If you type “build.rig.” you will be presented with a lot of options. I have used the ones which I found suitable, but you can use others depending upon your requirement. ”getCDNUrl” is an independent function which just needs input from the terminal so I have executed this as first and added as "addPreBuildTask". Once I initialize all the env settings I have added replacement logic in “addPostBuildTask”. This gets executed just before the webpack execution starts.
For replacement in files, you must define global constants that a webpack can replace later during bundling. This global constant is initialized using the Define plugin. MergeConfig and DefinePlugin are inbuilt in webpack so you don’t need to download any other package.
We will see how we use this in our files. First, let us see how to use global constants. There can be other ways, but with the following way that I am using in my code, during compile time the webpack will be replaced with an actual string.
- var TinyMCECdnUrl = `${tinymcecdnurl}`;
Config.json sample
- "externals": {
- "moment": "https://<<dummystring>>/moment.js"
- }
As you can see, I have used a dummy string that will be replaced during compile time.
Now, from the terminal, you can write the below compile command, and accordingly, your code will have the env settings:
- gulp build --target-env qa/prod/local
- gulp bundle --target-env qa/prod/local --ship
- gulp package-solution --target-env qa/prod/local –ship
Please let me know how you liked this article. I will post another article in the series soon.