Skip to content

Commit

Permalink
defensively copy targets so @babel/helper-compilation-targets
Browse files Browse the repository at this point in the history
Babel 7.10.0 [introduced a change that mutates the `targets` object passed into [`@babel/helper-compilation-targets`](babel/babel#11500).
Since [ember-cli caches the value of `config/targets.js` on the Project](https://github.com/ember-cli/ember-cli/blob/master/lib/models/project.js#L271-L289),
that means any subsequent calls to ember-cli-babel would lose `@babel/preset-env` options defined in `targets` if the ember-cli babel was
included again anywhere else in the tree (which it usually is due to addons depending on ember-cli-babel). This would sometimes result in a `regeneratorRuntime is not defined` error for addons like Ember Concurrency that use ECMAScript features like generator functions or async functions, because the addon would not be compiled against the appropriate `browsers` list (or other `@babel/preset-env` options) because `@babel/helper-compilation-targets` mutated it away. This would happen usually in development or test, if [limiting the targets used in development](https://www.rwjblue.com/2017/10/30/async-await-configuration-adventure/#limit-targets-locally), which has been the [default in Ember CLI for a while now](ember-cli/ember-cli@7798114).

As a workaround, we can copy the `targets` object before passing it to `@babel/helper-compilation-targets` as a workaround until the regression is [fixed upstream in babel](babel/babel#11648).
  • Loading branch information
fivetanley committed May 29, 2020
1 parent d835fbb commit 3dfc15b
Show file tree
Hide file tree
Showing 3 changed files with 230 additions and 103 deletions.
9 changes: 8 additions & 1 deletion index.js
Expand Up @@ -542,7 +542,14 @@ module.exports = {

let parser = require('@babel/helper-compilation-targets').default;
if (typeof targets === 'object' && targets !== null) {
return parser(targets);
// babel version 7.10.0 introduced a change that mutates the input:
// https://github.com/babel/babel/pull/11500
// copy the object to guard against it, otherwise subsequent calls to
// _getTargets() will only have a mutated copy and lose all config from `config/targets.js`
// in the host application.
// PR to fix this upstream in babel: https://github.com/babel/babel/pull/11648
const copy = clone(targets);
return parser(copy);
} else {
return targets;
}
Expand Down
11 changes: 11 additions & 0 deletions node-tests/addon-test.js
Expand Up @@ -18,6 +18,7 @@ const terminateWorkerPool = require('./utils/terminate-workers');
const path = require('path');
const fs = require('fs');
const rimraf = require('rimraf');
const clone = require('clone');

function prepareAddon(addon) {
addon.pkg.keywords.push('ember-addon');
Expand Down Expand Up @@ -1353,6 +1354,16 @@ describe('ember-cli-babel', function() {
let pluginRequired = this.addon.isPluginRequired('transform-regenerator');
expect(pluginRequired).to.be.false;
});

it('defensively copies `targets` to prevent @babel/helper-compilation-functions mutating it', function() {
let targets = {
browsers: ['last 2 Chrome versions']
};
this.addon.project.targets = clone(targets);

this.addon.isPluginRequired('transform-regenerator');
expect(this.addon.project.targets).to.deep.equal(targets);
});
});
});

Expand Down

0 comments on commit 3dfc15b

Please sign in to comment.