
Product
Socket for Jira Is Now Available
Socket for Jira lets teams turn alerts into Jira tickets with manual creation, automated ticketing rules, and two-way sync.
vite-plugin-legacy-swc
Advanced tools
Provides legacy browsers support for the production build with SWC
Provides legacy browsers support for the production build with SWC.
This package is intended to replace @vitejs/plugin-legacy in performance-sensitive situations. It is basically an implementation of vitejs/vite#4105.
As for performance, for reference, the results of my tests on a huge private project (with { modernPolyfills: true }) are as follows:
| Without legacy browsers support | With @vitejs/plugin-legacy | With vite-plugin-legacy-swc | |
|---|---|---|---|
| CPU Time | 146.45s | 697.82s | 295.04s |
| JS Asset Size* | 9.5M | 22M | 21M |
| JS Asset Size Without Legacy Chunks | 9.5M | 9.6M | 9.6M |
Compared to @vitejs/plugin-legacy, vite-plugin-legacy-swc saves 58% of time and 4% of JS asset size.
* In my current tests, @vitejs/plugin-legacy does not generate source maps for legacy chunks correctly, so the asset size statistics exclude the source maps.
Vite'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 @swc/core 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.LEGACY env variable, which will only be true in the legacy production build, and false in all other cases.
// vite.config.js
import legacy from 'vite-plugin-legacy-swc'
export default {
plugins: [
legacy({
targets: ['defaults', 'not IE 11'],
}),
],
}
targetsType: string | string[] | { [key: string]: string }
Default: 'last 2 versions and not dead, > 0.3%, Firefox ESR'
It's passed on to @swc/core when rendering legacy chunks.
The query is also Browserslist compatible. See Browserslist Best Practices for more details.
If it's not set, plugin-legacy-swc will load the browserslist config sources and then fallback to the default value.
modernTargetsType: string | string[]
Default: 'edge>=79, firefox>=67, chrome>=64, safari>=12, chromeAndroid>=64, iOS>=12'
It's passed on to @swc/core when collecting polyfills for modern chunks. The value set here will override the build.target option.
The query is also Browserslist compatible. See Browserslist Best Practices for more details.
If it's not set, plugin-legacy-swc will fallback to the default value.
Note that this options should not be set unless renderLegacyChunks is set to false.
polyfillsType: boolean | string[]
Default: true
By default, a polyfills chunk is generated based on the target browser ranges and actual usage in the final bundle (detected via @swc/core's mode: 'usage').
Set to a list of strings to explicitly control which polyfills to include. See Polyfill Specifiers for details.
Set to false to avoid generating polyfills and handle it yourself (will still generate legacy chunks with syntax transformations).
additionalLegacyPolyfillsType: 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.
additionalModernPolyfillsType: string[]
Add custom imports to the modern 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.
modernPolyfillsType: boolean | string[]
Default: false
Defaults to false. Enabling this option will generate a separate polyfills chunk for the modern build (targeting browsers that support widely-available features).
Set to a list of strings to explicitly control which polyfills to include. See Polyfill Specifiers for details.
If modernTargets is not set, it is not recommended to use the true value (which uses auto-detection) because core-js@3 is 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 setting modernTargets or using an on-demand service like https://cdnjs.cloudflare.com/polyfill/ to only inject necessary polyfills based on actual browser user-agents (most modern browsers will need nothing!).
renderLegacyChunksType: boolean
Default: true
Set to false to disable legacy chunks. This is only useful if you are using modernPolyfills, which essentially allows you to use this plugin for injecting polyfills to the modern build only:
import legacy from 'vite-plugin-legacy-swc'
export default {
plugins: [
legacy({
modernPolyfills: [
/* ... */
],
renderLegacyChunks: false,
}),
],
}
externalSystemJSType: boolean
Default: false
Defaults to false. Enabling this option will exclude systemjs/dist/s.min.js inside polyfills-legacy chunk.
renderModernChunksType: boolean
Default: true
Set to false to only output the legacy bundles that support all target browsers.
This is also useful when running the project locally using file: protocol, as loading modern chunks with type="module" may trigger CORS restrictions. To avoid this issue, simply set renderModernChunks to false to exclusively use legacy chunks instead.
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:
SyntaxError in browsers without those features supportThe following syntax are considered as widely-available:
import.metaPolyfill specifier strings for polyfills and modernPolyfills can be either of the following:
Any core-js 3 sub import paths - e.g. es/map will import core-js/es/map
Any individual core-js 3 modules - e.g. es.array.iterator will import core-js/modules/es.array.iterator.js
Example
import legacy from 'vite-plugin-legacy-swc'
export default {
plugins: [
legacy({
polyfills: ['es.promise.finally', 'es/map', 'es/set'],
modernPolyfills: ['es.promise.finally'],
}),
],
}
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.
The hash values (without the sha256- prefix) can be retrieved via:
import { cspHashes } from 'vite-plugin-legacy-swc'
The current values are:
sha256-MS6/3FCg4WjP9gwgaBGwLpRCY6fZBgwmhVCdrPrNf3E=sha256-tQjf8gvb2ROOMapIxFvFAYBeUJ0v1HCbOcSmDNXGtDo=sha256-ZxAi3a7m9Mzbc+Z1LGuCCK5Xee6reDkEPRas66H9KSo=sha256-+5XkZFazzJo8n0iOP4ti/cLCMUudTf//Mzkb7xNPXIc=Note that these values could change between minor versions. Thus, we recommend generating the CSP header from the exported cspHashes variable. If you copy the values manually, then you should pin the minor version using ~.
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.
FAQs
Provides legacy browsers support for the production build with SWC
The npm package vite-plugin-legacy-swc receives a total of 2,880 weekly downloads. As such, vite-plugin-legacy-swc popularity was classified as popular.
We found that vite-plugin-legacy-swc demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Socket for Jira lets teams turn alerts into Jira tickets with manual creation, automated ticketing rules, and two-way sync.

Company News
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.

Security News
NIST will stop enriching most CVEs under a new risk-based model, narrowing the NVD's scope as vulnerability submissions continue to surge.