7

I have a multi-entry point webpack build and I am working on optimizing artifact size for production. webpack-bundle-analyzer produced the following picture:

enter image description here

It's obvious that the AtlasKit dependencies make up a huge chunk of the total artifact size. Specifically, I see that styled-components.es.js is repeated many times. More so, this same dependency is is also present in vendor.js which itself is shared among all other packages.

Can anyone explain why styled-components.es.js is repeated all over and why it cannot be shared via single dependency in vendor.js? Is there anything I can do to remove duplicates and only depend on the single styled-components.es.js dependency in vendor.js?

I found it a bit strange that AtlasKit dependencies have a nested node_modules folder that is included in the package. Why is dist not enough? Maybe that's part of the reason why styled-components.es.js cannot be shared via vendor.js?

enter image description here

I tried to exclude the dependency manually via webpack's IgnorePlugin (similar to moment.js locales) but failed so far to do so.

Any insights would be greatly appreciated. Thanks!

Machavity
  • 30,841
  • 27
  • 92
  • 100
Tobi
  • 1,492
  • 1
  • 13
  • 20
  • Did you ever find a resolution for this? Having the same problem, thought I was just bad at webpack but it seems something is configured strangely with @atlaskit – Mitch Lillie Feb 21 '18 at 18:16
  • @MitchLillie unfortunately I didn't and I stopped investing more time on this. However, I if ever find some time again I would like to investigate this more. I still believe there should be a solution. – Tobi Feb 22 '18 at 03:16

2 Answers2

2

It sounds like you want to consolidate a dependency from multiple chunks into a common chunk: For this I would recommend looking into webpack.CommonsChunkPlugin.

Of particular interest is the minChunks property you can pass to the plugin:

minChunks: number|Infinity|function(module, count) -> boolean, // The minimum number of chunks which need to contain a module before it's moved into the commons chunk. // The number must be greater than or equal 2 and lower than or equal to the number of chunks. // Passing Infinity just creates the commons chunk, but moves no modules into it. // By providing a function you can add custom logic. (Defaults to the number of chunks)

I advise trying to add this plugin to your Webpack config:

new webpack.optimize.CommonsChunkPlugin({
  children: true,
  async: true,
  minChunks: 3
})

This usage is described further in "Extra async commons chunk".

If you are interested in seeing the amount of code shared between your chunks, consider trying samccone/bundle-buddy for Webpack as well.

If you are already using CommonsChunkPlugin, I would need to see your Webpack config to provide further information.

Peter
  • 96
  • 3
  • Hi Peter, thanks for your reply. I am already using CommonsChunkPlugin, that's how I get `vendor.js`. You can see my Webpack config here: https://pastebin.com/vgiQrPqs – Tobi Sep 15 '17 at 02:37
  • Thanks for posting your config. I suspect you are not getting real tree-shaking out of `@atlaskit` because you are importing the already transpiled code. It doesn't look like `@atlaskit` supports the `"module"` field which would allow you to consume it as an ES Module. Atlassian Kit seems to ship with a key `"ak:webpack:raw": "src/index.jsx"` which points to their raw source code. You could include from this entry point using a process described in [`this 2ality post`](http://2ality.com/2017/06/pkg-esnext.html#package-users). They should be using the "module" field, not `ak:webpack:raw` – Peter Sep 15 '17 at 03:14
1

While I don't know exactly what fixed the issue, I just noticed that the latest release of Atlaskit now works with tree-shaking. I now get minimal artifacts with everything shared from Atlaskit in a big vendor.js.

enter image description here

Tobi
  • 1,492
  • 1
  • 13
  • 20