-
-
Notifications
You must be signed in to change notification settings - Fork 7.2k
Description
Clear and concise description of the problem
The current implementation of plugin-legacy
forces dynamic-import
as the modern target (which means, browser supporting dynamic-import
will load the modern bundle and others will load the legacy bundle).
But the proportion of browsers that support newer feature is gradually increasing so we can choose a higher feature as the modern target to decrease the bundle size of "modern" target. For the browsers have no support for the given feature, let them load the legacy bundle.
Additionally, we uses @babel/preset-env
which generates too many polyfills (even for modern build). For example, if we used new URL
in default target (esmodules: true
), it generates URL polyfill since Safari < 14 implements URLSearchParams.prototype.delete
wrongly. But in most cases we won't care of this so we won't need a 100% right polyfill.
Suggested solution
We already generate code to test legacy/modern browsers. We can change to provide an option to customize it:
interface Options {
/**
* JS code to test if the current running browser should use the modern build. Should throw exception if not.
*
* @default `"import('data:text/javascript,')"`
*/
modernFeatureTestCode?: string
/**
* A browserslist of target we build the modern bundle for. Used for modern polyfills generation.
*
* @default A browserslist with support for ES6 dynamic import.
*/
modernTargets?: string;
}
Then generate the testing and gate-keeping code like:
const defaultModernFeatureTestCode = "import('data:text/javascript,')"
const getFallbackInlineCode = (featureTestCode) => `!function(){try{new Function("",${JSON.stringify(featureTestCode)})()}catch(o){console.warn("vite: loading legacy build because required features are unsupported, errors above should be ignored");var e=document.getElementById("${legacyPolyfillId}"),n=document.createElement("script");n.src=e.src,n.onload=function(){${systemJSInlineCode}},document.body.appendChild(n)}}();`
const getModernGatekeepingCode = (featureTestCode) => `export function __vite_legacy_guard(){${featureTestCode}};__vite_legacy_guard();`
For example, if I want to target browsers supporting Object.fromEntries
, we could use:
{
modernTargets: browsersWithSupportForFeatures( // From package `browserslist-generator`
"es6-module-dynamic-import",
"javascript.builtins.Object.fromEntries"
),
modernFeatureTestCode: "import('data:text/javascript,');Object.fromEntries([])"
}
Additionally, we could accept two functions to filter-out the polyfills we don't want to exclude:
interface Options {
// Pass a function for auto detection, which returns false to exclude a polyfill.
polyfills?: boolean | string[] | ((polyfill: string) => boolean)
modernPolyfills?: boolean | string[] | ((polyfill: string) => boolean)
}
Alternative
Change the way of "testing if the client browser should use modern build" to just test if it matches a browserslist. But it may be hard to do this in a code snippet in index.html
.
Additional context
I have implemented all I mentioned features and ready for creating a pull request.
Validations
- Follow our Code of Conduct
- Read the Contributing Guidelines.
- Read the docs.
- Check that there isn't already an issue that request the same feature to avoid creating a duplicate.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status