We've recently been looking at implementing code splitting into our complex web application to reduce the main bundle size. The main part that we're focussing on is dynamic imports using webpack & react-loadable.
I've come across something I deem to be quite a big problem, take this example:
const FirstChild = Loadable({
loader: () => import('some/file/path/FirstChild.jsx')
});
const SecondChild = Loadable({
loader: () => import('some/file/path/SecondChild.jsx')
});
const ParentComponent = () => (
<div>
<FirstChild />
<SecondChild />
</div>
);
where FirstChild.jsx & SecondChild.jsx both import the same service:
import MyService from 'some/file/path/my.service.js';
When bundling this with webpack, we end up with 3 files:
- Main bundle (which includes the parent component)
- FirstChild bundle (which includes
MyService
) - SecondChild bundle (which also includes
MyService
)
At this point I see a problem - we have duplicates of MyService
between both files. For some small apps this might not be a problem (or if the service was specifically just helper methods) but if we're using our service to store some data across the lifetime of the app, we would end up with two object references of this service, therefore defeating it's point entirely.
I understand that the service here could be moved 'top-level' to the ParentComponent
and possibly passed as a prop to each component but it seems like it destroys the architecture that webpack has in place in the first place - to be able to import whatever we need wherever we need and it creating just one reference. It also could be problematic if you have lots of nested components which all need to import various services and other components.
Obviously this example is simple but implementing this into a massive app which has a very complex architecture could immediately run us into problems.
Any thoughts on this? Thanks!
Going to answer my own question on this one.
Discovered that:
MyService.js
ends up in the output of each chunk. Webpack is clever enough to only load the first instance ofMyService
that it finds and uses just one reference for that. Meaning that ifFirstChild
loadsMyService
first, thenSecondChild
will also use the sameMyService
that was loaded byFirstChild
and it's copy ofMyService
will just be ignored.MyService.js
in this case might end up in a chunk likeservices~FirstChild/SecondChild/SecondChild.js
- which doesn't make very nice for debugging but I assume it's the way Webpack references it's imports.Please let me know if any of that is wrong or you find other interesting points about code splitting + webpack.