Skip to content

Commit 1cebaa0

Browse files
authored
chore(web): manually split bundle into multiple chunks (#6985)
* 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. * chore(web): add todo
1 parent 4b71478 commit 1cebaa0

File tree

1 file changed

+78
-1
lines changed

1 file changed

+78
-1
lines changed

packages/compass-web/webpack.config.js

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,68 @@ 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 (see TODO). This custom code splitting is way less
45+
* advanced, but works well for leaf node dependencies of the package.
46+
*
47+
* TODO(COMPASS-9445): This naive implementation works well only for leaf
48+
* dependencies with a single export file. A better approach would be to coerce
49+
* webpack to produce a require-able web bundle, which in theory should be
50+
* possible with a combination of `splitChunks`, `chunkFormat: 'commonjs'`, and
51+
* `target: 'web'`, but in practice produced bundle doesn't work due to webpack
52+
* runtime exports not being built correctly. We should investigate and try to
53+
* fix this to remove this custom chunk splitting logic.
54+
*/
55+
function createSiblingBundleFromLeafDeps(
56+
config,
57+
deps,
58+
moduleType = 'commonjs2'
59+
) {
60+
const siblings = Object.fromEntries(
61+
deps.map((depName) => {
62+
return [depName, `${moduleType} ./${normalizeDepName(depName)}.js`];
63+
})
64+
);
65+
const baseConfig = merge(config, { externals: siblings });
66+
const configs = [baseConfig].concat(
67+
deps.map((depName) => {
68+
return merge(baseConfig, {
69+
entry: resolveDepEntry(depName),
70+
output: {
71+
filename: `${normalizeDepName(depName)}.js`,
72+
library: { type: moduleType },
73+
},
74+
});
75+
})
76+
);
77+
return configs;
78+
}
79+
1880
/**
1981
* Atlas Cloud uses in-flight compression that doesn't compress anything that is
2082
* bigger than 10MB, we want to make sure that compass-web assets stay under the
@@ -222,7 +284,7 @@ module.exports = (env, args) => {
222284
},
223285
};
224286

225-
return merge(config, {
287+
const compassWebConfig = merge(config, {
226288
externals: {
227289
react: 'commonjs2 react',
228290
'react-dom': 'commonjs2 react-dom',
@@ -258,4 +320,19 @@ module.exports = (env, args) => {
258320
},
259321
],
260322
});
323+
324+
// Split production bundle into more chunks to make sure it's easier for us to
325+
// stay under the max chunk limit. Be careful when adding new packages here,
326+
// make sure you're only selecting big packages with the smallest amount of
327+
// shared dependencies possible
328+
const bundles = createSiblingBundleFromLeafDeps(compassWebConfig, [
329+
'@mongodb-js/compass-components',
330+
'ag-grid-community',
331+
'bson-transpilers',
332+
// bson is not that big, but is a shared dependency of compass-web,
333+
// compass-components and bson-transpilers, so splitting it out
334+
'bson',
335+
]);
336+
337+
return bundles;
261338
};

0 commit comments

Comments
 (0)