@kolibryjs/legacy-plugin v0.0.1
🐦 @kolibryjs/legacy-plugin 
Kolibry's default browser support baseline is Native ESM, native ESM dynamic import, and import.meta. This plugin provides support for legacy browsers that do not support those features when building for production.
By default, this plugin will:
🔄 Generate a corresponding legacy chunk for every chunk in the final bundle, transformed with @babel/preset-env and emitted as SystemJS modules (code splitting is still supported!).
🔌 Generate a polyfill chunk including SystemJS runtime, and any necessary polyfills determined by specified browser targets and actual usage in the bundle.
💉 Inject
<script nomodule>tags into generated HTML to conditionally load the polyfills and legacy bundle only in browsers without widely-available features support.💉 Inject the
import.meta.env.LEGACYenv variable, which will only betruein the legacy production build, andfalsein all other cases.
Usage
// kolibry.config.js
import legacy from '@kolibryjs/legacy-plugin'
export default {
plugins: [
legacy({
targets: ['defaults', 'not IE 11'],
}),
],
}Terser must be installed because legacy-plugin uses Terser for minification.
npm add -D terser🖥️ Options
🎯 targets
- Type:
string | string[] | { [key: string]: string } Default:
'last 2 versions and not dead, > 0.3%, Firefox ESR'If explicitly set, it's passed on to
@babel/preset-env.The query is also Browserslist compatible. See Browserslist Best Practices for more details.
🛠️ polyfills
- Type:
boolean | string[] Default:
trueBy default, a polyfills chunk is generated based on the target browser ranges and actual usage in the final bundle (detected via
@babel/preset-env'suseBuiltIns: 'usage').Set to a list of strings to explicitly control which polyfills to include. See Polyfill Specifiers for details.
Set to
falseto avoid generating polyfills and handle it yourself (will still generate legacy chunks with syntax transformations).
🧩 additionalLegacyPolyfills
Type:
string[]Add custom imports to the legacy polyfills chunk. Since the usage-based polyfill detection only covers ES language features, it may be necessary to manually specify additional DOM API polyfills using this option.
Note: if additional polyfills are needed for both the modern and legacy chunks, they can simply be imported in the application source code.
🚫 ignoreBrowserslistConfig
- Type:
boolean Default:
false@babel/preset-envautomatically detectsbrowserslistconfig sources:browserslistfield inpackage.json.browserslistrcfile in cwd.
Set to
falseto ignore these sources.
🔧 modernPolyfills
- Type:
boolean | string[] Default:
falseDefaults to
false. Enabling this option will generate a separate polyfills chunk for the modern build (targeting browsers with native ESM support).Set to a list of strings to explicitly control which polyfills to include. See Polyfill Specifiers for details.
Note it is not recommended to use the
truevalue (which uses auto-detection) becausecore-js@3is very aggressive in polyfill inclusions due to all the bleeding edge features it supports. Even when targeting native ESM support, it injects 15kb of polyfills!If you don't have hard reliance on bleeding edge runtime features, it is not that hard to avoid having to use polyfills in the modern build altogether. Alternatively, consider using an on-demand service like Polyfill.io to only inject necessary polyfills based on actual browser user-agents (most modern browsers will need nothing!).
🧱 renderLegacyChunks
- Type:
boolean Default:
trueSet to
falseto disable legacy chunks. This is only useful if you are usingmodernPolyfills, which essentially allows you to use this plugin for injecting polyfills to the modern build only:import legacy from '@kolibryjs/legacy-plugin' export default { plugins: [ legacy({ modernPolyfills: [ /* ... */ ], renderLegacyChunks: false, }), ], }
🔄 externalSystemJS
- Type:
boolean Default:
falseDefaults to
false. Enabling this option will excludesystemjs/dist/s.min.jsinside polyfills-legacy chunk.
🌐🚫 Browsers that supports ESM but does not support widely-available features
The legacy plugin offers a way to use widely-available features natively in the modern build, while falling back to the legacy build in browsers with native ESM but without those features supported (e.g. Legacy Edge). This feature works by injecting a runtime check and loading the legacy bundle with SystemJs runtime if needed. There are the following drawbacks:
- Modern bundle is downloaded in all ESM browsers
- Modern bundle throws
SyntaxErrorin browsers without those features support
The following syntax are considered as widely-available:
- dynamic import
import.meta- async generator
🧩📜 Polyfill Specifiers
Polyfill specifier strings for polyfills and modernPolyfills can be either of the following:
Any
core-js3 sub import paths - e.g.es/mapwill importcore-js/es/mapAny individual
core-js3 modules - e.g.es.array.iteratorwill importcore-js/modules/es.array.iterator.js
Example
import legacy from '@kolibryjs/legacy-plugin'
export default {
plugins: [
legacy({
polyfills: ['es.promise.finally', 'es/map', 'es/set'],
modernPolyfills: ['es.promise.finally'],
}),
],
}🔒🔐 Content Security Policy
The legacy plugin requires inline scripts for Safari 10.1 nomodule fix, SystemJS initialization, and dynamic import fallback. If you have a strict CSP policy requirement, you will need to add the corresponding hashes to your script-src list:
sha256-MS6/3FCg4WjP9gwgaBGwLpRCY6fZBgwmhVCdrPrNf3E=sha256-tQjf8gvb2ROOMapIxFvFAYBeUJ0v1HCbOcSmDNXGtDo=sha256-p7PoC97FO+Lu90RNjGWxhbm13yALSR4xzV8vaDhaQBo=sha256-+5XkZFazzJo8n0iOP4ti/cLCMUudTf//Mzkb7xNPXIc=
These values (without the sha256- prefix) can also be retrieved via
import { cspHashes } from '@kolibryjs/legacy-plugin'When using the regenerator-runtime polyfill, it will attempt to use the globalThis object to register itself. If globalThis is not available (it is fairly new and not widely supported, including IE 11), it attempts to perform dynamic Function(...) call which violates the CSP. To avoid dynamic eval in the absence of globalThis consider adding core-js/proposals/global-this to additionalLegacyPolyfills to define it.
📚🔗 References
2 years ago