Decrease Size of @sitecore-jss/sitecore-jss NPM Package by a Factor of Four
Modern web development frameworks take away a lot of pain related to optimization. You don’t need to worry about the concatenation of modules, modification, qualification, and splitting your JavaScript into chunks. You don't need put the first chunk into the head
tag anymore. Second chunk, right under the opening body
, and the last one before the closing body
. In the case of Next.js (and other similar frameworks), it happens automatically. You may not have to worry about it. Your code will be split into chunks and included on the page to ensure the best performance. But how smart modern tools are? Do they cover all cases?
Not all. I have found one case, that I would like to share with you. It is related to @sitecore-jss/sitecore-jss
NPM package. It affects a major part of Sitecore websites that are based on Next.js.
During the Next.js build, webpack
creates 3 separate JS bundles: client, node.js, and edge. Each bundle is responsible for code that is executed in a different runtime. Node.js is executed in the context of a serverless function hosting. Edge is executed in the context of an edge function. (Both node.js and edge are executed in the context of the Node.js process if you host it as a container or web application). We are interested most in the client bundle. This JavaScript bundle is transferred to the browser, parsed on the client side, and then executed.
Let’s take Styleguide Next.js Sitecore website(npx create-sitecore-jss
) and analyze the bundle. You can learn how to do it by reading my previous article in this series. You will just need to add a few lines of code.
We will get this fascinating graph.
We can make a lot of different conclusions, but let’s focus on @sitecore-jss/sitecore-jss
part. This part will be present in all Sitecore JSS Next.js websites.
Let’s analyze it. We can see that only a small part of the package is the package code (in green). The main part of the package is dependencies: graphql
in red, axios
in orange, graphql-request
in yellow. (There are also other suspicious parts in purple, but let’s ignore them for now as they are relatively small)
We can make the same analysis using the Bundlephobia service. It shows the same picture.
Now, we can confirm that the major part of sitecore-jss
library consists from other packages: graphql
, graphql-request
and axios
. Let’s think about when code from these packages is called.
All these packages are designed for communication between web services. Sitecore JSS makes requests to Sitecore to retrieve presentation, data, and dictionary for pages. It happens in the context of getStaticProps
and getStaticPaths
in the case of the default Next.js Sitecore setup. Both these methods are called in the server context. However, these NPM modules are present in the client-side bundle. That is wrong, we don’t need them here.
The important addition: some sites can make requests using graphql
and axios
libraries from the browser. If it is your case then everything is fine with your website. And you may skip the final part. You don’t need this optimization as it will break your website. But from my experience, it is a rare case. I haven’t seen any Sitecore Next.js websites that make GraphQL requests directly to Sitecore as it exposes the secret key.
Now, we know that we need to get rid of some modules on the client side. But, that is not easy as they are baked into another library @sitecore-jss/sitecore-jss
. We can build our sitecore-jss
module as it is open source, but that is quite time-consuming. Also, we will need to support it with each sitecore-jss
upgrade.
The easy way will be using webpack
alias configuration. We may create empty JavaScript file src/fake.js
with the following content:
export default {
};
and map existing packages to these files for client bundle build. We need to modify the next.config.js
file. We need to add the following code to the webpack
configuration:
const path = require('path');
...
webpack: (config, { isServer, webpack }) => {
if (!isServer) { // <-- We check that webpack prepares the client side bundle
config.resolve.alias = {
...config.resolve.alias,
//We replace the original 'graphql-request' package with empty file
'graphql-request': path.resolve(__dirname, 'src/fake.js'),
'graphql': path.resolve(__dirname, 'src/fake.js'), // <-- Same for graphql
'axios': path.resolve(__dirname, 'src/fake.js'), // <-- Same for axios
};
}
return config;
}
If you don't have path
package installed then you need to install it using npm install path
.
Now we can build the new bundle and review it.
We don’t see graphql
, graphql-request
, and axios
anymore. I have tested the website, and everything still works fine. We didn’t break anything. We can measure the result of improvement for sitecore-jss
NPM package.
sitecore‑jss | graphql | axios | graphql‑request | optimized sitecore‑jss | Improvent in X times | |
---|---|---|---|---|---|---|
Stat size | 287.2 KB | 113.11 KB | 48.95 KB | 42.66 KB | 82.48 KB | 3.48 |
Parsed size | 106.31 KB | 39.44 KB | 17.49 KB | 17.35 KB | 23.03 KB | 3.32 |
Gzipped size | 28.13 KB | 10.05 KB | 6.32 KB | 4.84 KB | 6.92 KB | 4.07 |
We get improvement by a factor of 4. However, the final client-side JavaScript bundle contains other packages and code as well. We can measure the difference using Lighthouse.
Was:
Now:
We get minus 20 KB, minus about 20%, and “Reduce unused JavaScript” suggestion is improved a lot. We even see different icons, which means that we moved this measurement category from low to medium score. Yes, there is still pretty much room for improvement. But all the next steps will require more effort and will have less effect. It is up to you, where you want to stop. Making performance ideal isn’t often worth it. But making the performance good enough is worth it.
Conclusion
You should keep an eye on your website's performance because the page load speed is essential for all websites. Slow websites cause loss of customers. Analyze your bundle and improve it, when you think it is worth it. If you have a Sitecore JSS Next.js website, then you can apply the recipe from this article. It will require a few hours of work but it will give you a measurable improvement. Or you can wait for Sitecore to make this improvement. They are aware of it.