@babel/helper-compilation-targets

@babel/helper-compilation-targets is a helper package that works with compilation targets (browsers or other environments like node) and compat tables (knowing what version supports a specific syntax). It is used by @babel/preset-env to determine which plugin should be enabled based on the targets option.

  1. import {
  2. filterItems,
  3. default as getTargets,
  4. isRequired,
  5. } from "@babel/helper-compilation-targets";

filterItems

  1. function filterItems(
  2. list: { [feature: string]: Targets },
  3. // A set of plugins that should always be included
  4. includes: Set<string>,
  5. // A set of plugins that should always be excluded
  6. excludes: Set<string>,
  7. targets: Targets,
  8. // A set of plugins that should always be included if `includes` is empty
  9. defaultIncludes: Array<string> | null,
  10. // A set of plugins that should always be excluded if `excludes` is empty
  11. defaultExcludes?: Array<string> | null,
  12. // A map from transform plugin to syntax plugin for backward compatibility with older `@babel/parser` versions
  13. pluginSyntaxMap?: Map<string, string | null>
  14. ): Set<string>; // A set of enabled plugins

Given a compat data table list (i.e. @babel/compat-data) and browser targets targets, return a set of required plugins.

Example

  1. const compatData = {
  2. "transform-feature-1": {
  3. chrome: "1",
  4. firefox: "1",
  5. },
  6. "transform-feature-2": {
  7. chrome: "2",
  8. firefox: "2",
  9. },
  10. "transform-feature-3": {
  11. chrome: "3",
  12. firefox: "3",
  13. },
  14. "transform-feature-4": {
  15. chrome: "4",
  16. firefox: "4",
  17. },
  18. };
  19. // filter a set of plugins required when compiled to chrome 2
  20. // returns new Set(["transform-feature-3", "transform-feature-4"])
  21. filterItems(compatData, new Set(), new Set(), {
  22. chrome: 2,
  23. });
  24. // filter a set of plugins required when compiled to chrome 2 and firefox 1
  25. // returns new Set(["transform-feature-2", "transform-feature-3", "transform-feature-4"])
  26. filterItems(compatData, new Set(), new Set(), {
  27. chrome: 2,
  28. firefox: 1,
  29. });
  30. // always include "transform-feature-2" and exclude "transform-feature-4"
  31. // returns new Set(["transform-feature-2", "transform-feature-3"])
  32. filterItems(
  33. compatData,
  34. new Set(["transform-feature-2"]),
  35. new Set(["transform-feature-4"]),
  36. {
  37. chrome: 2,
  38. }
  39. );
  40. // syntax-feature-2 is required to allow older @babel/parser to parse
  41. // the feature-2 syntax supported in chrome 2
  42. // returns new Set(["syntax-feature-2", "transform-feature-3", "transform-feature-4"])
  43. filterItems(
  44. compatData,
  45. new Set(),
  46. new Set(),
  47. {
  48. chrome: 2,
  49. },
  50. null,
  51. null,
  52. new Map([["transform-feature-2", "syntax-feature-2"]])
  53. );

When a new ES feature reaches stage-4, it will be matured in @babel/parser, which means it will always be parsed regardless of the plugin. However we need the syntax plugin for older @babel/parser.

getTargets

  1. type GetTargetsOption = {
  2. // This is not the path of the config file, but the path where start searching it from
  3. configPath?: string;
  4. // The path of the config file
  5. configFile?: string;
  6. // The env to pass to browserslist
  7. browserslistEnv?: string;
  8. // true to disable config loading
  9. ignoreBrowserslistConfig?: boolean;
  10. };
  11. type InputTargets = {
  12. ...Targets,
  13. browsers?: Browsers,
  14. // When `true`, this completely replaces the `browsers` option.
  15. // When `intersect`, this is intersected with the `browsers`
  16. // option (giving the higher browsers as the result).
  17. esmodules?: boolean | "intersect",
  18. };
  19. function getTargets(
  20. inputTargets: InputTargets = {},
  21. options: GetTargetsOption = {}
  22. ): Targets;

Normalize user specified targets to a list of supported targets. See also (@babel/preset-env)[preset-env.md#options] for GetTargetsOption

Example

  1. // Return the default compilation targets
  2. // returns {}
  3. getTargets();

An empty compilation target is equivalent to force all transforms. The default compilation targets will be changed to browserlists query defaults, not IE 11 in Babel 8.

One can also query the compilation targets with ES Module support, like @vue/babel-preset-app did in order to provide a set of modern targets.

  1. /* returns {
  2. "android": "61.0.0",
  3. "chrome": "61.0.0",
  4. "edge": "16.0.0",
  5. "firefox": "60.0.0",
  6. "ios": "10.3.0",
  7. "node": "13.2.0",
  8. "opera": "48.0.0",
  9. "safari": "10.1.0",
  10. "samsung": "8.2.0",
  11. } */
  12. getTargets({
  13. esmodules: true,
  14. });

Note: The ES Module compat data is generated from MDN.

isRequired

  1. function isRequired(
  2. name: string,
  3. targets: Targets,
  4. {
  5. compatData = pluginsCompatData,
  6. includes,
  7. excludes,
  8. }: {
  9. compatData?: { [feature: string]: Targets };
  10. includes?: Set<string>;
  11. excludes?: Set<string>;
  12. } = {}
  13. ): boolean;

Given browser targets targets, query the compatData whether plugin name is required for compilation. When compatData is not specified, the default data source is @babel/compat-data

Example

  1. // babel.config.js
  2. module.exports = api => {
  3. const targets = api.targets();
  4. // The targets have native optional chaining support
  5. // if `proposal-optional-chaining` is _not_ required
  6. const optionalChainingSupported = !isRequired(
  7. "proposal-optional-chaining",
  8. targets
  9. );
  10. };

Plugin authors can use isRequired to optimize plugin output given different targets:

  1. // a naive plugin replace `a.b` to `a != null && a.b`
  2. module.exports = api => {
  3. const targets = api.targets();
  4. // The targets have native optional chaining support
  5. // if `proposal-optional-chaining` is _not_ required
  6. const optionalChainingSupported = !isRequired(
  7. "proposal-optional-chaining",
  8. targets
  9. );
  10. const visited = new WeakSet();
  11. return {
  12. visitor: {
  13. MemberExpression(path) {
  14. if (path.matchesPattern("a.b")) {
  15. if (visited.has(path.node)) return;
  16. visited.add(path.node);
  17. if (optionalChainingSupported) {
  18. // When optional chaining is supported,
  19. // output `a?.b` instead of `a != null && a.b`
  20. path.replaceWith(api.templates`a?.b`);
  21. } else {
  22. path.replaceWith(api.templates`a != null && ${path.node}`);
  23. }
  24. }
  25. },
  26. },
  27. };
  28. };

@babel/plugin-proposal-object-rest-spread uses isRequired to determine whether targets already have native Object.assign support.