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

Do not put mutable state on the prototype. #386

Merged
merged 1 commit into from Sep 9, 2019

Conversation

rwjblue
Copy link
Collaborator

@rwjblue rwjblue commented Sep 6, 2019

Using a mutable object on the addon's prototype causes issues when ember-m3 is consumed by an addon as a direct dependency.

The specific setup is:

  • ember-m3 depends on ember-compatibility-helpers
  • ember-m3 has the following in its index.js:
module.exports = {
  name: require('./package').name,

  options: {
    m3: true,
    babel: {
      loose: true,
    },
  },
};
  • addon B depends on ember-m3 (not a dev dep)

In this scenario, ember-m3 will be instantiated twice. Once for addon B's dummy app and again for addon B's direct dependency. Since ember-m3 had a mutable object on its prototype (yes, you know whats coming now) ember-compatibility-helpers adds a plugins array to it and pushes into it.

Now that ember-m3 has updated to Babel 7, pushing the same babel plugin into the plugins array twice triggers an error (which is super annoying to debug):

Build Error (broccoli-persistent-filter:Babel > [Babel: ember-m3]) in ember-m3/factory.js

Duplicate plugin/preset detected.
If you'd like to use two separate instances of a plugin,
they need separate names, e.g.

  plugins: [
    ['some-plugin', {}],
    ['some-plugin', {}, 'some unique name'],
  ]


Stack Trace and Error Report: /var/folders/mt/yt2qjpl93ls98lrkrs81rzch000pzv/T/error.dump.246a0987138182f85c209aed25484574.log

@rwjblue rwjblue requested a review from hjdivad September 6, 2019 22:49
@rwjblue
Copy link
Collaborator Author

rwjblue commented Sep 6, 2019

Note: I've also created ember-cli/ember-compatibility-helpers#36 to fix ember-compatibility-helpers so that they won't add the same plugin twice, but IMHO we should still land the fix here also.

Using a mutable object on the addon's prototype causes issues when ember-m3 is consumed by an addon as a direct dependency.

The specific setup is:

* `ember-m3` depends on ember-compatibility-helpers
* `ember-m3` has the following in its `index.js`:

```js
module.exports = {
  name: require('./package').name,

  options: {
    m3: true,
    babel: {
      loose: true,
    },
  },
};
```

* addon B depends on `ember-m3` (**not** a dev dep)

In this scenario, `ember-m3` will be instantiated twice. Once for addon B's dummy app and again for addon B's direct dependency. Since `ember-m3` had a _mutable object_ on its prototype (yes, you know whats coming now) ember-compatibility-helpers adds a `plugins` array to it and pushes into it.

Now that ember-m3 has updated to Babel 7, pushing the same babel plugin into the plugins array twice triggers an error (which is super annoying to debug):

```
Build Error (broccoli-persistent-filter:Babel > [Babel: ember-m3]) in ember-m3/factory.js

Duplicate plugin/preset detected.
If you'd like to use two separate instances of a plugin,
they need separate names, e.g.

  plugins: [
    ['some-plugin', {}],
    ['some-plugin', {}, 'some unique name'],
  ]

Stack Trace and Error Report: /var/folders/mt/yt2qjpl93ls98lrkrs81rzch000pzv/T/error.dump.246a0987138182f85c209aed25484574.log
```
@dbashford
Copy link

@rwjblue running into this in my app which has a big combination of internal addons and engines. How does one go about digging into this?

Also, the documentation on the ember-cli-babel readme regarding the location of the babel config..

  • App => ember-cli-build.js
  • Engine => index.js (via init())
  • Addon => index.js (via init())

...imagine that plays a role? We need to be able to use all of our addons/engines individually as well a a part of the whole.

Struggling pretty hard tracking some of this down

@hjdivad
Copy link
Collaborator

hjdivad commented Sep 9, 2019

@dbashford what is the "this" you are running into? If it's exactly the error that @rwjblue posted above from babel about "Duplicate plugin/preset detected." then there are two answers

  1. We'll try to get a PR to babel to make that error more informative.
  2. If you debug and put a breakpoint at that place in babel it is very easy to see the duplicates.

You can add a debugger probably in node_modules/@babel/core/lib/config/config-descriptors.js. You will want to debug specifically the function assertNoDuplicates.

Run your build in debugging mode with

JOBS=1 node --inspect-brk ./node_modules/.bin/ember build

And then connect by opening chrome at chrome://inspect and clicking "Open dedicated DevTools for Node".

Print out all the items and you'll be able to see which specific plugins are duplicates.

console.log(JSON.stringify(items, null, 2));

Look for plugins that have the same alias and same name (keep in mind name may be undefined).

An alternative approach is to break once you're in the then branch for nameMap.has(item.name), ie just before the assertion is thrown. You can then find the exactly conflicts causing the assertion with something like:

let conflicts = items.filter(i => i.value === item.value);
console.log(JSON.stringify(conflicts, null, 2));

Once you know what plugin is conflicting yarn why $PluginName will tell you why you're loading the plugin at all, which should help you figure out what addons to investigate.

@hjdivad hjdivad merged commit 9204775 into master Sep 9, 2019
@hjdivad hjdivad deleted the rwjblue/mutable-trollage branch September 9, 2019 15:44
@hjdivad
Copy link
Collaborator

hjdivad commented Sep 9, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants