Skip to content

chore(web): manually split bundle into multiple chunks #6985

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 11, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 78 additions & 1 deletion packages/compass-web/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,68 @@ function localPolyfill(name) {
return path.resolve(__dirname, 'polyfills', ...name.split('/'), 'index.ts');
}

function normalizeDepName(name) {
return name.replaceAll('@', '').replaceAll('/', '__');
}

function resolveDepEntry(name) {
const monorepoPackagesDir = path.resolve(__dirname, '..');
const resolvedPath = require.resolve(name);
if (resolvedPath.startsWith(monorepoPackagesDir)) {
const packageJson = require(`${name}/package.json`);
const packageRoot = path.dirname(require.resolve(`${name}/package.json`));
const entrypoint = path.join(
packageRoot,
packageJson['compass:main'] ?? packageJson['main']
);
return entrypoint;
}
return require.resolve(name);
}

/**
* Takes in a webpack configuration for a library package and creates a
* multi-compiler config that splits the library into multiple parts that can be
* properly processed by another webpack compilation.
*
* This is opposed to using a webpack chunk splitting feature that will generate
* the code that uses internal webpack module runtime that will not be handled
* by any other bundler (see TODO). This custom code splitting is way less
* advanced, but works well for leaf node dependencies of the package.
*
* TODO(COMPASS-9445): This naive implementation works well only for leaf
* dependencies with a single export file. A better approach would be to coerce
* webpack to produce a require-able web bundle, which in theory should be
* possible with a combination of `splitChunks`, `chunkFormat: 'commonjs'`, and
* `target: 'web'`, but in practice produced bundle doesn't work due to webpack
* runtime exports not being built correctly. We should investigate and try to
* fix this to remove this custom chunk splitting logic.
*/
function createSiblingBundleFromLeafDeps(
config,
deps,
moduleType = 'commonjs2'
) {
const siblings = Object.fromEntries(
deps.map((depName) => {
return [depName, `${moduleType} ./${normalizeDepName(depName)}.js`];
})
);
const baseConfig = merge(config, { externals: siblings });
const configs = [baseConfig].concat(
deps.map((depName) => {
return merge(baseConfig, {
entry: resolveDepEntry(depName),
output: {
filename: `${normalizeDepName(depName)}.js`,
library: { type: moduleType },
},
});
})
);
return configs;
}

/**
* Atlas Cloud uses in-flight compression that doesn't compress anything that is
* bigger than 10MB, we want to make sure that compass-web assets stay under the
Expand Down Expand Up @@ -222,7 +284,7 @@ module.exports = (env, args) => {
},
};

return merge(config, {
const compassWebConfig = merge(config, {
externals: {
react: 'commonjs2 react',
'react-dom': 'commonjs2 react-dom',
Expand Down Expand Up @@ -258,4 +320,19 @@ module.exports = (env, args) => {
},
],
});

// Split production bundle into more chunks to make sure it's easier for us to
// stay under the max chunk limit. Be careful when adding new packages here,
// make sure you're only selecting big packages with the smallest amount of
// shared dependencies possible
const bundles = createSiblingBundleFromLeafDeps(compassWebConfig, [
'@mongodb-js/compass-components',
'ag-grid-community',
'bson-transpilers',
// bson is not that big, but is a shared dependency of compass-web,
// compass-components and bson-transpilers, so splitting it out
'bson',
]);

return bundles;
};
Loading