Comparing Webpack Bundle Size Changes on Pull Requests as a Part of CI

We’ve had some issues where developers haven’t realized it and inadvertently increased the size of our bundles in work they have been doing. So we tried to give them more visibility of the impact of their change on the Pull Request, but using webpack stats, and publishing a compare to the PR for them.

The first part of the is getting webpack-stats-plugin into the solution and also I’ve done a custom version of webpack-compare to output mark down, and only focus on the files you have changed instead of all of them.


"webpack-compare-markdown": "dicko2/webpack-compare",
"webpack-stats-plugin": "0.1.5"

Then we add yarn commands into the package json to preform the work of generating and comparing the stats files


"analyze": "webpack --profile --json > stats.json",
"compare": "webpack-compare-markdown stats.json stats-new.json -o compare"

But what are we comparing? Here’s where it gets a bit tricky. We need to be able to compare the latest master, so what I did was, when the build config that runs the compare runs on master branch I generate a nuget package and push it up to our local server, this way I can just get latest version of this package to get the master stats file.


 

if("%teamcity.build.branch%" -eq "master")
{
md pack
copy-item stats.json pack

$nuspec = '<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<!-- Required elements-->
<id>ClientSide.WebPackStats</id>
<version>$Version$</version>
<description>Webpack stats file from master builds</description>
<authors>Dicko</authors>
</metadata>
<files>
<file src="stats.json" target="tools" />
</files>
</package>'

$nuspec >> "pack\ClientSide.WebPackStats.nuspec"
cd pack
%teamcity.tool.NuGet.CommandLine.DEFAULT%\tools\nuget.exe pack -Version %Version%
%teamcity.tool.NuGet.CommandLine.DEFAULT%\tools\nuget.exe push *.nupkg -source https://lib-mynuget.io/api/odata -apiKey "%KlondikeApiKey%"
}

If we are on a non-master branch we need to download the nuget and run the compare to generate the report.


if("%teamcity.build.branch%" -ne "master")
{
%teamcity.tool.NuGet.CommandLine.DEFAULT%\tools\nuget.exe install ClientSide.WebPackStats
$dir = (Get-ChildItem . -Directory -Filter "ClientSide.WebPackStats*").Name
move-item stats.json stats-new.json
copy-item "$dir\tools\stats.json" stats.json
yarn compare
}

Then finally we need to comment back to the github pull request with the report


&nbsp;

#======================================================
$myRepoURL = "%myRepoURL%"
$GithubToken="%GithubToken%"
#======================================================
$githubheaders = @{"Authorization"="token $GithubToken"}
$PRNumber= ("%teamcity.build.branch%").Replace("pull/","")

$PathToMD ="compare\index.MD"

if("%teamcity.build.branch%" -ne "master")
{

function GetCommentsFromaPR()
{
Param([string]$CommentsURL)

$coms=invoke-webrequest $CommentsURL -Headers $githubheaders -UseBasicParsing
$coms=$coms | ConvertFrom-Json
$rtnGetCommentsFromaPR = New-Object System.Collections.ArrayList

foreach ($comment in $coms)
{
$info1 = New-Object System.Object
$info1 | Add-Member -type NoteProperty -name ID -Value $comment.id
$info1 | Add-Member -type NoteProperty -name Created -Value $comment.created_at
$info1 | Add-Member -type NoteProperty -name Body -Value $comment.Body
$i =$rtnGetCommentsFromaPR.Add($info1)
}
return $rtnGetCommentsFromaPR;
}

$pr=invoke-webrequest "$myRepoURL/pulls/$PRNumber" -Headers $githubheaders -UseBasicParsing
$pr=$pr.Content | ConvertFrom-Json

$pr.comments_url
$CommentsFromaPR= GetCommentsFromaPR($pr.comments_url)
$commentId=0
foreach($comment in $CommentsFromaPR)
{
if($comment.Body.StartsWith("[Webpack Stats]"))
{
Write-Host "Found an existing comment ID " + $comment.ID
$commentId=$comment.ID
}
}
$Body = [IO.File]::ReadAllText($PathToMD) -replace "`r`n", "`n"
$Body ="[Webpack Stats] `n" + $Body
$Body

$newComment = New-Object System.Object
$newComment | Add-Member -type NoteProperty -name body -Value $Body

&nbsp;

if($commentId -eq 0)
{
Write-Host "Create a comment"
#POST /repos/:owner/:repo/issues/:number/comments
"$myRepoURL/issues/$PRNumber/comments"
invoke-webrequest "$myRepoURL/issues/$PRNumber/comments" -Headers $githubheaders -UseBasicParsing -Method POST -Body ($newComment | ConvertTo-Json)
}
else
{
Write-Host "Edit a comment"
#PATCH /repos/:owner/:repo/issues/comments/:id
"$myRepoURL/issues/$PRNumber/comments/$commentId"
invoke-webrequest "$myRepoURL/issues/comments/$commentId" -Headers $githubheaders -UseBasicParsing -Method PATCH -Body ($newComment | ConvertTo-Json)
}

}

&nbsp;

And we are done, below is what the output looks like in GitHub

WebpackBundleSizeChangeOnPullRequestBuild

Happy packing!