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

Add support for ember-cli addon proxy (bundle caching) #941

Merged
merged 1 commit into from
Aug 26, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions packages/compat/src/get-real-addon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// As of ember-cli@3.28, addon instances _may_ be proxied. This can become a
// problem when patching (setting/restoring) methods on the addon instance or
// comparing with the addon `__proto__`. The purpose of this util method is to
// correctly return the _real_ (original) addon instance and not the proxy.
// @see https://github.com/ember-cli/ember-cli/pull/9487

let TARGET_INSTANCE_SYMBOL: any;

try {
// eslint-disable-next-line @typescript-eslint/no-require-imports
const targetInstanceModule = require('ember-cli/lib/models/per-bundle-addon-cache/target-instance');

if (targetInstanceModule) {
TARGET_INSTANCE_SYMBOL = targetInstanceModule.TARGET_INSTANCE;
}
} catch (e) {
// we only want to handle the error when this module isn't found; i.e.,
// when a consumer of `ember-engines` is using an old version of `ember-cli`
// (less than `ember-cli` 3.28)
if (!e || e.code !== 'MODULE_NOT_FOUND') {
throw e;
}
}

/**
* Given an addon instance, gets the _real_ addon instance
* @param maybeProxyAddon - the addon instance, which may be a proxy
* @returns the _real_ (not proxied) addon instance
*/
export default function getRealAddon(maybeProxyAddon: any): any {
return (TARGET_INSTANCE_SYMBOL && maybeProxyAddon[TARGET_INSTANCE_SYMBOL]) || maybeProxyAddon;
}
21 changes: 14 additions & 7 deletions packages/compat/src/v1-addon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import TemplateCompilerBroccoliPlugin from './template-compiler-broccoli-plugin'
import { fromPairs } from 'lodash';
import { getEmberExports } from '@embroider/core/src/load-ember-template-compiler';
import prepHtmlbarsAstPluginsForUnwrap from './prepare-htmlbars-ast-plugins';
import getRealAddon from './get-real-addon';

const stockTreeNames = Object.freeze([
'addon',
Expand Down Expand Up @@ -357,13 +358,15 @@ export default class V1Addon {
}

protected customizes(...treeNames: string[]) {
// get the real addon as we're going to compare with __proto__
const realAddon = getRealAddon(this.addonInstance);
return Boolean(
treeNames.find(treeName => {
return (
// customized hook exists in actual code exported from their index.js
this.mainModule[treeName] ||
// addon instance doesn't match its own prototype
(this.addonInstance.__proto__ && this.addonInstance[treeName] !== this.addonInstance.__proto__[treeName])
(realAddon.__proto__ && realAddon[treeName] !== realAddon.__proto__[treeName])
);
})
);
Expand Down Expand Up @@ -605,9 +608,11 @@ export default class V1Addon {
if (!this.customizes('treeFor')) {
return false;
}
// get the real addon as we're going to patch and restore `_super`
const realAddon = getRealAddon(this.addonInstance);
let origSuper = this.addonInstance._super;
try {
this.addonInstance._super = stubbedSuper;
realAddon._super = stubbedSuper;
let result = this.mainModule.treeFor?.call(this.addonInstance, name);
if (result === markedEmptyTree) {
// the method returns _super unchanged, so tree is not suppressed and we
Expand All @@ -623,8 +628,8 @@ export default class V1Addon {
unsupported(`${this.name} has a custom treeFor() method that is doing some arbitrary broccoli processing.`);
return false;
} finally {
if (this.addonInstance._super === stubbedSuper) {
this.addonInstance._super = origSuper;
if (realAddon._super === stubbedSuper) {
realAddon._super = origSuper;
}
}
}
Expand All @@ -634,11 +639,13 @@ export default class V1Addon {
{ neuterPreprocessors } = { neuterPreprocessors: false }
): Node | undefined {
return this.throughTreeCache(name, 'original', () => {
// get the real addon as we're going to patch and restore `preprocessJs`
const realAddon = getRealAddon(this.addonInstance);
let original;
try {
if (neuterPreprocessors) {
original = this.addonInstance.preprocessJs;
this.addonInstance.preprocessJs = function (tree: Node) {
original = realAddon.preprocessJs;
realAddon.preprocessJs = function (tree: Node) {
return tree;
};
}
Expand All @@ -648,7 +655,7 @@ export default class V1Addon {
return this.addonInstance._treeFor(name);
} finally {
if (neuterPreprocessors) {
this.addonInstance.preprocessJs = original;
realAddon.preprocessJs = original;
}
}
});
Expand Down