Trouble with webpack bundle size and loading performance

Hey,

I’m having some trouble with my vendor bundle size, but I’m also not sure how to go about trouble shooting it.

There’s one bundle that ends up in dist/static/js/vendors.[hash].chunk.js and its 15mb, and this is a blocking resource on every page (ends up being about 3mb gziped). To be fair I do have a lot of dependencies but there’s two things that I’m confused about.

  1. When I look in the file itself it doesn’t appear to be minified/uglified?
  2. The bundle size doesn’t change no matter what I do in src/Routes.js, I’ve tried commenting out ever route except for the home page (and I know that most of my heavy dependencies are used on other pages) and the bundle size is still 15mb. I thought that bundles were done per page? Docs - Redwood Router : RedwoodJS Docs or is this different because this is the vendor dependencies and they all go into single chunk?

— extra context —

repo is here: GitHub - Irev-Dev/cadhub: Let's make CodeCAD a thing.
website http://cadhub.xyz/

If it’s helpful this is the verbose output of the build yarn rw build web -v

                                                   Asset       Size  Chunks                                Chunk Names
                                           README.md    1.9 KiB          [emitted]                     
                                          Three.d.ts   7.08 KiB          [emitted]                     
               c407216d1e6fd1582f373f0ef7eb4d04.wasm   33.4 MiB          [emitted]              [big]  
                                    editor.worker.js    389 KiB          [emitted]              [big]  
                                editor.worker.js.map    459 KiB          [emitted] [dev]               
                                         favicon.svg   1.94 KiB          [emitted]                     
                                   fonts/Consola.ttf   96.2 KiB          [emitted]                     
                                  fonts/Consolas.ttf    102 KiB          [emitted]                     
                                   fonts/Papyrus.ttf    160 KiB          [emitted]                     
                                    fonts/Roboto.ttf    167 KiB          [emitted]                     
                                          index.html   1.58 KiB          [emitted]                     
                   js/StandardLibraryIntellisense.ts   16.4 KiB          [emitted]                     
                                       manifest.json   4.65 KiB          [emitted]                     
                                    opencascade.d.ts   74.2 KiB          [emitted]                     
                                          robots.txt   24 bytes          [emitted]                     
                         static/css/app.c22761c4.css   1.74 MiB       1  [emitted] [immutable]  [big]  app
                     static/css/app.c22761c4.css.map    551 KiB       1  [emitted] [dev]               app
                     static/css/vendors.ced82f68.css    112 KiB       0  [emitted] [immutable]         vendors
                 static/css/vendors.ced82f68.css.map   33.6 KiB       0  [emitted] [dev]               vendors
                      static/js/10.3b1a8cee.chunk.js   8.07 KiB      10  [emitted] [immutable]         
                  static/js/10.3b1a8cee.chunk.js.map   7.99 KiB      10  [emitted] [dev]               
                      static/js/11.4325e2d2.chunk.js   2.01 KiB      11  [emitted] [immutable]         
                  static/js/11.4325e2d2.chunk.js.map  881 bytes      11  [emitted] [dev]               
                      static/js/12.55b46f3f.chunk.js    116 KiB      12  [emitted] [immutable]         
                  static/js/12.55b46f3f.chunk.js.map    117 KiB      12  [emitted] [dev]               
                      static/js/13.e78bb7ff.chunk.js   2.05 KiB      13  [emitted] [immutable]         
                  static/js/13.e78bb7ff.chunk.js.map  969 bytes      13  [emitted] [dev]               
                      static/js/14.bb1ec65b.chunk.js      3 KiB      14  [emitted] [immutable]         
                  static/js/14.bb1ec65b.chunk.js.map   1.56 KiB      14  [emitted] [dev]               
                      static/js/15.35b39d63.chunk.js   3.02 KiB      15  [emitted] [immutable]         
                  static/js/15.35b39d63.chunk.js.map   2.07 KiB      15  [emitted] [dev]               
                      static/js/16.b278d054.chunk.js   2.44 KiB      16  [emitted] [immutable]         
                  static/js/16.b278d054.chunk.js.map   1.16 KiB      16  [emitted] [dev]               
                      static/js/17.8d0f39a4.chunk.js   10.7 KiB      17  [emitted] [immutable]         
                  static/js/17.8d0f39a4.chunk.js.map   9.24 KiB      17  [emitted] [dev]               
                      static/js/18.7ea38187.chunk.js   7.71 KiB      18  [emitted] [immutable]         
                  static/js/18.7ea38187.chunk.js.map   7.46 KiB      18  [emitted] [dev]               
                      static/js/19.2f3c7716.chunk.js    7.8 KiB      19  [emitted] [immutable]         
                  static/js/19.2f3c7716.chunk.js.map   6.76 KiB      19  [emitted] [dev]               
                      static/js/20.1777951d.chunk.js   5.58 KiB      20  [emitted] [immutable]         
                  static/js/20.1777951d.chunk.js.map   4.16 KiB      20  [emitted] [dev]               
                      static/js/21.d57edd2b.chunk.js   1.96 KiB      21  [emitted] [immutable]         
                  static/js/21.d57edd2b.chunk.js.map  836 bytes      21  [emitted] [dev]               
                      static/js/22.8c5e2d65.chunk.js    6.5 KiB      22  [emitted] [immutable]         
                  static/js/22.8c5e2d65.chunk.js.map   6.88 KiB      22  [emitted] [dev]               
                       static/js/3.07934e2c.chunk.js    130 KiB       3  [emitted] [immutable]         
                   static/js/3.07934e2c.chunk.js.map    196 KiB       3  [emitted] [dev]               
                       static/js/4.bc588ef6.chunk.js   5.03 KiB       4  [emitted] [immutable]         
                   static/js/4.bc588ef6.chunk.js.map   3.51 KiB       4  [emitted] [dev]               
                       static/js/5.14eff022.chunk.js   7.89 KiB       5  [emitted] [immutable]         
                   static/js/5.14eff022.chunk.js.map   8.93 KiB       5  [emitted] [dev]               
                       static/js/6.e4df6c86.chunk.js   11.4 KiB       6  [emitted] [immutable]         
                   static/js/6.e4df6c86.chunk.js.map   10.3 KiB       6  [emitted] [dev]               
                       static/js/7.a1db5c03.chunk.js   2.75 KiB       7  [emitted] [immutable]         
                   static/js/7.a1db5c03.chunk.js.map   1.44 KiB       7  [emitted] [dev]               
                       static/js/8.409b9ee1.chunk.js   2.05 KiB       8  [emitted] [immutable]         
                   static/js/8.409b9ee1.chunk.js.map  883 bytes       8  [emitted] [dev]               
                       static/js/9.6002be3f.chunk.js    2.5 KiB       9  [emitted] [immutable]         
                   static/js/9.6002be3f.chunk.js.map   1.22 KiB       9  [emitted] [dev]               
static/js/CascadeStudioMainWorker.fe556f0c.worker.js   2.76 MiB          [emitted] [immutable]  [big]  
static/js/CascadeStudioMainWorker.fe556f0c.worker.js.map   3.17 MiB          [emitted] [dev]               
                     static/js/app.1e177a2f.chunk.js   16.5 KiB       1  [emitted] [immutable]         app
                 static/js/app.1e177a2f.chunk.js.map   9.23 KiB       1  [emitted] [dev]               app
                   static/js/runtime-app.573a2c13.js   10.5 KiB       2  [emitted] [immutable]         runtime-app
               static/js/runtime-app.573a2c13.js.map   10.7 KiB       2  [emitted] [dev]               runtime-app
                 static/js/vendors.8eb29223.chunk.js   14.2 MiB       0  [emitted] [immutable]  [big]  vendors
             static/js/vendors.8eb29223.chunk.js.map   15.6 MiB       0  [emitted] [dev]               vendors
                   static/media/codicon.a609dc0f.ttf   55.2 KiB          [emitted]                     
                      textures/dullFrontLitMetal.png    161 KiB          [emitted]                     
                                        ts.worker.js   8.91 MiB          [emitted]              [big]  
                                    ts.worker.js.map   9.99 MiB          [emitted] [dev]           

I made a couple changes to my webpack config, as well.

const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin')

module.exports = (config, { env }) => {
  config.plugins.forEach((plugin) => {
    if (plugin.constructor.name === 'HtmlWebpackPlugin') {
      plugin.options.favicon = './src/favicon.svg'
    } else if (plugin.constructor.name === 'CopyPlugin') {
      plugin.patterns.push({
        from: './src/cascade/js/StandardLibraryIntellisense.ts',
        to: 'js/StandardLibraryIntellisense.ts',
      })
      plugin.patterns.push({
        from: './src/cascade/static_node_modules/opencascade.js/dist/oc.d.ts',
        to: 'opencascade.d.ts',
      })
      plugin.patterns.push({
        from: '../node_modules/three/src/Three.d.ts',
        to: 'Three.d.ts',
      })
      plugin.patterns.push({
        from: './src/cascade/fonts',
        to: 'fonts',
      })
      plugin.patterns.push({
        from: './src/cascade/textures',
        to: 'textures',
      })
    }
  })
  config.plugins.push(new MonacoWebpackPlugin())
  config.module.rules[0].oneOf.push({
    test: /opencascade\.wasm\.wasm$/,
    type: 'javascript/auto',
    loader: 'file-loader',
  })
  config.node = {
    fs: 'empty',
  }

  return config
}

One thing you can try, to debug this further, is use the webpack bundle analyzer, which you can run by running yarn rw build --stats

Thanks @Tobbe,

I had already had a look at that, and I can see the main culprits, I guess what I’m a bit lost on is how to actually effect the size of this bundle and start breaking it up. As I mentioned from what I read in the docs I thought that redwood apps were by default code-split per page, but commenting out routes didn’t change this bundle at all. I’ve also tried lazy the bigger modules with cost modulePromise = import('cool-module') but this hasn’t change the bundle either, I can still see these modules in that chunk.

I guess I need to configure webpack to code-split when using the import function?

Sorry dude, that’s all I’ve got :frowning:

Hopefully someone else can jump in here with more knowledge in the area. @danny might be able to help.

1 Like

Hey @Irev-Dev,

Yeah 15MB does look like a lot!

I’ve dealt with a similar problem on my redwood app, and only thing I can suggest is using this library, for example, to load the heavy libraries you’re loading dynamically react-loadable - npm

It does take a little bit of tweaking to get working, but the best way to verify is to use yarn rw build --stats to check if the modules you’re making dynamic are being skipped from vendor.bundle.js.

Hope this gives you a decent starting point!

Danny

Thanks for the input Danny, I’ll have a go at that soon.

1 Like

Hey Irev,

My guess would be that the bundles are split according to the route: so all the code and dependencies are separated.

But, maybe based off what you’re saying we’re actually not doing that and instead just sticking all the node_modules into a single file called vendors.

Would you open up a PR so that we can investigate this further?

I’ve created this issue: Improve vendor chunk splits along routes · Issue #2071 · redwoodjs/redwood · GitHub

1 Like