webpack-bundle-analyzer icon indicating copy to clipboard operation
webpack-bundle-analyzer copied to clipboard

Feature Request: Analyze gzipped bundles

Open RedVelocity opened this issue 4 years ago • 12 comments

Issue description

webpack-bundle-analyzer currently displays a blank page when a webpack build uses compression-webpack-plugin to compress bundles.

Technical info

Using the following workaround. This skips compression when webpack build command is used with 'analyze' environment variable.

module.exports = ({ env, analyze }) => {
  switch (env) {
    case 'development':
      return merge(commonConfig, developmentConfig);
    case 'production':
      if (analyze) commonConfig.plugins.push(new BundleAnalyzerPlugin());
      else
        productionConfig.plugins.push(
          new CompressionPlugin({
            filename: '[path].gz',
            algorithm: 'gzip',
            test: /\.(js|jsx|css|html|png|svg|jpg|gif)$/,
            threshold: 10240,
            minRatio: 0.8,
            deleteOriginalAssets: true,
          })
        );
      return merge(commonConfig, productionConfig);
    default:
      throw new Error('No matching configuration was found!');
  }
};
  System:
    OS: Windows 10 10.0.18363
    CPU: (8) x64 Intel(R) Core(TM) i5-8265U CPU @ 1.60GHz
    Memory: 8.06 GB / 15.81 GB
  Binaries:
    Node: 12.18.1 - ~\Apps\Node\node.EXE
    npm: 6.14.5 - ~\Apps\Node\npm.CMD
  npmPackages:
    clean-webpack-plugin: ^3.0.0 => 3.0.0 
    compression-webpack-plugin: ^4.0.1 => 4.0.1 
    html-webpack-plugin: ^4.3.0 => 4.3.0 
    optimize-css-assets-webpack-plugin: ^5.0.3 => 5.0.3 
    webpack: ^4.44.1 => 4.44.1 
    webpack-bundle-analyzer: ^3.8.0 => 3.8.0 
    webpack-cli: ^3.3.12 => 3.3.12 
    webpack-dev-server: ^3.11.0 => 3.11.0 
    webpack-merge: ^5.1.1 => 5.1.1 

Debug info

How do you use this module? As CLI utility or as plugin? -Both

If CLI, what command was used? (e.g. webpack-bundle-analyzer -O path/to/stats.json)

If plugin, what options were provided? (e.g. new BundleAnalyzerPlugin({ analyzerMode: 'disabled', generateStatsFile: true })) new BundleAnalyzerPlugin()

What other Webpack plugins were used? clean-webpack-plugin: ^3.0.0 => 3.0.0 compression-webpack-plugin: ^4.0.1 => 4.0.1 html-webpack-plugin: ^4.3.0 => 4.3.0 optimize-css-assets-webpack-plugin: ^5.0.3 => 5.0.3 webpack: ^4.44.1 => 4.44.1 webpack-bundle-analyzer: ^3.8.0 => 3.8.0 webpack-cli: ^3.3.12 => 3.3.12 webpack-dev-server: ^3.11.0 => 3.11.0 webpack-merge: ^5.1.1 => 5.1.1

RedVelocity avatar Aug 27 '20 06:08 RedVelocity

Thank you for opening this separate issue, it is now much clearer what is being asked! :relaxed:

If we'd want to support this, it might be enough to spot that file ends in .js.gz and then change this code:

https://github.com/webpack-contrib/webpack-bundle-analyzer/blob/b618f652db9f0870dcf92c15a7b7cd95f496bd94/src/parseUtils.js#L10-L11

to decompress the .js.gz file to plain JS file before continuing. A PR with a test case demonstrating that such a feature works would be nice ☺️

valscion avatar Aug 27 '20 06:08 valscion

@valscion, I'd like to help but I'm not sure if my local fork is setup right because nothing I change(console logs, file writes) seem to reflect in the webpack build.

Steps:

  1. Fork main branch
  2. Install dependencies
  3. run npm start
  4. Goto test project and run npm link
  5. Build with webpack,

RedVelocity avatar Aug 27 '20 08:08 RedVelocity

Hmm, I'm hazy on how npm link works. The instructions in https://github.com/webpack-contrib/webpack-bundle-analyzer/blob/master/CONTRIBUTING.md should work but I haven't verified them in a while — let me know if there's something that does not work.

valscion avatar Aug 27 '20 10:08 valscion

I played around with this and was able to get content from the compressed file by doing:

content = zlib.unzipSync(fs.readFileSync(bundlePath)).toString();

Config which I kept was:

    output: {
        path: path.resolve('build'),
        filename: '[name].js',
    },
    plugins: [
        new BundleAnalyzerPlugin(),
        new CompressionPlugin({
            filename: '[path].gz',
            algorithm: 'gzip',
            test: /\.(js|jsx|css|html|png|svg|jpg|gif)$/,
            threshold: 10240,
            minRatio: 0.8,
            deleteOriginalAssets: true,
        }),
    ],

However, there is still a blank page for the above config. Reason being that when stats.toJSON() call tries to map chunks at stats/DefaultStatsFactoryPlugin.js#L260, it sees that compilation.chunks have filename as test.js, while the compilation.asset has filename as test.js.gz, and thus it thinks that chunks aren't available for test.js.gz asset. Due to which this plugin isn't able to map modules to any chunks.

But, there is a way to fix this by keeping output filename and compressed filename same, like:

    output: {
        path: path.resolve('build'),
        filename: '[name].js.gz',  // changed
    },
    plugins: [
        new BundleAnalyzerPlugin(),
        new CompressionPlugin({
            filename: '[path]',     // changed
            algorithm: 'gzip',
            test: /\.(js|jsx|css|html|png|svg|jpg|gif)$/,
            threshold: 10240,
            minRatio: 0.8,
            deleteOriginalAssets: true,
        }),
    ],

This way webpack can map the chunks to compressed file and so can BundlerAnalyzer. And all stats are generated correctly.

@valscion let me know if it makes sense, I can raise a PR for this.

PS: There is an issue logged for this in compression-plugin https://github.com/webpack-contrib/compression-webpack-plugin/issues/49

xitter avatar Aug 28 '20 06:08 xitter

@xitter, great stuff! were you able to test it out with Brotli compression as well or that would be a different feature request?

RedVelocity avatar Aug 28 '20 07:08 RedVelocity

Brotli is a different feature request :)

valscion avatar Aug 28 '20 07:08 valscion

Sorry, don't have time to reply thoroughly to your comment yet, @xitter — sounds like you have made some progress and a PR could be useful

valscion avatar Aug 28 '20 07:08 valscion

@RedVelocity @valscion Brotli also worked well as zlib supports it, PR on the way.

Config for brotli:

new CompressionPlugin({
  filename: '[path].br',
  algorithm: 'brotliCompress',
  test: /\.(js|jsx|css|html|png|svg|jpg|gif)$/,
  compressionOptions: {
     // zlib’s `level` option matches Brotli’s `BROTLI_PARAM_QUALITY` option.
     level: 11,
  },
  threshold: 10240,
  minRatio: 0.8,
  deleteOriginalAssets: true,
});

xitter avatar Aug 28 '20 07:08 xitter

Made a PR(https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/379), please have a look.

xitter avatar Aug 31 '20 15:08 xitter

Was there ever a resolution to this? I'm currently in a situation where we use compression-webpack-plugin for our builds and this is causing blank pages for the bundle analyzer.

grug avatar Sep 14 '22 14:09 grug

Looks like #379 PR is open but the review by @th0r seems to be incomplete

valscion avatar Sep 15 '22 06:09 valscion

For the time being I've just had to run a separate build and pass in a "isStatsBuild" parameter to webpack to omit the compression. It works - not ideal, though.

grug avatar Sep 15 '22 08:09 grug