Skip to content
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

Fix ember-cli-babel optimization #1042

Merged
merged 1 commit into from
Dec 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 8 additions & 1 deletion packages/compat/src/build-compat-addon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ function buildCompatAddon(originalPackage: Package, v1Cache: V1InstanceCache): N

let oldPackages = v1Cache.getAddons(originalPackage.root);

if (oldPackages.length > 1) {
// extensibility hook that allows a compat adapter to optimize its own
// smooshing. We do it early so that if it reduces all the way to zero, the
// next check will handle that.
oldPackages = oldPackages[0].reduceInstances(oldPackages);
}

if (oldPackages.length === 0) {
// this happens when the v1 addon wasn't actually getting instantiated at
// all, which can happen if the app uses `addons.blacklist` or another addon
Expand All @@ -39,7 +46,7 @@ function buildCompatAddon(originalPackage: Package, v1Cache: V1InstanceCache): N
return new EmptyPackageTree(originalPackage.name);
}

let needsSmooshing = oldPackages[0].hasAnyTrees();
let needsSmooshing = oldPackages.length > 1 && oldPackages[0].hasAnyTrees();
if (needsSmooshing) {
let trees = oldPackages.map(pkg => pkg.v2Tree).reverse();
let smoosher = new SmooshPackageJSON(trees, { annotation: originalPackage.name });
Expand Down
30 changes: 13 additions & 17 deletions packages/compat/src/compat-adapters/ember-cli-babel.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
import writeFile from 'broccoli-file-creator';
import V1Addon from '../v1-addon';

// Because almost every addon depends on ember-cli-babel, and because ember-cli
// instantiates a separate instance of Addon per consumer, approximately *half*
// of all Addon instances in a typical app will be copies of ember-cli-babel.
//
// Under embroider, *all* of them should be contributing no files to the build.
export default class EmberCliBabel extends V1Addon {
// this ensures we don't bother smooshing together a large number of useless
// copies of the addon.
hasAnyTrees() {
return false;
}

// and the one copy that we do emit should just be an empty valid package. We
// don't want the babel helpers it emits, they're not even used under
// Embroider anyway.
get v2Tree() {
return writeFile('package.json', JSON.stringify(this.newPackageJSON, null, 2));
// the only copy of ember-cli-babel that might need to do something is the
// first one that wants to emit babel polyfills. No other copy is allowed to
// emit anything into the build.
reduceInstances(copies: EmberCliBabel[]): EmberCliBabel[] {
let polyfillCopy = copies.find(c => {
let instance = c.addonInstance as any;
return typeof instance._shouldIncludePolyfill === 'function' && instance._shouldIncludePolyfill();
});
if (polyfillCopy) {
return [polyfillCopy];
} else {
return [];
}
}
}
20 changes: 20 additions & 0 deletions packages/compat/src/v1-addon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,26 @@ export default class V1Addon {
}
}

// Optional extensible hook for pruning down the list of redundant addon
// instances produces by the classic ember-cli architecture. ember-cli
// instantiates each addon *per consumer*, not per package. So a given package
// will have many addon instances, and Embroider dutifully produces a V1Addon
// instance for each one, and then needs to mimic the classic smooshing
// behavior between them.
//
// But some packages (and ember-cli-babel is the motivating example) produce a
// huge number of instances that do nothing useful and incur significant cost.
// This hook allows their compat adapter to prune down the set, using
// addon-specific knowledge of which instance(s) are actually important.
//
// The order of the instances is significant. The first one is the one with
// the highest precedence, meaning its files would win under classic
// smooshing.
reduceInstances(instances: V1Addon[]): V1Addon[] {
// the default beahvior is that all copies matter
return instances;
}

// this is only defined when there are custom AST transforms that need it
@Memoize()
private get templateCompiler(): NodeTemplateCompiler | undefined {
Expand Down