Skip to content

Commit

Permalink
Merge pull request #97 from homer0/homer0_babel
Browse files Browse the repository at this point in the history
fix: improve Babel settings for polyfills
  • Loading branch information
homer0 committed Dec 28, 2019
2 parents 313cdfb + 97a62fb commit 38ca8ff
Show file tree
Hide file tree
Showing 7 changed files with 376 additions and 29 deletions.
14 changes: 13 additions & 1 deletion documents/projectConfiguration.md
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ Using this flags, you can tell projext to always watch your files when building
> objectRestSpread: false,
> },
> nodeVersion: 'current',
> env: {},
> overwrites: {},
> }
> ```
Expand All @@ -333,6 +334,10 @@ If you need other plugins, they can be included on the `overwrites` option.

When building the Babel configuration, projext uses the [`@babel/preset-env`](https://yarnpkg.com/en/package/@babel/preset-env) to just include the necessary stuff. This setting tells the preset the version of Node it should _"complete"_.

**`babel.env`**

Custom settings that projext will use as base when generating the ones for the [`@babel/preset-env`](https://yarnpkg.com/en/package/@babel/preset-env).

**`babel.overwrites`**

If you know how to use Babel and need stuff that is not covered by projext, you can use this setting to overwrite/add any value you may need.
Expand Down Expand Up @@ -652,6 +657,7 @@ Using this flags, you can tell projext to always watch your files when building
> browserVersions: 2,
> mobileSupport: true,
> polyfill: true,
> env: {},
> overwrites: {},
> }
> ```
Expand Down Expand Up @@ -681,7 +687,13 @@ If `true`, the configuration will add to the list of major browsers `iOS` and `A

**`babel.polyfill`**

Whether or not the configuration should include the [`babel-polyfill`](https://yarnpkg.com/en/package/babel-polyfill) package.
Whether or not the configuration for the [`@babel/preset-env`](https://yarnpkg.com/en/package/@babel/preset-env) should include the settings for [`useBuiltIns` and `corejs`](https://babeljs.io/docs/en/babel-preset-env#usebuiltins).

Something that should be noted is that if `babel.polyfill` is set to `true`, projext will set `useBuiltIns` to `usage`; if you want to change it to `entry`, you have to change it using `babel.env` (explained below) and manually import [`core-js/stable`](https://yarnpkg.com/en/package/core-js) and [`regenerator-runtime/runtime`](https://yarnpkg.com/en/package/regenerator-runtime). If you do it, you can use the same _semver range_ projext uses so `npm`/`yarn` can resolve them to the ones installed by projext.

**`babel.env`**

Custom settings that projext will use as base when generating the ones for the [`@babel/preset-env`](https://yarnpkg.com/en/package/@babel/preset-env).

**`babel.overwrites`**

Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
"nodemon": "^2.0.2",
"prompt": "^1.0.0",
"dotenv": "^8.2.0",
"dotenv-expand": "^5.1.0"
"dotenv-expand": "^5.1.0",
"core-js": "^3.6.1",
"regenerator-runtime": "0.13.3"
},
"devDependencies": {
"eslint": "^6.8.0",
Expand Down
102 changes: 83 additions & 19 deletions src/services/configurations/babelConfiguration.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,10 @@ class BabelConfiguration {
* @return {Object}
*/
getConfigForTarget(target) {
// Get the target settings we need
// Get the target settings we need.
const {
babel: {
features,
nodeVersion,
browserVersions,
mobileSupport,
overwrites,
},
flow,
Expand All @@ -87,21 +84,8 @@ class BabelConfiguration {

// If it doesn't have the `env` preset...
if (!hasEnv) {
// ...define the preset targets depending on the target type.
const presetTargets = {};
if (target.is.browser) {
const browsers = ['chrome', 'safari', 'edge', 'firefox'];
if (mobileSupport) {
browsers.push(...['ios', 'android']);
}

presetTargets.browsers = browsers
.map((browser) => `last ${browserVersions} ${browser} versions`);
} else {
presetTargets.node = nodeVersion;
}
// Push the new `env` preset on top of the list.
presets.unshift([envPresetName, { targets: presetTargets }]);
// ... create an `env` preset for the target and add it to the top of the list.
presets.unshift([envPresetName, this._createEnvPresetForTarget(target)]);
}

// Check if the configuration should include any _'known plugin'_.
Expand Down Expand Up @@ -135,6 +119,86 @@ class BabelConfiguration {
// Return a reduced configuration
return this.events.reduce('babel-configuration', config, target);
}
/**
* Creates a configuration for a Babel "env preset" using the settings from a target.
* @param {Target} target The target information.
* @return {Object}
* @access protected
* @ignore
*/
_createEnvPresetForTarget(target) {
// Get the target settings we need.
const {
babel: {
nodeVersion,
browserVersions,
mobileSupport,
polyfill,
env,
},
} = target;
/**
* If the target needs polyfills, use as base the settings for `core-js`, otherwise, just
* use an empty object.
*/
const presetBaseSettings = polyfill ? { corejs: 3, useBuiltIns: 'usage' } : {};
/**
* Merge an object with the required properties, the base generated after evaluating the need
* for polyfills, and whatever was specified on the target settings.
*/
const envPreset = Object.assign({ targets: {} }, presetBaseSettings, env);
// If the target is for browsers...
if (target.is.browser) {
/**
* Check if the target had settings for browsers, because if there are no settings, the
* method will create new ones, if there was an array, the method will only add settings
* for browsers that are not present; and if the value is `falsy`, it will delete the key.
*/
const { targets: { browsers: currentBrowsers } } = envPreset;
const currentBrowsersExists = Array.isArray(currentBrowsers);
if (currentBrowsersExists || typeof currentBrowsers === 'undefined') {
// Define the list of basic desktop browsers.
const browsers = ['chrome', 'safari', 'edge', 'firefox'];
// If the target needs transpilation for mobile, add the supported mobile browsers.
if (mobileSupport) {
browsers.push(...['ios', 'android']);
}
/**
* Map the settings into dictionaries with the name of the browser the setting is for and
* the value of the setting.
*/
let browsersSettings = browsers.map((browser) => ({
name: browser,
setting: `last ${browserVersions} ${browser} versions`,
}));

// Define the variable for the new value of the setting.
const newValue = [];
/**
* If there was a list of browser settings on the target, push it to the list that will be
* used as the new value and remove the browsers that are already present.
*/
if (currentBrowsersExists) {
newValue.push(...currentBrowsers);
browsersSettings = browsersSettings
.filter((settings) => !currentBrowsers.some((line) => line.includes(settings.name)));
}

// Push the settings for the list of browsers generated by the method.
newValue.push(...browsersSettings.map(({ setting }) => setting));
// Overwrite the value of the setting.
envPreset.targets.browsers = newValue;
} else {
// `browsers` was `falsy`, so it needs to be removed.
delete envPreset.targets.browsers;
}
} else if (typeof envPreset.targets.node === 'undefined') {
// Add the Node version if it's not already defined.
envPreset.targets.node = nodeVersion;
}

return envPreset;
}
/**
* Checks if a plugin/preset exists on a Babel configuration property list. The reason of the
* method is that, sometimes, the plugins or presets can be defined as array (first the name and
Expand Down
2 changes: 2 additions & 0 deletions src/services/configurations/projectConfiguration.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ class ProjectConfiguration extends ConfigurationFile {
objectRestSpread: false,
},
nodeVersion: 'current',
env: {},
overwrites: {},
},
flow: false,
Expand Down Expand Up @@ -195,6 +196,7 @@ class ProjectConfiguration extends ConfigurationFile {
browserVersions: 2,
mobileSupport: true,
polyfill: true,
env: {},
overwrites: {},
},
flow: false,
Expand Down
13 changes: 10 additions & 3 deletions src/typedef.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,11 @@
* This object can be used to enable/disable the Babel plugins projext includes.
* If you need other plugins, they can be included on the `overwrites` option.
* @property {string} [nodeVersion='current']
* When building the Babel configuration, projext uses the `babel-preset-env` to just include the
* When building the Babel configuration, projext uses the `@babel/preset-env` to just include the
* necessary stuff. This setting tells the preset the version of Node it should _"complete"_.
* @property {Object} [env={}]
* Custom settings that projext will use as base when generating the ones for the
* `@babel/preset-env`.
* @property {Object} [overwrites={}]
* If you know how to use Babel and need stuff that is not covered by projext, you can use this
* setting to overwrite/add any value you may need.
Expand Down Expand Up @@ -337,17 +340,21 @@
* This object can be used to enable/disable the Babel plugins projext includes.
* If you need other plugins, they can be included on the `overwrites` option.
* @property {number} [browserVersions=2]
* When building the Babel configuration, projext uses the `babel-preset-env` to just include the
* When building the Babel configuration, projext uses the `@babel/preset-env` to just include the
* necessary stuff. This setting tells how many old versions of the major browsers the target needs
* transpilation for.
* Major browsers: Firefox, Chrome, Safari and Edge.
* @property {boolean} [mobileSupport=true]
* If `true`, the configuration will add to the list of major browsers `iOS` and `Android`.
* @property {boolean} [polyfill=true]
* Whether or not the configuration should include the `babel-polyfill` package.
* Whether or not the configuration for the `@babel/preset-env` should include the settings for
* for `useBuiltIns` and `corejs`.
* @property {Object} [overwrites={}]
* If you know how to use Babel and need stuff that is not covered by projext, you can use this
* setting to overwrite/add any value you may need.
* @property {Object} [env={}]
* Custom settings that projext will use as base when generating the ones for the
* `@babel/preset-env`.
*/

/**
Expand Down

0 comments on commit 38ca8ff

Please sign in to comment.