Reputation: 2059
Following this answer to the question Is it possible to import modules from all files in a directory, using a wildcard? I was able to import multiple modules in a single declaration, exporting them like this:
/hooks/index.ts
export { default as useSections } from './useSections';
export { default as useArtworkEvents } from './useArtworkEvents';
export { default as useEventBusListener } from './useEventBusListener';
And then importing them in a component like this:
Packaging.tsx
import { useSections, useArtworkEvents, useEventBusListener } from 'src/hooks';
I’m doing the same thing in another project where there are no issues, but here I’m importing large libraries from the modules and all those libraries go into the vendor folder.
The libraries are imported like this:
import { autorun, IReactionDisposer } from 'mobx';
// body of the module
// and the export in the end
export default useArtworkEvents;
And this is the current situation:
It looks like the first place where one of the files is imported (let's say App.tsx
) is where all the libraries get loaded, even if only one should be imported (in my intentions).
I want to add that this is happening even if the components that use the libraries are loaded dynamically, through React Suspense:
App.tsx
const PackagingComponent = lazy(
() => import('src/components/PackagingComponent' /* webpackChunkName: "packaging" */)
);
And then
<ErrorBoundary locale={props.locale}>
<Suspense fallback={<Loader />}>
{props.componentType === AcceptedComponentTypes.PACKAGING && (
<DesignStackPackaging
locale={props.locale}
tenant={props.tenant}
/>
)}
{/* ...other conditions */}
</Suspense>
</ErrorBoundary>
If I remove the export in the index files (there are two in the project, one for common scripts and the other for hooks) and import the modules directly, the issue will go away.
/hooks/index.ts
export {};
Packaging.tsx
import useSections from 'src/hooks/useSections';
import useArtworkEvents from 'src/hooks/useArtworkEvents';
import useEventBusListener from 'src/hooks/useEventBusListener';
You can see that the issue seems to be solved:
So I’m asking two things:
I thought that maybe I could put all the modules that import large libraries in a separate folder where I don’t export them with an index file, while keeping smaller modules in some common folders where I do export them using the index file, but I don’t like the solution as it doesn't feel consistent, and a co-worker which is not aware may take the issue back.
For context I also add the Webpack Split Chunks configuration:
splitChunks: {
chunks: 'all',
name: true,
},
(BTW the same happens if name
is set to false
).
Upvotes: 3
Views: 2019
Reputation: 2059
So, after posting the question, I've found this other question in the related section: Barrel file and Tree Shaking, which made me understand that the index
files that I'm referring to have a name, which is barrel files, and that there are various articles on the subject.
This article for example advises not to use barrel files as they create issues with tree-shaking.
Luckily I've found this Github issue (in the Next.js repository) with the solution to my specific problem.
The solution is to turn off side effects for the barrel files, so that Webpack will not load the whole folder every time you need one single module.
So in my case the relevant part of the Webpack configuration becomes:
{
module: {
rules: [
// other rules...
{
test: [/src\/common\/index.ts/i, /src\/hooks\/index.ts/i],
sideEffects: false,
}
]
}
}
Everything else stays the same.
Finally I would like to quote a part of this reply from the same user which gave the solution:
Barrel files are effectively an API. A specific interface that distinguishes private vs public code. It especially makes sense in a monorepo with local packages. The same concept (why do packages have a specific import interface) pros/cons applies to monorepo packages.
So in the end I'm thankful that I've been able to keep barrel files without having to import every module separately.
Upvotes: 4