Monitor & Analyze Asset Sizes with Every Build
Implementing Build Budgeting with Webpack 4 and Jenkins
What is Build Budgeting?
Over the last few years, webpack has essentially become one of the most popular go-to build tools or modules for generating assets (JS, CSS, Fonts, Images etc.) powering numerous web applications on the world wide web.
Constant strides are being made to harness and build upon the capabilities of webpack and various plugins available to keep a continuous check on the performance as well as sizes of different assets generated during the build process.
Our Build Budgeting strategy for generating and analyzing the front-end builds attempts at the same and covers the following:
- Generating an assets (JS, CSS, images, webfonts etc. chunks/files) comparison report for comparing the difference in sizes of various assets generated in the current build and the previous production build.
- Restricting the maximum allowed increment limit in total size for each type of asset such as total increase in JS or CSS file sizes etc. for every subsequent build.
- Implementing warnings on the maximum size of each asset or chunk file generated to further prevent large file sizes and emphasize on splitting the bulky chunks.
- Getting an overview of total time taken by the build process along with the individual webpack plugins and loaders involved.
- Automating the complete process through a Jenkins based CI/CD front-end build pipeline, triggered on specific types of merge requests.
Various Plugins Utilized & Challenges Faced
In order to come up with a solution for budgeting, a no. of webpack plugins were explored. Some of those are described briefly below:
- size-plugin — Gives the exact byte difference in the generated assets since last build after gzip.
Cons: Only gives the sizes of the assets after gzipping.
NPM Link: https://www.npmjs.com/package/size-plugin
- speed-measure-webpack-plugin — Gives the time taken by each loader and plugin along with the complete time consumed in build process.
Pros: Effective for analyzing and reducing build times
NPM Link: https://www.npmjs.com/package/speed-measure-webpack-plugin
- webpack performance option — Helps in imposing checks on asset size (each file emitted) and bundle sizes (per entry point) & subsequently halting builds.
- webpack-bundle-analyzer — useful for visualizing the files within different chunks along with their parsed and gzipped sizes.
- bundle-stats-webpack-plugin — Generates a bundle comparison HTML report, comparing the sizes of different assets for the current and previous build.
Cons: Needs to be run manually since it stores the previous build details (baseline.json) within node_modules (which are generally gitignored).
NPM Link: https://www.npmjs.com/package/bundle-stats-webpack-plugin
Amongst the above, webpack performance option and bundle-stats-webpack-plugin were majorly utilized for our budgeting strategy with the option of manually including or excluding the speed-measure-webpack-plugin and the webpack-bundle-analyzer plugins.
Plan of Action Followed:
The whole purpose of this implementation is to generate a stats folder holding the complete information regarding the budgeting statistics after going through the budgeting process.
The various files that will be generated within the stats folder are explained below:
- baseline.json — contains asset sizes of the previous build.
- bundle-stats.html — HTML Assets (JS, CSS, images, web fonts etc.) Size Comparison Report for the current and the previous production build.
- bundle-analyzer.html — contains a graphical visualization of different chunks along with their parsed and gzipped sizes.
- bundle-stats.json — JSON containing information regarding asset sizes, chunks, modules and build related stats.
- limits-report.txt — A text file containing warnings related to asset files & entry points that have exceeded a certain threshold (Asset & Entry Point Level Restriction), difference in total size of different asset types (Build Level Restrictions) and the time taken by the loaders, plugins in the build process.
Integrating the bundle-stats-webpack-plugin
The plugin works by generating a baseline.json file (in the node_modules/.cache/bundle-stats folder), holding the previous build asset size and then compares the current build asset sizes against this baseline during the build process to generate two types of reports — bundle-stats.html & bundle-stats.json.
However, this baseline.json file gets removed whenever the code is pushed to our code repository (since node modules are gitignored).
So, the idea is to copy this file into a folder (stats/baseline.json) from the node_modules folder and copy it back to the node_modules folder before running the current build.
New scripts and changes introduced:
- Modifications/Additions to the package.json script commands:
- Addition of three new commands — ‘stats-comparison’, ‘stats-save’ and ‘stats-validateSize’ which internally execute the prepareStats.js file, explained below.
- Addition of ‘prod-budget’ command to execute the production like webpack build.
- Some modifications were done to the ‘prod’ command.
- webpack.prod-budget.js — production like webpack configuration with the addition of the plugins described above for executing the budgeting build.
- prepareStats.js — A new script file added to the build setup. It performs the following operations:
- It utilizes the bundle-stats.json file generated by the bundle-stats-webpack-plugin to impose restrictions on the total sizes of different asset types such as (JS, CSS, Webfonts and HTML etc.) for every successive build.
- It subsequently warns or terminates a build in case of size violations and appends the output to the limits-reports.txt file (on execution of npm run stats-validateSize).
- Additionally, it cleans the stats folder and copies the baseline.json file:
- To the node_modules folder (on the execution of npm run stats-comparison)
- From the node_modules (on the execution of npm run stats-save) into the stats folder, thereby automating the execution of bundle-stats-webpack-plugin by providing the baseline file for the subsequent builds.
- performance-build folder — temporary (gitignored) build folder for assets generated during the budgeting build.
Overview of the steps/process:
Here we take a quick look into the steps involved in the automation process of our budgeting strategy, exploring how the different scripts/commands introduced come into picture:
Note: During a new production release, this pipeline is not triggered. Instead, the existing static build pipeline will be triggered with the addition of the following:
- The prepareStats.js file will be executed again after the build process (during build stage) to copy the newly created baseline.json file from the node_modules folder to stats/baseline.json, since this will now serve as the new standard baseline.
- bundle-stats.html, bundle-stats.json and limits-reports.txt will be generated . However, bundle-analyzer.html & Asset Level Size Warning within limits-report.txt will not be generated.
Outcome — Budgeting Statistic Reports
Some outputs when budgeting was implemented on an existing code repository:
Impact and Utilization:
- We now have a detailed mechanism for keeping our asset sizes in check, making it easy to identify the modules being duplicated or pieces of code/files taking up the extra size.
- This essentially acts as a checkpoint and benchmark to adhere to the file and overall bundle size limits, prompting the developers to write optimized code and splitting code chunks whenever necessary.
- Insights into the time taken by different loaders and plugins during the build process further helps us in identifying and improving the plugins hampering our build process.
- Additionally, the Jenkins budgeting pipeline can be utilized by any repository with a webpack setup, making it fairly easy to extend to other frontend code bases, throughout the organisation.
Future Expansion Plans:
- Since the Jenkins pipeline can be utilized by any repository with a webpack setup by incorporating a merge request based webhook, the plan is to implement budgeting for more and more code repositories.
- Maintaining a history of budgeting reports in order to analyze the expansion in our code bases across multiple production releases, over a period of time.
- Exploring the webpack-lighthouse-plugin (in relation to our legacy architecture) for React based pages to further obtain page performance metrics.
Hit the 👏 (claps) button to make it reachable to more audience.