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

babel-preset-env: bump esmodule browserlist to Safari 11 #10225

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

connorjclark
Copy link

ios_saf 10.3 and safari 10.1 do not support the nomodule attribute, so they should not be the minimum constraints when esmodules: true.

It is common to use esmodules: true to split a build into two bundles (one containing fewer polyfills and transformed code - intended for newer browsers - and the other including more code to make old browsers happy), and nomodule is critical for that. I suggest bumping these browserlist constraints to Safari 11, which does support nomodule.

To support these older Safari versions, a few big-cost transforms must be added (list comes from my repro here: https://github.com/connorjclark/babel-esmodule-preset/tree/826e1c83faaa8a62f473179a08f467e575825c3e/src-esmodule). Bumping to 11 will remove all of these:

transform-template-literals { "ios":"10.3", "safari":"10.1" }
transform-unicode-regex { "ios":"10.3", "safari":"10.1" }
transform-block-scoping { "ios":"10.3", "safari":"10.1" }
transform-async-to-generator { "ios":"10.3", "safari":"10.1" }

The async-to-generator transform is especially bad - adds lots of code that is slower than native async/await, even though all browsers that properly support es6 modules also support async/await.

Note @wardpeet originally pointed out that this "build for modern browsers only" pattern doesn't really cut the mustard anymore - there are browsers 3 years old that support modules. However, these changes will at least cut some cruft for those still using this pattern.

[ios_saf](https://github.com/Fyrd/caniuse/blob/bed4faadcea2ec7719c5f43167c0e2dace892be7/features-json/es6-module.json#L318) and [safari](https://github.com/Fyrd/caniuse/blob/master/features-json/es6-module.json#L239) do not support the `nomodule` attribute.

It is common to use `esmodules: true` to split a build into two bundles (one containing fewer polyfills and transformed code - intended for newer browsers - and the other including more code to make old browsers happy), and `nomodule` is critical for that. I suggest bumping these browserlist constraints to Safari 11, which does support `nomodule`.

To support these older Safari versions, a few big-cost transforms and polyfills must be added (list comes from GoogleChrome/web.dev#965). Bumping to 11 will remove all of these:

```
// transforms

transform-template-literals { "ios":"10.3", "safari":"10.1" }
transform-unicode-regex { "ios":"10.3", "safari":"10.1" }
transform-async-to-generator { "ios":"10.3", "safari":"10.1" }

// polyfills

es.array.reverse { "ios":"10.3", "safari":"10.1" }
es.array-buffer.constructor { "ios":"10.3", "safari":"10.1" }
es.array-buffer.slice { "ios":"10.3", "safari":"10.1" }
es.number.parse-float { "ios":"10.3", "safari":"10.1" }
es.string.pad-end { "ios":"10.3", "safari":"10.1" }
es.string.pad-start { "ios":"10.3", "safari":"10.1" }
es.string.trim { "ios":"10.3", "safari":"10.1" }
es.typed-array.float32-array { "ios":"10.3", "safari":"10.1" }
es.typed-array.float64-array { "ios":"10.3", "safari":"10.1" }
es.typed-array.int8-array { "ios":"10.3", "safari":"10.1" }
es.typed-array.int16-array { "ios":"10.3", "safari":"10.1" }
es.typed-array.int32-array { "ios":"10.3", "safari":"10.1" }
es.typed-array.uint8-array { "ios":"10.3", "safari":"10.1" }
es.typed-array.uint8-clamped-array { "ios":"10.3", "safari":"10.1" }
es.typed-array.uint16-array { "ios":"10.3", "safari":"10.1" }
es.typed-array.uint32-array { "ios":"10.3", "safari":"10.1" }
es.typed-array.from { "ios":"10.3", "safari":"10.1" }
es.typed-array.of { "ios":"10.3", "safari":"10.1" }
```

(Note: Will checkout the source code shortly and edit the file that generates this data https://github.com/babel/babel/blob/9febf6388233c3d23d4fa9deca5ca8f682567573/packages/babel-preset-env/scripts/build-modules-support.js#L20)
@developit
Copy link
Member

I thought I'd drop by here to suggest an additional part of this change: currently folks implementing module/nomodule use a well-known Safari Fix to bring nomodule support into Safari 10.

Using the same onbeforeload technique as the original, here's a variant of the fix that treats Safari 11 and prior as nomodule browsers:
https://gist.github.com/developit/463a1ea6f6a92f35ede6eff9599e0684

@connorjclark
Copy link
Author

Looks like these data files moved to https://github.com/babel/babel/blob/master/packages/babel-compat-data/data/native-modules.json

@existentialism it seems your #10742 removes transform-template-literals from the list of applied transforms for esmodules: true, but everything else remained, right?

I'm not 100% caught up on the interplay w/ bugfixes: true #11083. I think it makes this PR completely unnecessary. Is that right @developit?

@developit
Copy link
Member

@connorjclark yes, these are directly covered by bugfixes. I'm mildly unsure of the Unicode regex transform, though I think its already enabled when bugfixes is true.

@nicolo-ribaudo
Copy link
Member

I don't have Safari to test, but if <script type="module" src="./foo.js"> loads ./foo.js in Safari 10.1, then the Babel output for esmodules: true should work in that browser.

@connorjclark
Copy link
Author

I don't have Safari to test, but if <script type="module" src="./foo.js"> loads ./foo.js in Safari 10.1, then the Babel output for esmodules: true should work in that browser.

Oh, that's not the issue. The babel output when esmodules: true is fine and should work in Safari 10.1. This is about reducing the number of transforms when esmodules: true–Safari 10.1 does not support nomodule, yet this plugin considers it as supporting esmodules, which means 1) "cutting the mustard" by using the module/nomodule pattern + this plugin has an edge case where Safari 10.1 would load both bundles; and 2) the "modern" bundle would have many large transforms only because of Safari 10.1.

My take is that Safari 10.1 shouldn't be considered as supporting esmodules because it lacks nomodule (the a in caniuse denotes this). If this "partial support" is ignored, esmodules: true would use fewer large transforms (the Safari constraint is the root cause of the transforms in the original post).

That said, based on @developit's comment the bugfixes: true works around this. I'd like to doublecheck the regex transform first before closing this out, but everything is probably fine :)

@developit
Copy link
Member

One thing to clarify: I beleive Mobile Safari 10.1 supports <script type=module>, but desktop does not (or the other way around, I can never remember).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants