How to implement Azure DevOps pipelines for SPFx solutions that use library components
Last updated on September 3, 2023
SharePoint Framework (SPFx) library components are excellent when you have two or more SPFx solutions (web parts or extensions) that use the same code. Instead of duplicating the code to all of these separate solutions, you should include the shared code in a library component and then reference the library component in all the solutions where you want to utilize the code. If you ever need to do a bug fix or a change to the code, you only need to do it to a single location instead of updating all of the solutions separately.
A downside of using library components is that they can cause a real headache when bundling and packaging your code for production. You need to do the bundling in a particular order, or you’ll encounter errors after you’ve deployed the solutions to the SharePoint app catalog.
To avoid this tedious process (and run some automated checks on my code), I wanted to create an Azure DevOps pipeline to build, package, and deploy my SPFx solution to the SharePoint app catalog whenever I pushed new code to the repository. Besides, publishing applications via YAML pipelines is the best practice for deploying code.
In this blog post, I want to share how you can build, package, and publish a SharePoint Framework solution that utilizes an SPFx library component from another repository in the same Azure DevOps organization. Without further ado, let’s get this show on the road and look at how it is done!
Table of contents
- Enabling authentication to SharePoint Online from Azure DevOps pipelines
- Utilizing a variable group
- Explanation of the pipeline actions
- TLDR: The complete pipelines
Enabling authentication to SharePoint Online from Azure DevOps pipelines
It might seem we are doing things in a funky order, but trust me, starting by setting up the authentication-related components requires the least amount of going back and forth between different views.
So, you know that eventually, we’ll need to deploy the code package (.sppkg) to the SharePoint app catalog. To be able to do that, we’ll need to authenticate to SharePoint Online during the pipeline execution. And for that to work, we need to do two things: create a self-signed certificate and configure an Azure AD application registration.
Self-signed certificate
We need a self-signed certificate for authenticating to SharePoint Online. We can create one by executing the PowerShell script below. Before running the script, adjust the $commonName and $password variable values. The certificate files will appear in the same directory where you execute the script.
Also, you must have the PnP.PowerShell module installed for the script to run successfully. If you install PnP.PowerShell version 2.0.0 or higher, you need to run the script using PowerShell 7. You can find instructions for installing PowerShell 7 on Microsoft documentation.
After creating the self-signed certificate, click Library under Pipelines on the Azure DevOps project where your code resides, and open the Secure files tab. Here, you should upload the generated .pfx certificate file so it is securely stored and accessible by the pipelines.
Azure AD application registration
We must also create a new application registration on Azure AD for authentication.
- On Azure Portal, click on Azure Active Directory on the left-hand side navigation. Then, select App Registrations.
- Click on New Registration.
- Name the app registration however you want (e.g., Azure DevOps SPFx pipelines). Otherwise, you can leave the settings to their default values and click on Register.
After creating the application registration, we must configure it with permissions and a certificate.
- In the application registration settings, as the first thing while you are still on the Overview blade, please copy the Application (client) ID and the Directory (tenant) ID to, e.g., Notepad. You’ll need them later!
- Then, go to the API permissions blade and do the following.
- Click on Add a permission.
- Select SharePoint.
- Select Application Permissions.
- Select Sites.FullControl.All.
- Click on Add Permissions.
- Again, click on Add a permission.
- This time, select Microsoft Graph.
- Select Application Permissions.
- Select Sites.Read.All.
- Click on Add Permissions.
- Click on Grant admin consent for the organization. You may need to ask your global admin to perform this step if you do not have the required permissions.
- Click on Add a permission.
- Then, go to the Certificates & Secrets blade.
- Open the Certificates tab.
- Click on Upload certificate.
- Select the .cer file we generated with the PowerShell script above. You may also optionally enter a description to explain what the certificate is for.
Utilizing a variable group
The complete CI/CD implementation presented in this blog article will consist of two YAML pipelines: one for the actual SPFx solution (the web part or extension) and one for the library component. Because both pipelines share many of the same configuration values, we should specify them in a variable group accessible by both pipelines instead of duplicating the values. This makes maintaining the configurations much more effortless.
You can create a new variable group by clicking Library under Pipelines in the same Azure DevOps project where your code resides. Name the group shared-variables, and add the following variables to it. Mark the certificatePassword as a secret so the value can’t be seen after saving.
Name | Value | Secret |
---|---|---|
appCatalogScope | tenant or sitecollection depending on whether you want to upload the package to the tenant app catalog or a site collection app catalog. | |
appCatalogSiteUrl | The URL of the app catalog site (e.g., https://yourtenant.sharepoint.com/sites/apps) | |
certificatePassword | The same password you used when creating the self-signed certificate. | ✓ |
CLIMICROSOFT365_AADAPPID | The app/client ID (GUID) of the application registration you created earlier. | |
CLIMICROSOFT365_TENANT | The directory/tenant ID (GUID) of your organization’s Azure AD. | |
libraryPackageName | The name of the library package. You can check the name from the top of the package.json file of the library component (e.g., my-library). | |
libraryRepositoryBranchName | The name of the branch from which you want to use the library component code when building the solution (e.g., main) | |
libraryRepositoryName | The name of the repository where the library component code is located. | |
nodeVersionNumber | Specify a Node version compatible with the SPFx version you’ve used in your SPFx solution and library as a whole number (e.g., 16). You can check the SPFx version from the package.json file of your solution and then check the latest compatible Node version from the SPFx development environment compatibility chart. | |
pfxCertificateFileName | The name of the .pfx certificate file you uploaded to the secure files, including the file extension. |
After saving the variable group, you need to specify which pipelines have permissions to the group. Ideally, you’ll later narrow the access only to the two pipelines we are about to create, but for now (as the pipelines do not exist yet), you can specify open access, which allows all pipelines in the project to access the group.
Explanation of the pipeline actions
If you’ve never created an Azure DevOps pipeline before, that happens by navigating to the project where your code is located and opening Pipelines in the left-hand navigation. There, you can create a new pipeline for the repository containing the code you wish to package and deploy. The initial pipeline configuration template doesn’t matter; we’ll specify all the steps anyway. Hence, make sure to delete any automatically inserted markup from the file.
As the first thing, we need to specify when the pipeline will get triggered. In my case, I want to start it whenever something changes in the main branch of the solution repository that justifies a new deployment (such as code or configuration changes). Simultaneously, I want to avoid the pipeline from triggering unnecessarily if I only modify a markdown file, such as the README, or make edits to the YAML pipeline definitions — like we are doing now. In those cases, there is no point in building and packaging the code all over again. Unfortunately, variables can’t be used for specifying these configuration values; they must be hardcoded.
Next, we want to introduce the variable group we created before to our pipeline. If you followed my earlier instructions to the t, your variable group should also be called shared-variables; hence, no further actions are required. Otherwise, you need to update the group name to match the name you chose earlier. This value must also be hardcoded (can’t come from pipeline variables).
Because our SPFx library component source code is stored in a separate repository from our SPFx solution, we need to check out two branches during our pipeline: the current branch (main) of the SPFx solution repository and a branch of the library component repository. For checking out the library component, we need to specify the Azure DevOps project name, the library repository name, and the branch that contains the code version we wish to build.
System.TeamProject refers to the same project where we are currently running the pipeline. If your library component is located in another Azure DevOps project, specify the project name in a custom variable.
Before executing any build-related tasks, we must install Node.js on the virtual machine Azure DevOps has spun up for performing our pipeline tasks. You should have already specified a Node version compatible with the SPFx version used by your solution in the variable group we created earlier.
After installing Node, we can start building the code. First, we want to install the dependencies the library component utilizes and then build a non-minified version of the code. At this point, we must build a non-minified version of the code because if the library component code is minified before the solution code, the solution will not run after deployment, even if it were to build successfully. We will minify and package the library component code after we have successfully packaged the solution code.
Because we have checked out two repositories, we need to specify the working directory to match the solution we are building. A similar definition will be present for most of the tasks in the pipeline.
After building the library component code, we’ll expose the built code for the SPFx solution by creating a symbolic link.
The SPFx solution can then consume the library component by referencing it via the symbolic link.
When the solution is successfully linked to the library component, we can start building and packaging its code. As the first thing, we need to install the dependencies from the npm registry.
And then, with the ship flag, we can bundle a minified version of the code that is ready for production.
After successfully bundling the code, we’ll package it.
Then, we’ll use a script to figure out the name of the created package file. We’ll need the package file name for later steps, so we’ll store it in a variable.
We have successfully built and packaged our SPFx solution into a .sppkg file ready for deployment! We’ll do the deployment with the help of the Microsoft 365 CLI, which we first need to install.
Then, we need to download our .pfx certificate file from the Azure DevOps project secure files section.
Now, we can use the certificate to authenticate to SharePoint Online. The tenant ID and the client ID of the application registration that we specified in the variable group are used automatically, even though they are not visible as command parameters.
Now that we have successfully authenticated, we can upload the package to the SharePoint application catalog.
And finally, after a successful file upload, we can tell SharePoint to deploy the solution.
Tada! You should now see your solution package deployed in the SharePoint app catalog.
Of course, you still need to deploy the library component for the SPFx solution to work in your tenant. The approach is similar but more straightforward, as we only need to check out and build code from a single repository. You can find the complete markup for both pipelines in the next section, ready for copy-pasting.
TLDR: The complete pipelines
As long as you’ve configured the self-signed certificate, the application registration, and the variable group as instructed at the beginning of this blog article, these pipelines should work as is.
The SPFx solution pipeline
The SPFx library component pipeline
Afterword
If you want to take the pipeline implementation a step further, consider moving the identical tasks from both pipelines into a separate YAML template and referencing that in the “trigger” pipelines. I decided against using the approach in this blog post to keep the initial setup process relatively simple to follow. However, code duplication is always a bad practice, so using a template file for the shared tasks is recommended.
I hope you enjoyed reading this blog post and found it helpful. If you did, why not share it with your friends and colleagues so they can also build these kinds of pipelines for their projects?
You may also be interested in following me on social media, where I’ll announce all my new blog posts and other notable things that are going on. You can find links to all of my social media profiles on the sidebar (or at the bottom on mobile).
Other than that, have fun while coding, and until next time!
Laura
Love the content! Got a question about maintaining version numbers across pipeline builds without having to manually edit the package-solution.json or package.json files. I have modified the gulp.js file to include versioning and it works great. The only problem is that the it updates those files on the server during the build pipeline, but it does not update the files in our devops repo. So every time we build in the pipeline, its using the version numbers from the incoming package.json and package-solution.json files which have not be changed since the previous build. Thoughts?
Hi Jerry,
You need to commit the package.json and package-solution.json files to the repository during the pipeline run for the version numbers to update in the repo.
Laura
Thanks a lot Laura,
Really good article valuable content about building pipelines for SPFX solutions.
But I wonder how have you solved the issue where some special lists and fields and configuration has to be in place for a site before deploying SPFX solution on top of it?
I mean when SPFX solution depends on some lists, fields and other configuration on site?
How would you solve it through pipelines?
Mihkel
Hi Mihkel,
You can, for example, use the M365 CLI, which we already use in the pipeline for deployment, to create and configure lists on SharePoint during the pipeline run (if they do not exist).
Create a list: https://pnp.github.io/cli-microsoft365/cmd/spo/list/list-add/
Create a field: https://pnp.github.io/cli-microsoft365/cmd/spo/field/field-add
Laura