Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow preset-env to specify custom core-js package name #10379

Open
otakustay opened this issue Aug 31, 2019 · 4 comments

Comments

@otakustay
Copy link

commented Aug 31, 2019

Feature Request

Is your feature request related to a problem? Please describe.

When babel is encapsulated in a custom tool, we'd like to prevent users install core-js themselves, instead we shipped a core-js@3 along with out tool including a babel configuration.

In this case, if user or another package installed by user requires a core-js with different version and is also hoisted, babel will import the wrong version of core-js since it simply create imports like core-js/modules/foo.

Describe the solution you'd like

Make preset-env accepts an corejs.packageName like:

[
  'preset-env',
  {
    corejs: {
      version: 3,
      packageName: require.resolve('core-js') // use specified one
    }
  }
]

Describe alternatives you've considered

We can also use webpack's alias to lock the core-js path but it only works with webpack.

Teachability, Documentation, Adoption, Migration Strategy

This should be completely backward compatible

@babel-bot

This comment has been minimized.

Copy link
Collaborator

commented Aug 31, 2019

Hey @otakustay! We really appreciate you taking the time to report an issue. The collaborators on this project attempt to help as many people as possible, but we're a limited number of volunteers, so it's possible this won't be addressed swiftly.

If you need any help, or just have general Babel or JavaScript questions, we have a vibrant Slack community that typically always has someone willing to help. You can sign-up here for an invite.

@TrejGun

This comment has been minimized.

Copy link

commented Sep 1, 2019

Just don't forget to include original message to your custom build 🤣

@nicolo-ribaudo

This comment has been minimized.

Copy link
Member

commented Sep 2, 2019

Currently you can implement it yourself using a custom plugin and a really ugly workaround.
core-js imports are injected after that the program transformation is finished, and it is inside a preset which is run before the plugins.
For this reason, you need to create a preset which contains a plugin which runs after that the transformation is finished, and place it before preset-env in your config:

// babel.config.js

module.exports = {
  presets: [
    presetRenameCoreJS,
    ["@babel/preset-env", { "useBuiltIns": "usage", "corejs": 3 }]
  ]
};

function presetRenameCoreJS() {
  return { plugins: [pluginRenameCoreJS] };
}

function pluginRenameCoreJS() {
  function replaceSource(source) {
    source.value = source.value.replace(/^core-js/, "custom-core-js");
  }

  return {
    post({ path }) {
      path.traverse({
        ImportDeclaration(path) {
          replaceSource(path.node.source);
        },
        CallExpression(path) {
          if (
            path.get("callee").isIdentifier({ name: "require" }) &&
            path.node.arguments.length === 1 &&
            path.get("arguments.0").isStringLiteral()
          ) {
            replaceSource(path.node.arguments[0]);
          }
        },
      });
    },
  };
}

When #10142 is fixed (pr: #10146) it will be simpler:

// babel.config.js

module.exports = {
  presets: [
    ["@babel/preset-env", { "useBuiltIns": "usage", "corejs": 3 }]
  ],
  plugins: [
    pluginRenameCoreJS
  ]
};

function pluginRenameCoreJS() {
  function replaceSource(source) {
    source.value = source.value.replace(/^core-js/, "custom-core-js");
  }

  function isRequire(path) {
    if (!path.get("callee").isIdentifier({ name: "require" })) return false;
    if (path.node.arguments.length === 0) return false;
    if (!path.get("arguments.0").isStringLiteral()) return false;
    return true;
  }

  return {
    visitor: {
      ImportDeclaration(path) {
        replaceSource(path.node.source);
      },
      CallExpression(path) {
        if (isRequire(path)) {
          replaceSource(path.node.arguments[0]);
        }
      },
    },
  };
}
@otakustay

This comment has been minimized.

Copy link
Author

commented Sep 4, 2019

@nicolo-ribaudo 's solution works fine, so this issue can be closed if this feature would not be supported officially.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants
You can’t perform that action at this time.