Skip to content

Commit 3b9abe5

Browse files
committed
Add plugin that declares side-effects
1 parent 830f86a commit 3b9abe5

2 files changed

Lines changed: 245 additions & 2 deletions

File tree

package.json

Lines changed: 162 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,5 +365,166 @@
365365
]
366366
}
367367
},
368-
"packageManager": "pnpm@10.33.2"
368+
"packageManager": "pnpm@10.33.2",
369+
"sideEffects": [
370+
"./dist/dev/packages/@ember/-internals/container/index.js",
371+
"./dist/dev/packages/@ember/-internals/deprecations/index.js",
372+
"./dist/dev/packages/@ember/-internals/environment/index.js",
373+
"./dist/dev/packages/@ember/-internals/runtime/lib/ext/rsvp.js",
374+
"./dist/dev/packages/@ember/-internals/runtime/lib/mixins/-proxy.js",
375+
"./dist/dev/packages/@ember/-internals/runtime/lib/mixins/action_handler.js",
376+
"./dist/dev/packages/@ember/-internals/runtime/lib/mixins/comparable.js",
377+
"./dist/dev/packages/@ember/-internals/runtime/lib/mixins/container_proxy.js",
378+
"./dist/dev/packages/@ember/-internals/runtime/lib/mixins/registry_proxy.js",
379+
"./dist/dev/packages/@ember/-internals/runtime/lib/mixins/target_action_support.js",
380+
"./dist/dev/packages/@ember/-internals/string/index.js",
381+
"./dist/dev/packages/@ember/-internals/views/lib/compat/fallback-view-registry.js",
382+
"./dist/dev/packages/@ember/-internals/views/lib/mixins/action_support.js",
383+
"./dist/dev/packages/@ember/-internals/views/lib/views/core_view.js",
384+
"./dist/dev/packages/@ember/-internals/views/lib/views/states.js",
385+
"./dist/dev/packages/@ember/application/index.js",
386+
"./dist/dev/packages/@ember/application/namespace.js",
387+
"./dist/dev/packages/@ember/array/index.js",
388+
"./dist/dev/packages/@ember/array/proxy.js",
389+
"./dist/dev/packages/@ember/canary-features/index.js",
390+
"./dist/dev/packages/@ember/component/index.js",
391+
"./dist/dev/packages/@ember/controller/index.js",
392+
"./dist/dev/packages/@ember/debug/index.js",
393+
"./dist/dev/packages/@ember/debug/lib/deprecate.js",
394+
"./dist/dev/packages/@ember/debug/lib/warn.js",
395+
"./dist/dev/packages/@ember/engine/index.js",
396+
"./dist/dev/packages/@ember/engine/instance.js",
397+
"./dist/dev/packages/@ember/enumerable/index.js",
398+
"./dist/dev/packages/@ember/enumerable/mutable.js",
399+
"./dist/dev/packages/@ember/object/-internals.js",
400+
"./dist/dev/packages/@ember/object/compat.js",
401+
"./dist/dev/packages/@ember/object/core.js",
402+
"./dist/dev/packages/@ember/object/evented.js",
403+
"./dist/dev/packages/@ember/object/index.js",
404+
"./dist/dev/packages/@ember/object/mixin.js",
405+
"./dist/dev/packages/@ember/object/observable.js",
406+
"./dist/dev/packages/@ember/object/promise-proxy-mixin.js",
407+
"./dist/dev/packages/@ember/object/proxy.js",
408+
"./dist/dev/packages/@ember/reactive/collections.js",
409+
"./dist/dev/packages/@ember/routing/index.js",
410+
"./dist/dev/packages/@ember/routing/lib/routing-service.js",
411+
"./dist/dev/packages/@ember/routing/none-location.js",
412+
"./dist/dev/packages/@ember/routing/route.js",
413+
"./dist/dev/packages/@ember/routing/router-service.js",
414+
"./dist/dev/packages/@ember/routing/router.js",
415+
"./dist/dev/packages/@ember/runloop/index.js",
416+
"./dist/dev/packages/@ember/template-compiler/lib/dasherize-component-name.js",
417+
"./dist/dev/packages/@glimmer/program/index.js",
418+
"./dist/dev/packages/@glimmer/validator/index.js",
419+
"./dist/dev/packages/@glimmer/wire-format/index.js",
420+
"./dist/dev/packages/ember-template-compiler/index.js",
421+
"./dist/dev/packages/ember-testing/index.js",
422+
"./dist/dev/packages/ember-testing/lib/adapters/adapter.js",
423+
"./dist/dev/packages/rsvp/index.js",
424+
"./dist/dev/packages/shared-chunks/arguments-gkFKpbTy.js",
425+
"./dist/dev/packages/shared-chunks/cache-DqwW4PZn.js",
426+
"./dist/dev/packages/shared-chunks/capabilities-CajW4QjE.js",
427+
"./dist/dev/packages/shared-chunks/compiler-QUSl_urU.js",
428+
"./dist/dev/packages/shared-chunks/container-BzzHmCNj.js",
429+
"./dist/dev/packages/shared-chunks/curly-5lnWjV_e.js",
430+
"./dist/dev/packages/shared-chunks/element-Djb0WF7r.js",
431+
"./dist/dev/packages/shared-chunks/env-g-kaAFLN.js",
432+
"./dist/dev/packages/shared-chunks/get-BnKnpMTb.js",
433+
"./dist/dev/packages/shared-chunks/guid-Cbq2sNV_.js",
434+
"./dist/dev/packages/shared-chunks/hash-CBwipd1d.js",
435+
"./dist/dev/packages/shared-chunks/helper-CWl5B-4E.js",
436+
"./dist/dev/packages/shared-chunks/index-CXWqBTZ_.js",
437+
"./dist/dev/packages/shared-chunks/index-D3YEDflV.js",
438+
"./dist/dev/packages/shared-chunks/libraries-CaP2cp6J.js",
439+
"./dist/dev/packages/shared-chunks/not-DuTrBRNw.js",
440+
"./dist/dev/packages/shared-chunks/observers-srAIhjN-.js",
441+
"./dist/dev/packages/shared-chunks/on-C42k4J29.js",
442+
"./dist/dev/packages/shared-chunks/property_get-Dc2Ve_Hk.js",
443+
"./dist/dev/packages/shared-chunks/reference-DElZaLK7.js",
444+
"./dist/dev/packages/shared-chunks/render-BxsZ3FBD.js",
445+
"./dist/dev/packages/shared-chunks/rsvp.es-sjc83pnY.js",
446+
"./dist/dev/packages/shared-chunks/setup-registry-CEjTxtYx.js",
447+
"./dist/dev/packages/shared-chunks/super-BBBjgF69.js",
448+
"./dist/dev/packages/shared-chunks/template-only-DI-cJA3I.js",
449+
"./dist/dev/packages/shared-chunks/textarea-DvjbcJjV.js",
450+
"./dist/dev/packages/shared-chunks/tracked-CzOGbr6n.js",
451+
"./dist/dev/packages/shared-chunks/unique-id-BhLq21xA.js",
452+
"./dist/dev/packages/shared-chunks/unrecognized-url-error-CNAGqvYM.js",
453+
"./dist/prod/packages/@ember/-internals/container/index.js",
454+
"./dist/prod/packages/@ember/-internals/deprecations/index.js",
455+
"./dist/prod/packages/@ember/-internals/environment/index.js",
456+
"./dist/prod/packages/@ember/-internals/runtime/lib/ext/rsvp.js",
457+
"./dist/prod/packages/@ember/-internals/runtime/lib/mixins/-proxy.js",
458+
"./dist/prod/packages/@ember/-internals/runtime/lib/mixins/action_handler.js",
459+
"./dist/prod/packages/@ember/-internals/runtime/lib/mixins/comparable.js",
460+
"./dist/prod/packages/@ember/-internals/runtime/lib/mixins/container_proxy.js",
461+
"./dist/prod/packages/@ember/-internals/runtime/lib/mixins/registry_proxy.js",
462+
"./dist/prod/packages/@ember/-internals/runtime/lib/mixins/target_action_support.js",
463+
"./dist/prod/packages/@ember/-internals/string/index.js",
464+
"./dist/prod/packages/@ember/-internals/views/lib/compat/fallback-view-registry.js",
465+
"./dist/prod/packages/@ember/-internals/views/lib/mixins/action_support.js",
466+
"./dist/prod/packages/@ember/-internals/views/lib/views/core_view.js",
467+
"./dist/prod/packages/@ember/-internals/views/lib/views/states.js",
468+
"./dist/prod/packages/@ember/application/index.js",
469+
"./dist/prod/packages/@ember/application/namespace.js",
470+
"./dist/prod/packages/@ember/array/index.js",
471+
"./dist/prod/packages/@ember/array/proxy.js",
472+
"./dist/prod/packages/@ember/canary-features/index.js",
473+
"./dist/prod/packages/@ember/component/index.js",
474+
"./dist/prod/packages/@ember/controller/index.js",
475+
"./dist/prod/packages/@ember/engine/index.js",
476+
"./dist/prod/packages/@ember/engine/instance.js",
477+
"./dist/prod/packages/@ember/enumerable/index.js",
478+
"./dist/prod/packages/@ember/enumerable/mutable.js",
479+
"./dist/prod/packages/@ember/object/compat.js",
480+
"./dist/prod/packages/@ember/object/core.js",
481+
"./dist/prod/packages/@ember/object/evented.js",
482+
"./dist/prod/packages/@ember/object/index.js",
483+
"./dist/prod/packages/@ember/object/observable.js",
484+
"./dist/prod/packages/@ember/object/promise-proxy-mixin.js",
485+
"./dist/prod/packages/@ember/object/proxy.js",
486+
"./dist/prod/packages/@ember/reactive/collections.js",
487+
"./dist/prod/packages/@ember/routing/index.js",
488+
"./dist/prod/packages/@ember/routing/lib/routing-service.js",
489+
"./dist/prod/packages/@ember/routing/none-location.js",
490+
"./dist/prod/packages/@ember/routing/route.js",
491+
"./dist/prod/packages/@ember/routing/router-service.js",
492+
"./dist/prod/packages/@ember/routing/router.js",
493+
"./dist/prod/packages/@ember/runloop/index.js",
494+
"./dist/prod/packages/@ember/template-compiler/lib/dasherize-component-name.js",
495+
"./dist/prod/packages/@glimmer/program/index.js",
496+
"./dist/prod/packages/@glimmer/validator/index.js",
497+
"./dist/prod/packages/@glimmer/wire-format/index.js",
498+
"./dist/prod/packages/ember-template-compiler/index.js",
499+
"./dist/prod/packages/ember-testing/index.js",
500+
"./dist/prod/packages/ember-testing/lib/adapters/adapter.js",
501+
"./dist/prod/packages/rsvp/index.js",
502+
"./dist/prod/packages/shared-chunks/arguments-tja1iZKE.js",
503+
"./dist/prod/packages/shared-chunks/cache-CppWGdQ4.js",
504+
"./dist/prod/packages/shared-chunks/capabilities-BuVYh-vx.js",
505+
"./dist/prod/packages/shared-chunks/compiler-lBSssiWp.js",
506+
"./dist/prod/packages/shared-chunks/curly-BVN3BwzJ.js",
507+
"./dist/prod/packages/shared-chunks/element-CdgK_DV6.js",
508+
"./dist/prod/packages/shared-chunks/env-DXxsTFkM.js",
509+
"./dist/prod/packages/shared-chunks/get-tneeUZus.js",
510+
"./dist/prod/packages/shared-chunks/guid-Cbq2sNV_.js",
511+
"./dist/prod/packages/shared-chunks/hash-BoYO-y9I.js",
512+
"./dist/prod/packages/shared-chunks/helper-BquvJSix.js",
513+
"./dist/prod/packages/shared-chunks/index-BrUPli3r.js",
514+
"./dist/prod/packages/shared-chunks/index-DQ_rYPZ7.js",
515+
"./dist/prod/packages/shared-chunks/libraries-CbGkth0j.js",
516+
"./dist/prod/packages/shared-chunks/not-CBwPVTAg.js",
517+
"./dist/prod/packages/shared-chunks/observers-SvVftzcD.js",
518+
"./dist/prod/packages/shared-chunks/on-D8CZzVgt.js",
519+
"./dist/prod/packages/shared-chunks/property_get-BmpDn1vT.js",
520+
"./dist/prod/packages/shared-chunks/reference-I0E7ajs4.js",
521+
"./dist/prod/packages/shared-chunks/render-6pHjGvYr.js",
522+
"./dist/prod/packages/shared-chunks/rsvp.es-sjc83pnY.js",
523+
"./dist/prod/packages/shared-chunks/setup-registry-C4gFRbyc.js",
524+
"./dist/prod/packages/shared-chunks/super-BBBjgF69.js",
525+
"./dist/prod/packages/shared-chunks/template-only-B_Ne8IRP.js",
526+
"./dist/prod/packages/shared-chunks/textarea-n1F8oZtK.js",
527+
"./dist/prod/packages/shared-chunks/unique-id-DCk9gt8T.js",
528+
"./dist/prod/packages/shared-chunks/unrecognized-url-error-CJNUvmrL.js"
529+
]
369530
}

rollup.config.mjs

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { dirname, parse, resolve, join } from 'node:path';
1+
import { dirname, parse, resolve, join, relative, isAbsolute } from 'node:path';
22
import { existsSync, readFileSync, statSync, writeFileSync } from 'node:fs';
33
import { createRequire } from 'node:module';
44
import { fileURLToPath } from 'node:url';
55
import glob from 'glob';
66
import * as resolveExports from 'resolve.exports';
7+
import { rollup } from 'rollup';
78
import { babel } from '@rollup/plugin-babel';
89
import sharedBabelConfig from './babel.config.mjs';
910

@@ -97,6 +98,8 @@ function sharedESMConfig({ input, debugMacrosMode, includePackageMeta = false })
9798
plugins.push(packageMeta());
9899
}
99100

101+
plugins.push(updateSideEffects());
102+
100103
return {
101104
onLog: handleRollupWarnings,
102105
input,
@@ -550,6 +553,85 @@ function packageMeta() {
550553
};
551554
}
552555

556+
let cleanedSideEffects = false;
557+
function updateSideEffects() {
558+
let manifestPath = resolve(projectRoot, 'package.json');
559+
let entryId = '\0side-effect-probe-entry';
560+
561+
async function hasNoSideEffects(file) {
562+
let bundle;
563+
try {
564+
bundle = await rollup({
565+
input: entryId,
566+
treeshake: { moduleSideEffects: 'no-external' },
567+
onwarn() {},
568+
plugins: [
569+
{
570+
name: 'side-effect-probe',
571+
resolveId(source, importer) {
572+
if (source === entryId) return entryId;
573+
if (importer === file) return { id: source, external: true };
574+
return null;
575+
},
576+
load(id) {
577+
if (id === entryId) return `import ${JSON.stringify(file)};`;
578+
},
579+
},
580+
],
581+
});
582+
let { output } = await bundle.generate({ format: 'es' });
583+
return output[0].code.trim() === '';
584+
} finally {
585+
if (bundle) await bundle.close();
586+
}
587+
}
588+
589+
return {
590+
name: 'update-side-effects-in-package-json',
591+
async buildStart() {
592+
// we only want to clean once,
593+
// but add sideEffects for each sub-config that uses this plugin
594+
if (cleanedSideEffects) return;
595+
let manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
596+
597+
delete manifest.sideEffects;
598+
599+
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
600+
cleanedSideEffects = true;
601+
},
602+
async writeBundle(options) {
603+
let outputDir = isAbsolute(options.dir) ? relative(projectRoot, options.dir) : options.dir;
604+
let files = glob.sync(`${outputDir}/packages/**/*.js`, {
605+
cwd: projectRoot,
606+
nodir: true,
607+
});
608+
609+
let withSideEffects = [];
610+
let batchSize = 50;
611+
612+
for (let i = 0; i < files.length; i += batchSize) {
613+
let batch = files.slice(i, i + batchSize);
614+
let pure = await Promise.all(
615+
batch.map((file) => hasNoSideEffects(resolve(projectRoot, file)))
616+
);
617+
618+
batch.forEach((file, index) => {
619+
if (!pure[index]) {
620+
withSideEffects.push('./' + file);
621+
}
622+
});
623+
}
624+
625+
let manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
626+
let fromOtherBuilds = manifest.sideEffects ?? [];
627+
628+
manifest.sideEffects = fromOtherBuilds.concat(withSideEffects).toSorted();
629+
630+
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
631+
},
632+
};
633+
}
634+
553635
const allowedCycles = [
554636
// external and not causing problems
555637
'node_modules/rsvp/lib/rsvp',

0 commit comments

Comments
 (0)