webpack-contrib / webpack-bundle-analyzer

Webpack plugin and CLI utility that represents bundle content as convenient interactive zoomable treemap
MIT License
12.58k stars 488 forks source link

Feature Request: Analyze gzipped bundles #377

Closed RedVelocity closed 1 year ago

RedVelocity commented 4 years ago

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

valscion commented 4 years ago

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 ☺️

RedVelocity commented 4 years ago

@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,
valscion commented 4 years ago

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.

xitter commented 4 years ago

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

RedVelocity commented 4 years ago

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

valscion commented 4 years ago

Brotli is a different feature request :)

valscion commented 4 years ago

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

xitter commented 4 years ago

@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 commented 4 years ago

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

grug commented 2 years ago

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.

valscion commented 2 years ago

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

grug commented 2 years ago

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.