How to reduce size of JS artifacts including AtlasKit?

atlassian-connect-dev
atlaskit

#1

I have a Webpack build that creates artifacts for my Connect app. When trying to optimize artifact size created by Webpack I noticed that AtlasKit makes up a big chunk of the total package size. In particular styled-components dependency is duplicated all over the place. Please see my StackOverflow question that details the problem.

Any Webpack or AtlasKit experts who can help? Is this due to the way AtlasKit modules are built?


#2

Anyone from the AtlasKit team who can help here?

Or anyone using AtlasKit and facing the same issue?


#3

It is to do with the way that AtlasKit modules are built and the way that Webpack bundles those modules as dependencies of your application.

Given that you can use each AtlasKit module independently, each bundled AtlasKit module has to have all its dependencies - this explains the duplication all over the shop.

As for Webpack - it isn’t smart enough (and I’ve not found any modules to make it smarter) to de-duplicate the dependencies (styled-components) of your dependencies (atlaskit) - especially when one AtlasKit module could depend on v1.2.3 of the styled-components and another AtlasKit module depend on v1.2.4 of styled-components.

If Atlassian changed their imports from styles-components to be more like this:

import React from 'react/lib/React';
import { PureComponent } from 'react/lib/ReactBaseClasses';
import Div from './styled/something/here';

instead of like they currently are:

import React, { PureComponent } from 'react';
import Div from './styled';

then AtlasKit’s own build could optimize how much of React/styled-components etc are bundled into each module because only the parts they care about are imported, instead of the entire dependency.


#4

Also, looking a bit closer at your Stackoverflow post - you can use the CommonsChunkPlugin (read the options very carefully) to split all atlaskit dependencies into their own chunk that your other chunks depend on.

In our application we have a single entry point ‘shell.js’ that asynchronously loads the relevant page and its dependencies, but then we split out 3rd party code like this:

function isExternal(module) {
    return matchesLibrary(module, 'node_modules');
}

function matchesLibrary(module, lib) {
    const userRequest = module.userRequest;

    if (typeof userRequest !== 'string') {
        return false;
    }

    return userRequest.indexOf(lib) >= 0;
}
// ...
new webpack.optimize.CommonsChunkPlugin({
    name: 'shell',        // Because this is loaded async, this must match the entry point name
    async: 'atlaskit',    // Give this chunk a name
    children: true,       // Include the dependencies of the modules included below
    minChunks: function (module) {
        return isExternal(module)
            && (matchesLibrary(module, '@atlaskit') || matchesLibrary(module, 'ak-modal-dialog'));
    }
}),

#5

Thanks for your response Jon. This looks promising, I will give this a try.


#6

Hi @tbinna,

Have you been able to fight the problem?

I’ve just started using AtlasKit and the size of webpack output bundle is enormous.

Thanks,
Jack


#7

Hi @jack,

Unfortunately not, I had some higher priority items to work on so this one was kind of left behind.


#8

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.

MAGIC! :heart_eyes: