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
Only reference helpers from external/runtime helpers if they are known to be available. #8398
Conversation
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/8753/ |
export default helpers; | ||
|
||
helpers.typeof = () => template.program.ast` | ||
"minVersion: 7.0.0-beta.0"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
imho it's slightly weird to use directive-like for this, making it a property of the helper (or wrapping helpers in objects with this and smth like create
method) would make it less magical
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, what about helpers.typeof.minVersion = "7.0.0-beta.0"
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was being lazy :P Since none of this is actually part of the public API, I figured refactoring it later would be trivial. I'll see if I can make it better now though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this PR allow us to introduce breaking change to the helpers, by incrementing the minVersion
?
throw new Error( | ||
"Babel 7.0.0-beta.56 has dropped support for the 'helpersNamespace' utility." + | ||
"If you are using @babel/plugin-external-helpers you will need to use a newer " + | ||
"version than the one you currently have installed.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This error message should suggest plugin authors to use helperGenerator
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call.
return ( | ||
typeof versionRange !== "string" || | ||
(!semver.intersects(`<${minVersion}`, versionRange) && | ||
!semver.intersects(`>=8.0.0`, versionRange)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this second check needed? Some helpers almost never change (e.g. the typeof
one), so I would expect it to be possible that some helpers are compatible even between major versions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My concern is that while that is indeed likely, it's not a given. Changing a helper in a breaking way in a new major version is still entirely possible, so my limiting this range clearly, we can be sure that if someone has @babel/core@8
installed, and they try to use @babel/runtime@7.3
or whatever, we'll just inline the helpers instead of inserting the runtime imports.
} | ||
|
||
return ( | ||
typeof versionRange !== "string" || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this should also work with integers, like the api.assertVersion
function does?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could, though I'm not sure it's worth it. This is an API I don't think many will use, and always expecting semver strings does simplify things a bit.
@@ -14,6 +14,7 @@ export default declare((api, options) => { | |||
regenerator, | |||
useBuiltIns, | |||
useESModules, | |||
version: runtimeVersion = "7.0.0-beta.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In availableHelper
is versionRange is optional, could we omit the default argument here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In availableHelper
, if you omit the version, it just checks if the helper exists in the current version of core, rather than if it was historically available at a particular version. If we left this blank, we'd essentially always insert the helper imports, even when it was invalid.
export default helpers; | ||
|
||
helpers.typeof = () => template.program.ast` | ||
"minVersion: 7.0.0-beta.0"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, what about helpers.typeof.minVersion = "7.0.0-beta.0"
?
packages/babel-helpers/src/index.js
Outdated
@@ -247,6 +252,15 @@ function loadHelper(name) { | |||
globals: metadata.globals, | |||
}; | |||
}, | |||
minVersion() { | |||
return fn() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And following my previous comment. Here: fn.minVersion
.
156c1dd
to
4042fcd
Compare
No, that's not my intention with this PR, but what it will allow us to do is add a new helper with a new API, and use that new helper as a replacement for the old one in a safe way. |
4042fcd
to
5cfd383
Compare
5cfd383
to
adca165
Compare
…ey are known to be available.
6de201e
to
e2d64f1
Compare
I am implementing .babelrc file{
"presets": [
[
"env",
{
"modules": false
}
]
],
"plugins": [
"external-helpers"
]
} package.json"devDependencies": {
"@babel/core": "^7.0.0",
"babel-plugin-external-helpers": "^6.22.0",
"babel-preset-env": "^1.7.0",
"eslint": "^5.4.0",
"eslint-config-prettier": "^3.0.1",
"eslint-config-standard": "^12.0.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-node": "^7.0.1",
"eslint-plugin-prettier": "^2.6.2",
"eslint-plugin-promise": "^4.0.0",
"eslint-plugin-standard": "^4.0.0",
"prettier": "1.14.2",
"rollup": "^0.65.0",
"rollup-plugin-babel": "^4.0.2",
"rollup-plugin-size-snapshot": "^0.6.1"
} |
You can use |
@nico29 I changed my EDIT: I also updated to Updated .babelrc
|
Babel by default injects the helpers in every file. |
Just to add what kinda got already said - Need to update rollup docs (had no idea they have section about this) to explain difference between configuring for babel@6 and babel@7. |
Why
This PR aims to resolve a specific problem. Babel's helpers live as part of
@babel/core
conceptually, or indirectly from@babel/helpers
, but when users use@babel/plugin-transform-runtime
or@babel/plugin-external-helpers
, the helpers actually load from a static file like@babe/runtime/helpers/classCallCheck
.While very handy, this has the downside that we don't actually know what version of a helper we're going to get, and even more frustratingly, we don't actually know if the helper even exists in the runtime, for instance if we've recently added new helpers. In 6.x, this meant that we could add a new transform for instance, along with a helper for it, but users using
@babel/runtime
would get the extremely unhelpful error that their import didn't find the file.It also meant that there was literally no way for a plugin to check if a helper was available. If
transform-runtime
or similar plugin was enabled, any attempt to load a helper would insert a reference, even if it was totally broken, or you'd just typoed the name of a helper or something.This PR aims to resolve that problem by changing the expectations around intercepting runtime helper loading. If an override function is given, it is that function's responsibility to only insert a reference to a helper if it knows the helper exists. That means that plugins themselves can more easily evolve over time. For instance, a plugin can attempt to add a helper, and if it doesn't exist, it could fall back to inserting a different helper instead, or it could provide useful feedback to users saying that they'll need to update their version of
@babel/core
in order to use this new helper.How
This PR accomplishes it's goal by having
@babel/core
itself be a source of truth for what helpers exist, and what helpers became available when. When a user doesthey are declaring "load all helpers from the runtime, BUT only if they were available at the release of whichever version this PR lands in.
What this means is that, in the future if we make a new plugin with some new helper, it will not be loaded via the runtime at all. It would be up to the user to explicitly do
to essentially say "I promise that I have version 7.4.2 of
@babel/runtime
available, so any helpers that existed in7.4.2
are free to be loaded from this runtime.Downsides
The main downside of this approach is that it's more work for users to have to manually provide the version. In a perfect world, I'd love for
@babel/transform-runtime
to actually try to look at the user'spackage.json
or something, and I thought about doing that for this PR, but I ended up deciding that it complicated things too much for now. We can always explore adding it as an opt-in feature during 7.x's lifetime.