From d955e4554869188ebd53dc123a8cfbc420318d8c Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Thu, 27 Aug 2026 09:37:27 +0300 Subject: [PATCH] build(rollup-utils): Skip bare side-effect imports for `sideEffects: false` externals Co-Authored-By: Claude Opus 5 --- dev-packages/rollup-utils/npmHelpers.mjs | 40 ++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/dev-packages/rollup-utils/npmHelpers.mjs b/dev-packages/rollup-utils/npmHelpers.mjs index 064dd6f4e8e9..de626e066702 100644 --- a/dev-packages/rollup-utils/npmHelpers.mjs +++ b/dev-packages/rollup-utils/npmHelpers.mjs @@ -29,6 +29,38 @@ const packageDotJSON = JSON.parse(fs.readFileSync(path.resolve(process.cwd(), '. const ignoreSideEffects = /[\\/]debug-build\.ts$/; +const repoRoot = path.resolve(__dirname, '../..'); +const sideEffectsCache = new Map(); + +/** + * Whether an external package declares `"sideEffects": false` in its `package.json`. + * Unknown packages are treated as having side effects. + */ +function isSideEffectFreePackage(packageName) { + const cached = sideEffectsCache.get(packageName); + if (cached !== undefined) { + return cached; + } + + let sideEffectFree = false; + try { + const json = JSON.parse( + fs.readFileSync(path.resolve(repoRoot, 'node_modules', packageName, 'package.json'), { encoding: 'utf8' }), + ); + sideEffectFree = json.sideEffects === false; + } catch { + // Not resolvable from the repo root - assume side effects. + } + + sideEffectsCache.set(packageName, sideEffectFree); + return sideEffectFree; +} + +function getPackageName(id) { + const segments = id.split('/'); + return id.startsWith('@') ? segments.slice(0, 2).join('/') : segments[0]; +} + export function makeBaseNPMConfig(options = {}) { const { entrypoints = ['src/index.ts'], @@ -109,9 +141,11 @@ export function makeBaseNPMConfig(options = {}) { return false; } - // @sentry/conventions only exports constants (sideEffects: false), - // so Rollup shouldn't emit bare side-effect imports for it. - if (external && id.startsWith('@sentry/conventions')) { + // Rollup keeps a bare `import ''` alive whenever it tree-shakes away every + // binding of an external it believes has side effects. For a package that declares + // `"sideEffects": false` that import contradicts its own manifest, and bundlers such + // as esbuild warn about it (`ignored-bare-import`). + if (external && isSideEffectFreePackage(getPackageName(id))) { return false; }