diff --git a/index.js b/index.js index 32eacf69..534bbb1b 100644 --- a/index.js +++ b/index.js @@ -84,18 +84,88 @@ module.exports = { } }, + _shouldIncludeHelpers() { + let appOptions = (this.app && this.app.options) || {}; + let customOptions = appOptions['ember-cli-babel']; + + if (customOptions && 'includeExternalHelpers' in customOptions) { + return customOptions.includeExternalHelpers === true; + } else { + return false; + } + }, + + _importHelpers(app) { + let helpersPath = 'vendor/babel-helpers/babel-helpers.js'; + + if (this.import) { // support for ember-cli >= 2.7 + this.import(helpersPath, { prepend: true }); + } else if (app.import) { // support ember-cli < 2.7 + app.import(helpersPath, { prepend: true }); + } else { + // eslint-disable-next-line no-console + console.warn('Please run: ember install ember-cli-import-polyfill'); + } + }, + + _getHelperWhitelist() { + let appOptions = this._getAppOptions(); + let customOptions = appOptions['ember-cli-babel']; + + return customOptions && customOptions.externalHelperWhitelist; + } + + _getHelperVersion() { + let appOptions = this._getAppOptions(); + let customOptions = appOptions['ember-cli-babel']; + + return customOptions && customOptions.externalHelperVersion; + } + + _getHelpersPlugin() { + return [ + [ + require.resolve('@babel/plugin-external-helpers'), + { + helperVersion: this._getHelperVersion(), + whitelist: this._getHelperWhitelist() + } + ] + ] + }, + treeForVendor() { - if (!this._shouldIncludePolyfill()) { return; } + let trees = []; - const Funnel = require('broccoli-funnel'); - const UnwatchedDir = require('broccoli-source').UnwatchedDir; + if (this._shouldIncludePolyfill()) { + const Funnel = require('broccoli-funnel'); + const UnwatchedDir = require('broccoli-source').UnwatchedDir; - // Find babel-core's browser polyfill and use its directory as our vendor tree - let polyfillDir = path.dirname(require.resolve('@babel/polyfill/dist/polyfill')); + // Find babel-core's browser polyfill and use its directory as our vendor tree + let polyfillDir = path.dirname(require.resolve('@babel/polyfill/dist/polyfill')); - return new Funnel(new UnwatchedDir(polyfillDir), { - destDir: 'babel-polyfill' - }); + let polyfillTree = new Funnel(new UnwatchedDir(polyfillDir), { + destDir: 'babel-polyfill' + }); + + trees.push(polyfillTree); + } + + // Helpers are a global config, so only the root application should bother + // generating and including the file. + if (this.parent === this.app && this._shouldIncludeHelpers()) { + const babel = require('@babel/core'); + const writeFile = require('broccoli-file-creator'); + + let helpers = babel.buildExternalHelpers(this._getHelperWhitelist); + let babelHelpersTree = writeFile('babel-helpers/babel-helpers.js', helpers); + + trees.push(babelHelpersTree); + } + + if (trees.length > 0) { + return new MergeTrees(trees); + } }, included: function(app) { @@ -105,6 +175,13 @@ module.exports = { if (this._shouldIncludePolyfill()) { this._importPolyfill(app); } + + + // Helpers are a global config, so only the root application should bother + // generating and including the file. + if (this.parent === app && this._shouldIncludeHelpers()) { + this._importHelpers(app); + } }, isPluginRequired(pluginName) { @@ -120,7 +197,11 @@ module.exports = { }, _getAddonOptions() { - return (this.parent && this.parent.options) || (this.app && this.app.options) || {}; + return (this.parent && this.parent.options) || this._getAppOptions(); + }, + + _getAppOptions() { + return (this.app && this.app.options) || {}; }, _parentName() { @@ -158,6 +239,7 @@ module.exports = { _getBabelOptions(config) { let addonProvidedConfig = this._getAddonProvidedConfig(config); let shouldCompileModules = this._shouldCompileModules(config); + let shouldIncludeHelpers = this._shouldIncludeHelpers(); let emberCLIBabelConfig = config['ember-cli-babel']; let shouldRunPresetEnv = true; @@ -188,6 +270,7 @@ module.exports = { let userPostTransformPlugins = addonProvidedConfig.postTransformPlugins; options.plugins = [].concat( + shouldIncludeHelpers ** this._getHelpersPlugin(), userPlugins, this._getDebugMacroPlugins(config), this._getEmberModulesAPIPolyfill(config), diff --git a/package.json b/package.json index 55998d4c..6cebbae5 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ }, "dependencies": { "@babel/core": "^7.0.0", + "@babel/plugin-external-helpers": "^7.0.0", "@babel/plugin-transform-modules-amd": "^7.0.0", "@babel/polyfill": "^7.0.0", "@babel/preset-env": "^7.0.0", @@ -48,7 +49,9 @@ "babel-plugin-module-resolver": "^3.1.1", "broccoli-babel-transpiler": "^7.1.0", "broccoli-debug": "^0.6.4", + "broccoli-file-creator": "^2.1.1", "broccoli-funnel": "^2.0.1", + "broccoli-merge-trees": "^3.0.1", "broccoli-source": "^1.1.0", "clone": "^2.1.2", "ember-cli-version-checker": "^2.1.2", diff --git a/yarn.lock b/yarn.lock index 587d3751..174b7a9c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -193,6 +193,13 @@ version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.0.0.tgz#697655183394facffb063437ddf52c0277698775" +"@babel/plugin-external-helpers@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-external-helpers/-/plugin-external-helpers-7.0.0.tgz#61ee7ba5dba27d7cad72a13d46bec23c060b762e" + integrity sha512-tZKTMdhZvTy0KCEX5EGQQm1RHr7jUa36q/yax1baEA0yZapVYmu10yW7LTqijITgSq416gPVjrcexiA6y4pJlA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-async-generator-functions@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.0.0.tgz#5d1eb6b44fd388b97f964350007ab9da090b1d70" @@ -1579,6 +1586,14 @@ broccoli-file-creator@^1.1.1: broccoli-plugin "^1.1.0" mkdirp "^0.5.1" +broccoli-file-creator@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/broccoli-file-creator/-/broccoli-file-creator-2.1.1.tgz#7351dd2496c762cfce7736ce9b49e3fce0c7b7db" + integrity sha512-YpjOExWr92C5vhnK0kmD81kM7U09kdIRZk9w4ZDCDHuHXW+VE/x6AGEOQQW3loBQQ6Jk+k+TSm8dESy4uZsnjw== + dependencies: + broccoli-plugin "^1.1.0" + mkdirp "^0.5.1" + broccoli-funnel-reducer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" @@ -1666,6 +1681,14 @@ broccoli-merge-trees@^3.0.0: broccoli-plugin "^1.3.0" merge-trees "^2.0.0" +broccoli-merge-trees@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-3.0.1.tgz#545dfe9f695cec43372b3ee7e63c7203713ea554" + integrity sha512-EFPBLbCoyCLdjJx0lxn+acWXK/GAZesXokS4OsF7HuB+WdnV76HVJPdfwp9TaXaUkrtb7eU+ymh9tY9wOGQjMQ== + dependencies: + broccoli-plugin "^1.3.0" + merge-trees "^2.0.0" + broccoli-middleware@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/broccoli-middleware/-/broccoli-middleware-1.2.1.tgz#a21f255f8bfe5a21c2f0fbf2417addd9d24c9436"