This is one of a multi-part series of posts answering the most common questions on the SharePoint Framework. This series, SharePoint Framework Five “W"s & One “H” answered, gives you the best high-level picture of the SharePoint Framework. I ( Andrew Connell) wrote this series in late 2020 to help people new to the SharePoint Framework get the answers to the most common and basic questions about the SharePoint Framework.
This piece to my series is going to take a different direction than the rest of the series. Other articles in the series are more high-level and look at things more from a decision-maker perspective. I wrote them for developers, development managers and tried to stay out of the technical details.
But in this post, I want to get my hands dirty and take you into the depths of the SharePoint Framework (SPFx). While this article is for you, I have to admit that it might be equally (and maybe more-so) selfishly for me.
The points I’m going to cover address questions I answer over and over. With this post, I can now point to a reference I haven’t seen elsewhere.
So, let’s get started!
SharePoint Framework at a high-level
The most important thing to know about the SPFx is that it is a 100% client-side technology. This means that it only runs in the browser. When you build solutions, they are only client-side, not server side.
With that being said, you can implement a scenario where your SPFx components call server-side components you’ve deployed, such as a REST API, but that the API project doesn’t have anything to do with your SPFx component.
As I covered in the post Who and Where can the SharePoint Framework be Used?: SharePoint page customization areas, SharePoint has specific places carved out that you can use the SPFx to customize. These include web part zones, the top & bottom placeholders, field customizers and command sets.
When a page is requested, SharePoint first creates the page source for the structure of the page before sending it to the client. Some components load asynchronously in the browser, such as parts of the suite bar.
When it comes to SPFx, SharePoint first determines if there are any SPFx components that have been added to the requested page. If so, SharePoint will load the SPFx runtime on the page. Otherwise, it doesn’t load it; as I said above, SPFx is entirely client-side and if there aren’t any components on the page, it doesn’t need add the runtime to the page response and unnecessarily bloat the payload.
So what happens when the SPFx runtime loads? Ah… now we get to the real business of this post. Let’s go low-level…
SharePoint Framework at a low-level
In the last section, I said that when SharePoint detects there are SPFx components on the requested page, it loads the runtime. But what exactly does that mean?
The SPFx runtime is just a bunch of JavaScript. When the page loads, it gets a list of all the components that should be on the page. Once it has that list, it needs to know everything about that component. Specifically, it needs to know about the component’s dependencies including the JavaScript bundle that represents that component. This information is spread across two manifest files: one contains a list of all components available in SharePoint (let’s call this the SPFx master manifest) while each component has it’s own manifest the defines it’s dependencies (this is called the SPFx component manifest).
Let’s look at this first manifest file…
Generate a list of all components - the SPFx master manifest
The SPFx master manifest contains a list of all the components that could be on the page. This is a collection of the components installed to the tenant app catalog and the current site collection’s app catalog. Think of this list as just an array of name-value pairs. Each entry is for the SPFx component ID and it points to the URL of the component’s manifest file.
Think of it like the following snippet. This is not real, but it conveys the basic concept:
[
// image web part
{
"id": "<some GUID>",
"manifest": "https://.../image-web-part.manifest.json"
},
// text web part
{
"id": "<some GUID>",
"manifest": "https://.../text-web-part.manifest.json"
},
// >>> more OOTB SPFx components...
// your custom hellow world web part
{
"id": "<some GUID>",
"manifest": "https://<your-tenant-o365-cdn>/hello-world.mainfest.json"
}
]
This manifest acts like a directory for SPFx. Once it has this list, it moves onto the next step to get the components on the page.
Load SPFx components on the page
Now that the SPFx runtime has a directory of everything that can be on the page, it then uses this list to figure out what to load. The SPFx runtime then starts working through all components that should be on the page, finds them in this directory, and uses the information it gets to load the dependencies for the component.
This is where things get interesting. Let’s take our custom web part for example.
Let’s assume our web part leverages the popular jQuery DataTables plugin. Not only will the SPFx runtime need to load the DataTables plugin library, but it also needs to load jQuery, our web part and any other SPFx components we may be using such as the @microsoft/sp-http and certainly the @microsoft/sp-webpart-base packages.
Many of the SPFx packages have already been added to your project when you ran the Yeoman SharePoint Framework Generator. Take a look in your package.json file and you’ll see these listed out for your web part:
{
"dependencies": {
"@microsoft/sp-core-library": "1.11.0",
"@microsoft/sp-lodash-subset": "1.11.0",
"@microsoft/sp-office-ui-fabric-core": "1.11.0",
"@microsoft/sp-property-pane": "1.11.0",
"@microsoft/sp-webpart-base": "1.11.0"
},
}
These are all needed by your component. But you also had additional components as well. You may have installed the jquery & DataTables plugins using the npm install command. In that case, your package.json might look like this:
{
"dependencies": {
"@microsoft/sp-core-library": "1.11.0",
"@microsoft/sp-webpart-base": "1.11.0",
"datatables": "1.10.13",
"jquery": "1.12.4",
"@microsoft/sp-lodash-subset": "1.11.0",
"@microsoft/sp-office-ui-fabric-core": "1.11.0"
},
}
But you’re a smart SPFx developer… you know that you shouldn’t be including jQuery or DataTables in your resulting component’s bundle! So you went to your project’s ./config/config.json file to add these as dependencies. This tells the SPFx bundling process to not suck these files into the resulting bundle. Instead, you want to tell SPFx to make sure it downloads the jQuery and DataTables plugin libraries in a specific order before your web part is loaded.
{
"externals": {
"jquery": {
"path": "https://code.jquery.com/jquery-1.12.4.js",
"globalName": "jQuery"
},
"datatables": {
"path": "https://cdn.datatables.net/1.10.12/js/jquery.dataTables.min.js",
"globalName": "jQuery",
"globalDependencies": [
"jquery"
]
}
}
}
The order the libraries are loaded on the page is critical! If your web part bundle loaded before jQuery or DataTables was on the page, things would break as there’s an assumption they are already on the page!
The SPFx bundling process takes this into account for you. The SPFx documentation addresses how the bundling process works but most of it only focuses on the creation of the bundle. The other thing the bundling process does is generate that SPFx component manifest.
Take a look… after you run gulp bundle, you’ll see two files in the ./dist folder. The *.js file is the bundle while the .manifest.json file is the SPFx component’s manifest. Within this file, you’ll find an object named loaderConfig:
{
"loaderConfig": {
"entryModuleId": "cswp-jquery-data-tables-web-part",
"internalModuleBaseUrls": [
"https://localhost:4321/"
],
"scriptResources": {
"cswp-jquery-data-tables-web-part": {
"type": "path",
"path": "dist/cswp-jquery-data-tables-web-part.js"
},
"datatables": {
"type": "path",
"path": "https://cdn.datatables.net/1.10.12/js/jquery.dataTables.min.js",
"globalDependencies": [
"jquery"
],
"globalName": "jQuery"
},
"jquery": {
"type": "path",
"path": "https://code.jquery.com/jquery-1.12.4.js",
"globalName": "jQuery"
},
"CswpJqueryDataTablesWebPartStrings": {
"defaultPath": "lib/webparts/cswpJqueryDataTables/loc/en-us.js",
"type": "localizedPath"
},
"@microsoft/sp-loader": {
"type": "component",
"version": "1.11.0",
"id": "1c6c9123-7aac-41f3-a376-3caea41ed83f"
},
"@microsoft/sp-core-library": {
"type": "component",
"version": "1.11.0",
"id": "7263c7d0-1d6a-45ec-8d85-d4d1d234171b"
},
"@microsoft/sp-webpart-base": {
"type": "component",
"version": "1.11.0",
"id": "974a7777-0990-4136-8fa6-95d80114c2e0"
}
}
}
}
This contains three properties:
entryModuleId
: name of the JavaScript module that contains the main SPFx componentinternalModuleBaseUrls
: the base URl where any non-absolute URLs listed in the manifest are located (in the above snippet, its pointing to localhost, but this could be your own CDN)scriptResources
: name-value collection of all libraries and components that the SPFx components needs to run
The last property, scriptResources
, is the interesting one. This contains a list sorted in reverse order of everything that must be loaded for the component to work. Notice the last few listed are components. These are SPFx runtime out-of-the-box components that should already be on the page.
Notice how the bundle that contains our SPFx web part is listed at the top? It comes after the DataTables plugin which comes after the jQuery library.
What the SPFx runtime does is use something called a module loader to handle the process of loading all the necessary libraries.
The SPFx has changed module loaders over time that it uses to load the different modules. Initially the SPFx was using the popular module loader system.js to load the modules, but in the SPFx v1.10.0 release notes from January 2020 they stated they were moving to another popular module loader: require.js.
This doesn’t really matter to you, but I mention them in case you want to go read up on how these work. While Microsoft hasn’t said it, I expect that only SharePoint Online will switch to require.js while SharePoint Server 2016 & SharePoint Server 2019 will continue to use system.js.
The module loader is smart enough to know that if a dependency has already been loaded on the page from another component’s dependency tree, it won’t download it a second time.
How are components added to the page?
Once a component’s modules (aka: JavaScript files) are loaded on the page, how is it added to the page?
When the SPFx loads the final module, it creates an instance of the object in the defined entryModuleId
and calls one of the expected methods you can define. For instance, to add add HTML to the page in a web part, you implement the render()
method.
The object your web part class is derived from, the BaseClientSideWebPart, provides a property domElement
that is a reference to the <div>
that SharePoint added to the page where your component should go based on what the user specified when it was loaded.
How does workbench & debugging impact the SPFx runtime?
Now that you understand how the SPFx runtime loads components, you might wonder how the hosted workbench and debugging extensions impacted by this.
Let’s first look at the hosted workbench.
SharePoint Framework and the hosted workbench
When you navigate to the hosted workbench, located at https://[your SharePoint site]/_layouts/workbench.aspx
, if you haven’t spun up your local development web server by running gulp serve, you get the following message:
The reason you get this is because the workbench is asking for an additional manifest file. Not only does it get the manifest file from SharePoint to list everything that’s available, but it also requests a manifest file from https://localhost:4321/temp/manifests.js
. This file contains the same manifest details that the SPFx runtime gets in the SPFx master manifest, but only the components you’re currently developing in your project are listed.
Are you ready to learn the SharePoint Framework? Check out our on-demand video course with over 30 hours of demos, explanation and downloadable code: Mastering the SharePoint Framework!
Start with the FREE Starter bundle that includes three (3) chapters including a walk-through of setting up your developer environment to start creating SharePoint Framework components.
Once you start working, jump to the Fundamentals bundle to learn the basics and start creating SharePoint Framework components. The Ultimate bundle will make you a master at the SharePoint Framework with automated testing, continuous monitoring, implement CI/CD practices, and learn other advanced techniques.
The Ultimate bundle includes the Fundamentals bundle and grants you access to our live monthly office hours meetings as well as access to our student-only mastermind group.
When you have started your local web development server using the gulp serve command, the SPFx workbench merges the collection of manifests it received from your local web server and the SPFx master manifest into one collection to present you with all the components you can load.
This works for great for testing web parts… but what about extensions?
Testing and debugging SharePoint Framework extensions
Unfortunately the SPFx hosted workbench can’t debug extensions. To debug extensions, you need a real SharePoint page. In the case of a field customizer or command set, you also need a real SharePoint list or library.
But to test a component on a real SharePoint page, you have to tell SharePoint that’s what you want to do. This is done using a specially crafted URL that includes parameters to tell SharePoint the following things:
- If it isn’t already loaded, load the SPFx runtime on the site.
- The SPFx runtime should load manifest.js file from your local development web server.
- Which component to load & anything unique about the component
Thankfully, SPFx extension projects will create this URL for you based on the values you set in the ./config/serve.json file. Take a look at the following URL… I’ve broken it up to make it more readable:
https://contoso.sharepoint.com/sites/mySite/SitePages/myPage.aspx?
debugManifestsFile=https%3A%2F%2Flocalhost%3A4321%2Ftemp%2Fmanifests.js
&loadSPFX=true
&customActions={"fca30018-46f0-4b5e-b160-e9480f3e0690"%3A
{"location"%3A"ClientSideExtension.ApplicationCustomizer"%2C"properties"%3A
{"testMessage"%3A"Test+message"}
}
}
You’ll notice a few properties in the URL:
loadSPFX=true
: this tells SharePoint to load the SPFx runtime if it isn’t already loaded on the page (which would be the case if the page you’re using to test your extension has no other SPFx component on it)debugManifestFile
: this tells the SPFx runtime where to load the manifest file fromcustomActions
: this is a JSON object, URL encoded, that contains details about the component
In the above example, you can see that we are telling the SPFx runtime to load the component fca30018-46f0-4b5e-b160-e9480f3e0690, listed in the debugManifestFile
on the page. The remaining information is specific to the component. In this case, it tells SPFx that it is an application customizer and sets it’s public properties. When it’s a field customizer, this will also contain the internal name of the field, or column, the customizer should override in testing.
You’ll notice when you use this URL, you’re presented with a warning:
This is presented by SharePoint when SPFx is asked to load a manifest file from an untrusted location, such as your local web server. Think about it… this would be a fantastic opportunity for a phishing attack to get a random script loaded in your corporate intranet! Once loaded, it will run under your context and thus have all the permissions you have!
Conclusion
My goal in this post was to answer the question How does the SharePoint Framework work? By now you should have a good grasp on how the SPFx runtime works, how components are added to the page and how to debug extensions on modern pages.
This is one of a multi-part series of posts answering the most common questions on the SharePoint Framework. This series, SharePoint Framework Five “W"s & One “H” answered, gives you the best high-level picture of the SharePoint Framework. I ( Andrew Connell) wrote this series in late 2020 to help people new to the SharePoint Framework get the answers to the most common and basic questions about the SharePoint Framework.