Add preset-env target esmodules (#7212)

This commit is contained in:
Kristofer Baxter 2018-01-22 13:44:10 -08:00 committed by Brian Ng
parent dccfed3601
commit b3969d35fa
7 changed files with 182 additions and 1 deletions

View File

@ -30,6 +30,22 @@ This example only includes the polyfills and code transforms needed for the last
}
```
You may also target browsers supporting ES Modules (https://www.ecma-international.org/ecma-262/6.0/#sec-modules). When specifying this option, the browsers field will be ignored. You can use this approach in combination with `<script type="module"></script>` to conditionally serve smaller scripts to users (https://jakearchibald.com/2017/es-modules-in-browsers/#nomodule-for-backwards-compatibility).
*Please note*: when specifying the esmodules target, browsers targets will be ignored.
```json
{
"presets": [
["@babel/preset-env", {
"targets": {
"esmodules": true
}
}]
]
}
```
Similarly, if you're targeting Node.js instead of the browser, you can configure @babel/preset-env to only include the polyfills and transforms necessary for a particular version:
```json

View File

@ -0,0 +1,8 @@
{
"es6.module": {
"edge": "16",
"chrome": "61",
"safari": "10.1",
"ios_saf": "10.3"
}
}

View File

@ -8,7 +8,7 @@
"repository": "https://github.com/babel/babel/tree/master/packages/babel-preset-env",
"main": "lib/index.js",
"scripts": {
"build-data": "node ./scripts/build-data.js"
"build-data": "node ./scripts/build-data.js; node ./scripts/build-modules-support.js"
},
"dependencies": {
"@babel/plugin-check-constants": "7.0.0-beta.38",
@ -59,6 +59,7 @@
"@babel/helper-fixtures": "7.0.0-beta.38",
"@babel/helper-plugin-test-runner": "7.0.0-beta.38",
"compat-table": "kangax/compat-table#3e30cd67a5d3d853caf8424d00ca66d100674d4f",
"request": "^2.83.0",
"electron-to-chromium": "^1.3.27"
}
}

View File

@ -0,0 +1,70 @@
const path = require("path");
const fs = require("fs");
const request = require("request");
// This mapping represents browsers who have shipped ES Modules Support.
// For more information, checkout the specifications:
// * https://www.ecma-international.org/ecma-262/6.0/#sec-modules
// * https://html.spec.whatwg.org/multipage/scripting.html#attr-script-type
const lastKnown = {
chrome: 61,
firefox: 59,
safari: 10.1,
ios_saf: 10.3,
edge: 16,
};
function input() {
return new Promise(function(resolve, reject) {
request(
"https://raw.githubusercontent.com/Fyrd/caniuse/master/features-json/es6-module.json",
function(error, response, body) {
if (error || response.statusCode !== 200) {
return reject(
new Error(
`Error retrieving es6-module.json. ${
error ? error : `statusCode=${response.statusCode}`
}`
)
);
}
try {
const { stats } = JSON.parse(body);
const allowedBrowsers = {};
Object.keys(stats).forEach(browser => {
if (browser !== "and_chr") {
const browserVersions = stats[browser];
const allowedVersions = Object.keys(browserVersions)
.filter(value => {
return browserVersions[value] === "y";
})
.sort((a, b) => a - b);
if (allowedVersions[0] !== undefined) {
allowedBrowsers[browser] = allowedVersions[0];
}
}
});
resolve(allowedBrowsers);
} catch (error) {
return reject(new Error(`Error parsing es6-module.json.`));
}
}
);
});
}
function output(minVersions) {
const dataPath = path.join(__dirname, "../data/built-in-modules.json");
const data = {
"es6.module": minVersions,
};
fs.writeFileSync(dataPath, `${JSON.stringify(data, null, 2)}\n`);
}
Promise.resolve(input())
.then(minVersions => output(minVersions))
.catch(output(lastKnown));

View File

@ -183,6 +183,17 @@ export default function buildPreset(
console.log("");
}
if (optionsTargets && optionsTargets.esmodules && optionsTargets.browsers) {
console.log("");
console.log(
"@babel/preset-env: esmodules and browsers targets have been specified together.",
);
console.log(
`\`browsers\` target, \`${optionsTargets.browsers}\` will be ignored.`,
);
console.log("");
}
const targets = getTargets(optionsTargets, {
ignoreBrowserslistConfig,
configPath,

View File

@ -4,6 +4,7 @@ import browserslist from "browserslist";
import semver from "semver";
import { semverify, isUnreleasedVersion, getLowestUnreleased } from "./utils";
import { objectToBrowserslist } from "./normalize-options";
import browserModulesData from "../data/built-in-modules.json";
import type { Targets } from "./types";
const browserNameMap = {
@ -109,6 +110,15 @@ type ParsedResult = {
};
const getTargets = (targets: Object = {}, options: Object = {}): Targets => {
const targetOpts: Targets = {};
// `esmodules` as a target indicates the specific set of browsers supporting ES Modules.
// These values OVERRIDE the `browsers` field.
if (targets.esmodules) {
const supportsESModules = browserModulesData["es6.module"];
targets.browsers = Object.keys(supportsESModules)
.map(browser => `${browser} ${supportsESModules[browser]}`)
.join(", ");
}
// Parse browsers target via browserslist;
const queryIsValid = isBrowsersQueryValid(targets.browsers);
const browsersquery = queryIsValid ? targets.browsers : null;
@ -121,6 +131,7 @@ const getTargets = (targets: Object = {}, options: Object = {}): Targets => {
}
// Parse remaining targets
const parsed = Object.keys(targets)
.filter(value => value !== "esmodules")
.sort()
.reduce(
(results: ParsedResult, target: string): ParsedResult => {

View File

@ -78,6 +78,70 @@ describe("getTargets", () => {
});
});
describe("esmodules", () => {
it("returns browsers supporting modules", () => {
assert.deepEqual(
getTargets({
esmodules: true,
}),
{
chrome: "61.0.0",
safari: "10.1.0",
ios: "10.3.0",
edge: "16.0.0",
},
);
});
it("returns browsers supporting modules, ignoring browsers key", () => {
assert.deepEqual(
getTargets({
esmodules: true,
browsers: "ie 8",
}),
{
chrome: "61.0.0",
safari: "10.1.0",
ios: "10.3.0",
edge: "16.0.0",
},
);
});
it("returns browser supporting modules and keyed browser overrides", () => {
assert.deepEqual(
getTargets({
esmodules: true,
ie: 11,
}),
{
chrome: "61.0.0",
safari: "10.1.0",
ios: "10.3.0",
ie: "11.0.0",
edge: "16.0.0",
},
);
});
it("returns browser supporting modules and keyed browser overrides, ignoring browsers field", () => {
assert.deepEqual(
getTargets({
esmodules: true,
browsers: "ie 10",
ie: 11,
}),
{
chrome: "61.0.0",
safari: "10.1.0",
ios: "10.3.0",
ie: "11.0.0",
edge: "16.0.0",
},
);
});
});
describe("node", () => {
it("should return the current node version with option 'current'", () => {
assert.deepEqual(