-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
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
Add preset-env target esmodules #7212
Conversation
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/6676/ |
Love the idea ❤️ ! |
@@ -78,6 +78,22 @@ describe("getTargets", () => { | |||
}); | |||
}); | |||
|
|||
describe("esmodules", () => { | |||
it("returns browsers supporting modules", () => { |
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.
Can we add a test that covers the "override browsers" behavior?
Sidenote: should we warn when a user does esmodules and browsers?
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.
Makes sense to add this test. Will do.
Good question on warning: what semantics are the guiding rule for warnings within Babel?
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.
Added this test in 15e2672.
targets.browsers = Object.keys(supportsESModules) | ||
.map(browser => `${browser} ${supportsESModules[browser]}`) | ||
.join(", "); | ||
} |
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.
The main worry I'd have with this approach is that, at least for now, all those browsers are very fresh.
But I guess I'll only have to worry about cutting old browsers with this feature in 3~5 years so I guess it's a bit premature to worry.
Possible future addition: plugin that rewrites import strings into resolved relative paths; it's necessary to actually be able to load these files in browsers. |
As a user, here's some bikeshedding:
|
It's likely I am confused about how In this model, adding a target of As browsers continue to implement features the number of items requiring transpilation under this definition would grow. I believe this makes sense given usage targetting the Agree this is confusing, and would love some additional options around naming. Edits: Poor grammar, sorry :( |
What if, for example, I only want to support Chrome versions which have esmodules support? Something like this should work: {
"presets": [["@babel/preset-env", {
"targets": {
"esmodules": true,
"browsers": ["Chrome"]
}
}]] |
@nicolo-ribaudo Right now that is not supported by this PR. Making I can see a good reason for allowing intersection between the values Would your recommendation be to add this kind of complexity across the board? How would one specify intersection types? i.e start with Edit: Here's how one would target Chrome versions targetting esmodules today, and with this change. presets: [
[
'@babel/env', {
targets: ["Chrome 61"]
}
],
] |
I've had a custom implementation of split module/nomodule bundles on a branch for a while. This would alleviate much of the work that's kept it as a proof of concept. I wonder if there could be confusion on using this mostly as a gate for "modern browsers" rather than for actual module scripts. |
If, for example, my config is {
"targets": {
"esmodules": true,
"browsers": ["Chrome 63"]
}
} I don't expect Babel to output code which works in Chrome 61, since I explicitly chose Chrome 63.
Yes. From my understanding, this option means "I will import the file using I'm not 100% sure of how this would work on node, since it doesn't have
This would require users to know which browsers support esmodules, which is exactly the duty that preset-env takes away from the developer. Update: when in the debug mode, preset-env should log the browsers that would be discarded because of |
@greggb – Hopeful that this path is good for exactly the use-case you presented. @nicolo-ribaudo – The intersection work you're describing sounds like a great followup to this work. But I'd like to make sure the syntax is well understood.
{
"targets": {
"esmodules": true
}
}
{
"targets": {
"esmodules": {
"browsers": ["Chrome 63"]
}
}
}
{
"targets": {
"esmodules": true,
"browsers": ["Chrome 63"]
}
}
Edit: Looks like you can already do this override (thanks @simonbuchan and @existentialism), and it works as expected. {
"targets": {
"esmodules": true,
"chrome": 63
}
} |
I'd be OK with the current behavior with it also validating you only used one of |
That isn't ideal from a learning perspective, but that's because there's only One Right Thing™ - there's no point creating code that will only run in the non-existent intersection of Chrome and Firefox! It's less obvious why this flag and other targets should only ever be an intersection. Assuming that this flag should only be set if you have another If you are only targeting module, it could be because you don't care about further optimizations, which is the current PR, but it could be you already have browsers you want to target, but want to ensure that those do support module so you can drop your nomodule bundle. Regardless, I think the name also matters, and I don't like that it is confusable with top-level I'm not a huge fan, but how do people feel about // .babelrc.js
const browsers = ['last 2 versions'];
module.exports = api => {
switch (api.env()) { // .env key is deprecated in 7
default: return { presets: ['env', { targets: { node: true } }] };
case 'ie': return { presets: ['env', { module: false, targets: { ie: 11 } }] };
case 'nomodule': return { presets: ['env', { module: false, targets: { browsers } }] };
case 'module': return { presets: ['env', { module: false, targets: { scriptType: 'module', browsers } }] };
}
};
The last one is interesting in that it adds a use for intersecting in |
The current behavior has all other items in targets ( Also need to consider how the target works alongside other explicit targets, like the following: {
"targets": {
"esmodules": true,
"chrome": "63"
}
} |
Override is intuitive for the browser names targets, as they are clearly more specific than the likely browserlist queries (you could do something bizarre like |
But all of that can still be explained as "whatever comes out of browsers result is overridden by whatever you set explicitly, node included". I'm not arguing that this is great or the end all be all api/behavior, I'm just stating that this is what we have currently and doing something differently just seems to make it even more confusing. I mean, we could just as easily move it to a flag outside targets (like uglify -> forceAllTransforms) and have it just override anything placed in targets. |
@simonbuchan and @existentialism – Thanks for calling out the targets option for specific browser name/value combinations. I'm creating a test and fixing the issue. Will update this PR afterwards. |
@existentialism – I've added a test specifically for the case of providing it("returns browser supporting modules and keyed browser overrides", () => {
... {
esmodules: true,
ie: 11,
}... ); Also a test for Thanks for pointing this case out! See f2264c3 |
Would it be better for the ecosystem to add a new |
browserlist can't do |
Regarding browserlist, the owner replied to a similar question about the websocket feature with "Use caniuse-api", which this PR does. Looking at it that way, I suppose you could look at this like a features query: Still has the issue of how it interacts with |
@existentialism and @simonbuchan – Is there anything else that should be done before this PR can be accepted? |
I personally would like:
How do you feel about the That said, I'm just a guy, "should" doesn't really apply :) |
👍
I actually prefer the
Your input for this PR is highly appreciated 😉 |
It would be cool because ideally, we want If we'll have +1 for the |
Also, like an idea. What if we'll rethink a bit about implementation of these PRs? For example: {
targets: {
// will use targets that support es2017 and type="module". maybe some new templates in the future. if both template has same target, then use the lowest one.
use: ['es2017', 'esmodules'],
// overrides chrome version to 60.
chrome: 60,
// ??? See other idea below
browsers: '> 2%'
}
} The other idea is to use browsers values like other templates, because actually {
targets: {
/* will use targets that support es2017, type="module",
all browsers with >2% usage and ie11. All templates will be safely merged
and selected the lowest
target. Also, we can extend this with values isn't supported
by browserslist, like node.
*/
use: ['es2017', 'esmodules', '>2%', 'ie 11', 'current node'],
// overrides chrome version to 60.
chrome: 60,
// deprecated.
browsers: ['chrome 60']
}
} cc @existentialism @Kovensky @nicolo-ribaudo |
@yavorsky I'm not opposed to extending What if we land this as is with the addition of an error if |
@existentialism Sure!
Maybe just leave minimal value for conflicts with |
@yavorsky works for me /cc: @kristoferbaxter! |
Sounds straightforward, a warning for when browsers target is ignored because esmodules is present. Will add this over the weekend. |
Messaging added – let's get this merged and I'll modify the repl to include the option! |
@kristoferbaxter thanks! Thanks for the great discussion @simonbuchan and everyone! Let's continue in a new issue discussing options for adding a more flexible target syntax? |
This PR adds a new feature to Babel's
preset-env
allowing a developer to target a class of browsers that support<script type="module">
and transpile only what is necessary.Two important notes:
Specifying a target of esmodules overrides the target field
browsers
, to avoid conditions where additional specification of browsers would make the bundle increase in size. It expected that one would leverage this feature like https://github.com/kristoferbaxter/preset-env-modules/blob/master/.babelrc.js does... creating a bundle for ESModule only capable browsers, and one for other browsers. Edit: You may continue to override the values specified bybrowsers
andesmodules
targets via named browser keys. ({esmodules: true, ie: 10}
includes ie 10 in the list).Leverages CanIUse data by requesting the latest JSON payload for this feature when building new data (similar to compat-table already in use). Compat-table doesn't contain this information, so a different pathway was required to keep the data up to date.
request
and on CanIUse for up-to-date data on browsers supporting es modules.