Replies: 3 comments 6 replies
-
I personally prefer solution 1 which is employed by |
Beta Was this translation helpful? Give feedback.
-
Update
Update
|
Beta Was this translation helpful? Give feedback.
-
I am definitely in favor of Solution 1; Solution 2 requires the Some points:
I don't think this is too major of a concern, as long as it's sure to never underpolyfill. Personally I think that even a naive If using In Solution 1, if some method of diffing the polyfill list of the There is also a way to potentially reduce the build time penalty of Solution 1, but similar to Solution 2, it would depend on a feature that does not currently exist: a way to tell the preset-env equivalent to limit the "input level" of its code. Think of it as something similar to tsconfig.json's Similarly to Solution 1, projects targeting only modern-enough browsers would not pay for this second pass; also similarly to Solution 1, only the This does have greater complexity with its own caveats:
|
Beta Was this translation helpful? Give feedback.
-
Background
Next.js has
next-polyfill-nomodule
andnext-polyfill-module
. The implementation detail of the module can be found here:next-polyfill-nomodule
next-polyfill-module
Next.js uses
<script nomodule>
to loadnext-polyfill-nomodule
on unsupported browsers only, and bundlesnext-polyfill-module
in themain
bundle (along with Next.js client-side code).In RFC #33227 (Implemented by #36584), Next.js is starting experiments dropping legacy browsers support.
Pitfalls
The current approach greatly reduces the bundle size when first introduced back in Next.js 9.x. However, it has some problems:
String.prototype.trimStart
,String.prototype.trimEnd
,Array.prototype.flat
, andPromise.prototype.finally
in themain
bundle (because they are all parts ofnext-polyfill-module
), even if a website doesn't use any of those features, or doesn't target legacy browsers.main
bundle even for browsers that support it.Object.fromEntries
). See issues Edge 18 (Object.fromEntries) not supported even with correct polyfills #16715, Rule no-unwanted-polyfillio wrongly reports error on es2019 rule #33072, Update polyfill for eslint no-unwanted-polyfillio rule #33170, and Add Object#fromEntries polyfill (with 6 lines of code) #36426.next-polyfill-module
will continuously increase. ES2020 introducesBigInt
,String.prototype.matchAll
, andPromise.allSettled
, ES2021 introducesString.prototype.replaceAll
,Promise.any
, andWeakRef
. And in June of this year, ES2022 will introduceString.prototype.at
,Array.prototype.at
,TypedArray.prototype.at
, andObject.hasOwn
. The bundle size will become huge even if we only include part of those features' polyfill intonext-module-polyfill
. And once again, not everyone is using all of the new ES features or targets old browsers.core-js
not only provides polyfills for features not supported on legacy browsers but also corrects the behavior for those browsers that implement features incorrectly. For example,core-js
provides a workaround for a critical bug aboutArray.prototype.reduce
introduced in Chrome 80-82, a workaround for a critical bug aboutArray.prototype.reverse
introduced in Safari 12, a workaround for a wrong implementation ofReflect.set
on Edge 18. Since Next.js doesn't usecore-js
(it maintains anext-polyfill-module
), although the bundle size is reduced, the critical bug fixes fromcore-js
is also omitted.Possible Solutions
The proposal is trying to accomplish these goals:
core-js
.Object.hasOwn
is already in ECMAScript stage 4, is shipped in Firefox, Chrome, and Safari 15.4 at the time being, and will be landed in ES2022)Here I propose two solutions:
Solution 1
next-polyfill-nomodule
.browserlist
targets browsers without<script nomodule>
, Next.js should create two different sets of bundles, one set targets legacy browsers that doesn't have<script nomodule>
support, and another set targets modern browsers with<script module>
support. The final emitted HTML will be like this:browserlist
only targets modern browser, Next.js should only create one bundle. The final emitted HTML will be like this:The approach is used by Parcel bundler, and Vue CLI (when creating a new Vue app).
Pros:
env.mode
(Babel'suseBuiltins
).With
mode
set tousage
, SWC / Babel will only include required polyfills.Cons:
According to the SWC's documentation:> Theusage
mode is currently not as efficient as Babel, yet.<script module>
but doesn't support<script nomodule>
, which means Safari 10.1 will download and executed all of the codes.browserlist
that targets legacy browsers, we will have to manually parse and split it into two ranges, one legacy range (for<script nomodule>
) and one modern range (for<script module>
).Solution 2
next-polyfill-nomodule
to include polyfills targeting legacy browsers without<script nomodule>
supports.browserlists
.core-js
to target the modern browsers that support<script nomodule>
.Pros
next-polyfill-nomodule
.Cons
According to the SWC's documentation:> Theusage
mode is currently not as efficient as Babel, yet.core-js
to target only modern browsers.browserlist
that targets legacy browsers, we will have to manually parse and split it into two ranges, one legacy range (when transforming syntax) and one modern range (to include polyfills for modern browsers).cc @kdy1 @styfle @timneutkens @developit
Beta Was this translation helpful? Give feedback.
All reactions