getsentry / sentry-javascript

Official Sentry SDKs for JavaScript
https://sentry.io
MIT License
7.95k stars 1.57k forks source link

Bug: Bundling with webpack produces to big bundle #1238

Closed pke closed 6 years ago

pke commented 6 years ago

Bundling the raven-js lib 3.22.3 using webpack and using it like this:

import { install } from "sentry"

install(...)

produces the following bundle:

image

Compared to the minimized file dist/raven.min.js that is 28kib the size in my bundled version seems to be to big.

Also look at the treemap:

image

This seems to be a bug how the ES6 modules are bundled.

kamilogorek commented 6 years ago

Can you provide your webpack config so I can recreate this locally?

pke commented 6 years ago

Thanks for the swift response. I'll create a reduced version of my webpack config for tests.

kamilogorek commented 6 years ago

Spring cleaning: Closing due to inactivity

davidfurlong commented 6 years ago

I'm getting the same thing. Why is raven-js/src in my webpack prod bundle???

kamilogorek commented 6 years ago

@davidfurlong same question:

Can you provide your webpack config so I can recreate this locally?

davidfurlong commented 6 years ago

Cheers, hope this helps track down the issue!

// client.prod.js
process.traceDeprecation = true;

const webpack = require('webpack');
const path = require('path');
const autoprefixer = require('autoprefixer');

// Webpack plugins
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const WriteFilePlugin = require('write-file-webpack-plugin');
const ExtractCssChunks = require('extract-css-chunks-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
  .BundleAnalyzerPlugin;

const configuration = {
  name: 'client',
  target: 'web',
  devtool: 'source-map',
  output: {
    filename: '[name].[chunkhash].js',
    chunkFilename: '[name].[chunkhash].js',
    path: path.resolve(__dirname, '../build'),
    publicPath: '/',
  },
  entry: [
    'babel-polyfill',
    'bootstrap-loader',
    path.resolve(__dirname, '../src/clientRender.js'),
  ],
  resolve: {
    extensions: ['.json', '.js', '.jsx', '.css'],
    alias: {
      handlebars: path.resolve(__dirname, '..', 'handlebars', 'runtime.js'),
      components: path.resolve(__dirname, '..', 'src/components/'),
      reducks: path.resolve(__dirname, '..', 'src/reducks/'),
      shared: path.resolve(__dirname, '../../api/shared/'),
      containers: path.resolve(__dirname, '..', 'src/containers/'),
      consts$: path.resolve(__dirname, '..', 'src', 'consts', 'index.js'),
      features: path.resolve(__dirname, '..', 'src/features/'),
      helpers: path.resolve(__dirname, '..', 'src/helpers/'),
      react: path.resolve(__dirname, '..', 'node_modules', 'react'),
      '@fortawesome/fontawesome-pro-solid$':
        '@fortawesome/fontawesome-pro-solid/shakable.es.js',
      '@fortawesome/fontawesome-pro-light$':
        '@fortawesome/fontawesome-pro-light/shakable.es.js',
      '@fortawesome/fontawesome-free-brands$':
        '@fortawesome/fontawesome-free-brands/shakable.es.js',
      '@fortawesome/fontawesome-pro-regular$':
        '@fortawesome/fontawesome-pro-regular/shakable.es.js',
      'react/addons': path.resolve(
        __dirname,
        '..',
        'node_modules',
        'react',
        'addons'
      ),
      moment: path.resolve(__dirname, '..', 'node_modules', 'moment'),
      'moment-timezone': path.resolve(
        __dirname,
        '..',
        'node_modules',
        'moment-timezone'
      ),
      'react-dom': path.resolve(__dirname, '..', 'node_modules', 'react-dom'),
    },
  },
  resolveLoader: {
    alias: {
      hbs: 'handlebars-loader',
    },
  },
  module: {
    noParse: /node_modules\/quill\/dist/,
    rules: [
      {
        test: /bootstrap-sass[/\\]assets[/\\]javascripts[/\\]/,
        loader: 'imports-loader',
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: 'babel-loader',
      },
      {
        test: /\.(jpg|png|gif|svg|ico|ttf|eot|svg|woff(2)?)(\?v=\d+\.\d+\.\d+)?$/,
        use: [
          {
            loader: 'url-loader',
          },
        ],
      },
      {
        test: /\.(webm|mp4)$/,
        exclude: /node_modules/,
        use: ['file-loader'],
      },
      {
        test: /antd.*\.css$/,
        use: ExtractCssChunks.extract({
          fallback: 'style-loader',
          use: [
            'css-loader',
            {
              loader: 'postcss-loader',
              options: {
                config: {
                  path: './postcss.config.js',
                },
              },
            },
          ],
        }),
      },
      {
        test: /\.css$/,
        exclude: /antd.*\.css$/,
        use: ExtractCssChunks.extract({
          fallback: 'style-loader',
          use: [
            'css-loader',
            {
              loader: 'postcss-loader',
              options: {
                config: {
                  path: './postcss.config.js',
                },
              },
            },
          ],
        }),
      },
      {
        test: /\.scss$/,
        use: ExtractCssChunks.extract({
          use: [
            {
              loader: 'css-loader',
              options: {
                modules: true,
                localIdentName: '[name]__[local]',
              },
            },
            {
              loader: 'postcss-loader',
              options: {
                config: {
                  path: './postcss.config.js',
                },
              },
            },
            'sass-loader',
          ],
        }),
      },
      {
        test: /\.less$/,
        use: ExtractCssChunks.extract({
          use: [
            {
              loader: 'css-loader',
              options: {
                modules: true,
                localIdentName: '[name]__[local]',
              },
            },
            {
              loader: 'postcss-loader',
              options: {
                config: {
                  path: './postcss.config.js',
                },
              },
            },
            'less-loader',
          ],
        }),
      },
    ],
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify('production'),
      },
    }),
    new webpack.optimize.CommonsChunkPlugin({
      names: ['bootstrap'], // needed to put webpack bootstrap code before chunks
      filename: '[name].[chunkhash].js',
      minChunks: Infinity,
    }),
    new ExtractCssChunks(),
    new ExtractTextPlugin({
      filename: 'styles.css',
      // allChunks: true,
      disable: false,
    }),
    // Nice to haves / Optimizations
    new WriteFilePlugin(),
    new BundleAnalyzerPlugin({
      analyzerMode: 'static',
      openAnalyzer: false,
      generateStatsFile: true,
    }),
    new LodashModuleReplacementPlugin({
      shorthands: true,
      collections: true,
    }),
    new webpack.LoaderOptionsPlugin({
      minimize: true,
      debug: false,
      options: {
        postcss: [
          autoprefixer({
            browsers: ['last 3 version', 'ie >= 10'],
          }),
        ],
      },
    }),
    new webpack.optimize.UglifyJsPlugin({
      beautify: false,
      mangle: {
        screw_ie8: true,
        keep_fnames: true,
      },
      compress: {
        warnings: false,
        screw_ie8: true,
        conditionals: true,
        unused: true,
        comparisons: true,
        sequences: true,
        dead_code: true,
        evaluate: true,
        if_return: true,
        join_vars: true,
      },
      comments: false,
    }),
    new webpack.IgnorePlugin(/glyphicon.*/),
    new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /en|de|nl/), // LOCALIZATION
    new CompressionPlugin({
      asset: '[path].gz[query]',
      algorithm: 'gzip',
      test: /\.js$|\.css$|\.html$|\.eot?.+$|\.ttf?.+$|\.woff?.+$|\.svg?.+$/,
      threshold: 10240,
      minRatio: 0.8,
    }),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production'),
      'process.env.BABEL_ENV': JSON.stringify('es6'),
    }),
  ],
};

module.exports = configuration;
// .babelrc
{
  "presets": [
    ["env", {
      "modules": false,
      "targets": {
        "uglify": true,
        "browsers": ["last 2 versions", "ie >= 10"]
      }
    }],
    "react",
    "stage-0",
    "jest"
  ],
  "compact": "true",
  "env": {
    "production": {
      "only": [
        "src"
      ],
      "plugins": [
        "transform-react-remove-prop-types",
        "transform-react-constant-elements",
        "transform-react-inline-elements",
        "transform-flow-strip-types"
      ]
    }
  },
  "plugins": [
    [
      "import",
      {
        "libraryName": "antd",
        "libraryDirectory": "es",
        "style": "css"
      }
    ],
    "universal-import",
    "transform-runtime",
    "transform-decorators-legacy",
    "transform-react-display-name",
    "transform-react-stateless-component-name"
  ]
}
kamilogorek commented 6 years ago

@davidfurlong wellll... it's kinda large and very project-specific 😅I won't be able to extract the main issue from this thing. I somehow need someone to provide a minimal possible config that exposes the culprit itself.

davidfurlong commented 6 years ago

Thats what I figured.. Any ideas how I may debug the issue?

On Tue, May 8, 2018 at 5:36 PM Kamil Ogórek notifications@github.com wrote:

@davidfurlong https://github.com/davidfurlong wellll... it's kinda large and very project-specific 😅I won't be able to extract the main issue from this thing. I somehow need someone to provide a minimal possible config that exposes the culprit itself.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/getsentry/raven-js/issues/1238#issuecomment-387445300, or mute the thread https://github.com/notifications/unsubscribe-auth/AAlhcDF-a858KfGJmbN_ASgNxZ82QwVCks5twbtsgaJpZM4SPBAh .

henrikbjorn commented 6 years ago

https://gist.github.com/henrikbjorn/dfc50687638f9ebfc9a212675eacaff5

Example, where the produced size after running webpack is 40kb.

lencioni commented 6 years ago

@davidfurlong We are also seeing this at Airbnb. Is there anything I can do to help reduce the size of this project?

We are importing it like this:

import Raven from 'raven-js';

And we don't have any other special config related to raven-js in our build.

https://bundlephobia.com/result?p=raven-js@3.26.4

Here's a source-map-explorer visualization of raven-js in one of our bundles:

screen shot 2018-08-17 at 9 48 26 am

And here's the output of a different analysis I ran on it (I believe these sizes are pre-minification though):

/node_modules/raven-js/src/singleton.js size: 1.94 kB, treeSize: 122 kB, importCount: 2, savedByRemoving: 122 kB
 ./node_modules/raven-js/src/raven.js size: 69.9 kB, treeSize: 120 kB, importCount: 1, savedByRemoving: 120 kB
   ./node_modules/raven-js/vendor/TraceKit/tracekit.js size: 22.2 kB, treeSize: 40.7 kB, importCount: 1, savedByRemoving: 22.2 kB
     ./node_modules/raven-js/src/utils.js size: 16.5 kB, treeSize: 18.5 kB, importCount: 3, savedByRemoving: 16.5 kB
       ./node_modules/raven-js/vendor/json-stringify-safe/stringify.js size: 2.03 kB, treeSize: 2.03 kB, importCount: 2, savedByRemoving: 2.03 kB
   ./node_modules/raven-js/src/console.js size: 1.24 kB, treeSize: 19.7 kB, importCount: 1, savedByRemoving: 1.24 kB
     ./node_modules/raven-js/src/utils.js size: 16.5 kB, treeSize: 18.5 kB, importCount: 3, savedByRemoving: 16.5 kB
   ./node_modules/raven-js/src/utils.js size: 16.5 kB, treeSize: 18.5 kB, importCount: 3, savedByRemoving: 16.5 kB
   ./node_modules/raven-js/vendor/md5/md5.js size: 7.89 kB, treeSize: 7.89 kB, importCount: 1, savedByRemoving: 7.89 kB
   ./node_modules/raven-js/vendor/json-stringify-safe/stringify.js size: 2.03 kB, treeSize: 2.03 kB, importCount: 2, savedByRemoving: 2.03 kB
   ./node_modules/raven-js/src/configError.js size: 236 B, treeSize: 236 B, importCount: 1, savedByRemoving: 236 B

It looks like most of the weight comes from raven.js itself, so that's probably where most of the attention should be given. It also looks like there might be some other potentially small wins by moving md5 to a node_module perhaps, or allowing a different hashing function to be injected in a way that would the weight of your md5 module (e.g. string-hash, which is a very small implementation of djb2).

lencioni commented 6 years ago

This also seems roughly the same size as the minified version you publish in the dist directory of the package: https://unpkg.com/raven-js@3.26.4/dist/

If you are looking for a way to debug this issue, it looks like you should be able to run your normal build and inspect the size of the output of that file.

jraoult commented 6 years ago

I guess it is related: I'm seeing the same with the new SDK: 23 KB gzipped.

screen shot 2018-09-19 at 13 22 54

kamilogorek commented 6 years ago

23kB is an accurate measurement right now. We'll start on working to reduce it once we iron out all the details of the 4.0.0

AWare commented 5 years ago

Hi, this is causing us issues adopting sentry in new projects and prevents us from updating the SDK.

image image

Excuse the large screenshots, but we're seeing an increase of about 2.6 times in transmitted size and 3.6 times in parsed size which would seriously impact our javascript budgets.

I'd like to request that this is reopened and the Needs Reproduction label is dropped.

We'd also like to thank you for continuing to support raven-js as its' smaller bundle size allows us to continue monitoring errors without impacting performance for users.

kamilogorek commented 5 years ago

@AWare we are tracking this issue here https://github.com/getsentry/sentry-javascript/issues/1552 Cheers!