Skip to content

Commit 7b7b25e

Browse files
committed
chore(web): we have chunk splitting at home
It's really hard to make webpack to bundle both for target web and use require imports for its internal module system, to work around that we add this manual chunk splitting logic for the production build.
1 parent 37cad99 commit 7b7b25e

File tree

1 file changed

+73
-1
lines changed

1 file changed

+73
-1
lines changed

packages/compass-web/webpack.config.js

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,64 @@ function localPolyfill(name) {
1515
return path.resolve(__dirname, 'polyfills', ...name.split('/'), 'index.ts');
1616
}
1717

18+
function normalizeDepName(name) {
19+
return name.replaceAll('@', '').replaceAll('/', '__');
20+
}
21+
22+
function resolveDepEntry(name) {
23+
const monorepoPackagesDir = path.resolve(__dirname, '..');
24+
const resolvedPath = require.resolve(name);
25+
if (resolvedPath.startsWith(monorepoPackagesDir)) {
26+
const packageJson = require(`${name}/package.json`);
27+
const packageRoot = path.dirname(require.resolve(`${name}/package.json`));
28+
const entrypoint = path.join(
29+
packageRoot,
30+
packageJson['compass:main'] ?? packageJson['main']
31+
);
32+
return entrypoint;
33+
}
34+
return require.resolve(name);
35+
}
36+
37+
/**
38+
* Takes in a webpack configuration for a library package and creates a
39+
* multi-compiler config that splits the library into multiple parts that can be
40+
* properly processed by another webpack compilation.
41+
*
42+
* This is opposed to using a webpack chunk splitting feature that will generate
43+
* the code that uses internal webpack module runtime that will not be handled
44+
* by any other bundler. This custom code splitting is way less advanced, but
45+
* works well for leaf node dependencies of the package.
46+
*
47+
* NB: This naive implementation works well only for leaf dependencies with a
48+
* single export file. It can be updated to support multiple exports packages,
49+
* but we can skip this for now
50+
*/
51+
function createSiblingBundleFromLeafDeps(
52+
config,
53+
deps,
54+
moduleType = 'commonjs2'
55+
) {
56+
const siblings = Object.fromEntries(
57+
deps.map((depName) => {
58+
return [depName, `${moduleType} ./${normalizeDepName(depName)}.js`];
59+
})
60+
);
61+
const baseConfig = merge(config, { externals: siblings });
62+
const configs = [baseConfig].concat(
63+
deps.map((depName) => {
64+
return merge(baseConfig, {
65+
entry: resolveDepEntry(depName),
66+
output: {
67+
filename: `${normalizeDepName(depName)}.js`,
68+
library: { type: moduleType },
69+
},
70+
});
71+
})
72+
);
73+
return configs;
74+
}
75+
1876
/**
1977
* Atlas Cloud uses in-flight compression that doesn't compress anything that is
2078
* bigger than 10MB, we want to make sure that compass-web assets stay under the
@@ -222,7 +280,7 @@ module.exports = (env, args) => {
222280
},
223281
};
224282

225-
return merge(config, {
283+
const compassWebConfig = merge(config, {
226284
externals: {
227285
react: 'commonjs2 react',
228286
'react-dom': 'commonjs2 react-dom',
@@ -258,4 +316,18 @@ module.exports = (env, args) => {
258316
},
259317
],
260318
});
319+
320+
// Split production bundle into more chunks to make sure it's easier for us to
321+
// stay under the max chunk limit. Be careful when adding new packages here,
322+
// make sure you're only selecting big packages with the smallest amount of
323+
// shared dependencies possible
324+
const bundles = createSiblingBundleFromLeafDeps(compassWebConfig, [
325+
'@mongodb-js/compass-components',
326+
'bson-transpilers',
327+
// bson is not that big, but is a shared dependency of compass-web,
328+
// compass-components and bson-transpilers, so splitting it out
329+
'bson',
330+
]);
331+
332+
return bundles;
261333
};

0 commit comments

Comments
 (0)