Skip to content

Instantly share code, notes, and snippets.

@chrisabrams
Forked from kanavarora/bundleAnalysis.js
Created September 23, 2017 16:01
Show Gist options
  • Save chrisabrams/cd77ee4e93fc54d243e4194e560dd706 to your computer and use it in GitHub Desktop.
Save chrisabrams/cd77ee4e93fc54d243e4194e560dd706 to your computer and use it in GitHub Desktop.

Revisions

  1. @kanavarora kanavarora renamed this gist Feb 15, 2017. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. @kanavarora kanavarora created this gist Feb 15, 2017.
    145 changes: 145 additions & 0 deletions bundleAnalysis.csv
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,145 @@
    /*
    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');
    });
    }