/* Utility to analyze bundle chunks over versions. Assumes: webpack has already created the bundle summary json file -> stats.json Parameters: version: (Optional) a string that labels the current bundle with the version provided and saves the summary in a csv file. Output: If run the first time, generates a csv file bundleAnalaysis.csv, which tracks bundle sizes by version. Adds one row with the current analysis. If run the next time, analyzes the current stats.json with the last row in bundleAnalysis.csv and prints out summary to command line. If run with version, does the same as above plus adds a row with the version in bundleAnalysis.csv. This will be used as the next baseline. Usage: In package.json, add this script: "prod-bundle-analyze": "webpack --config webpack/prod.config.js --json > stats.json && node bundleAnalyzer.js" Run script first time to create a baseline. npm run prod-bundle-analyze If you want to analyze your current code (will compare with the last baseline) npm run prod-bundle-analyze If you want to create a new baseline (use this when you have a new release) npm run prod-bundle-analyze v2.0 */ const csv = require('csvtojson'); var path = require('path'); var json2csv = require('json2csv'); const jsonBundleFilePath = 'stats.json'; var fs = require('fs'); var obj = JSON.parse(fs.readFileSync(jsonBundleFilePath, 'utf8')); var args = process.argv.slice(2); var versionName = null; if (args[0]) { versionName = args[0]; } var assetsByChunkName = obj.assetsByChunkName; var assets = obj.assets; var summarySize = {}; for (var i = 0; i < assets.length; i++) { var asset = assets[i]; if (!asset.chunkNames || asset.chunkNames.length != 1) { continue; } var chunkName = asset.chunkNames[0]; if (!assetsByChunkName[chunkName]) { continue; } var assetName = asset.name; var assetSize = asset.size; var extension = path.extname(assetName); // flat keys doesnt work of csv to json. this is sad, so have to remove the dot. summarySize[chunkName + " " + extension.substring(1)] = parseInt(assetSize)/1000.0; } const summaryFileName = 'build_tools/bundleAnalysis.csv'; const summaryFileNameBackup = 'build_tools/bundleAnalysis_backup.csv'; if (fs.existsSync(summaryFileName)) { analyzeNewBundle(summarySize); } else { writeCSVFirstTime(summarySize); } function analyzeNewBundle(summarySize) { const csvFilePath=summaryFileName; var csvString = fs.readFileSync(csvFilePath, "utf8"); var jsonObjects = []; csv({flatKeys:true}) .fromString(csvString) .on('json',(jsonObj)=>{ jsonObjects.push(jsonObj); var lastBundleSummary = jsonObjects[jsonObjects.length-1]; for (var assetName in summarySize) { if (summarySize.hasOwnProperty(assetName)) { // do stuff var oldSize = lastBundleSummary[assetName]; var newSize = summarySize[assetName]; var changeInSize = newSize - oldSize; var stringToPrint = assetName + ':' + oldSize + 'kB->' + newSize + 'kB = '; if (oldSize == 0) { stringToPrint += 'new file'; } else { stringToPrint += (changeInSize*100.0/oldSize) + '% increase'; } console.log(stringToPrint); } } }) .on('done',(error)=>{ //console.log(jsonObjects); if (versionName) { saveResultInCSV(jsonObjects, summarySize, versionName); } }) } function saveResultInCSV(oldBundleJsonObjects, summarySize, versionName) { // copy to backup fs.createReadStream(summaryFileName).pipe(fs.createWriteStream(summaryFileNameBackup)); summarySize['version'] = versionName; summarySize['date'] = (new Date()).toDateString(); oldBundleJsonObjects.push(summarySize); var fieldsDict = {}; for (var i = 0; i < oldBundleJsonObjects.length; i++) { var bundleJsonObj = oldBundleJsonObjects[i]; for (var fieldName in bundleJsonObj) { if (bundleJsonObj.hasOwnProperty(fieldName) && !fieldsDict.hasOwnProperty[fieldName]) { fieldsDict[fieldName] = true; } } } var csv = json2csv({ data: oldBundleJsonObjects, fields: Object.keys(fieldsDict)}); fs.writeFile(summaryFileName, csv, function(err) { if (err) throw err; console.log('summary file created'); }); } function writeCSVFirstTime (summarySize) { var currentTime = new Date(); var fields = ['version', 'date']; fields = fields.concat(Object.keys(summarySize)); summarySize.version = '0.0'; summarySize.date = currentTime.toDateString(); var csv = json2csv({ data: summarySize, fields: fields }); fs.writeFile(summaryFileName, csv, function(err) { if (err) throw err; console.log('file saved'); }); }