Vite is a modern tool for frontend development. One of Vite’s functionalities is to deploy the app for production, including bundling all JavaScript (JS) files. Although Vite supports building for a particular browser target, it only transforms syntax with the help of ebuild, but does not perform any JavaScript polyfill.
However, polyfill is essential for many projects. On the one hand, it’s often error-prone to manually polyfill, such as using core-js manually. On the other hand, an on-demand polyfill service like polyfill.io bears its own limitations and security risks. Therefore, it is ideal to use an automatic polyfill mechanism that is integrated with Vite.
In this post, we discuss how to automatically polyfill JavaScript APIs in a Vite project with the help of the Vite legacy plugin.
Overview: Automatic Polyfill with Vite
To automatically polyfill modern JS functions, install the Vite legacy plugin
(@vitejs/legacy-plugin
) and add the following to vite.config.ts
if you use TypeScript, or
vite.config.js
if you use JS:
|
|
Also, remove as const
if you use JS.
modernTargets
: Specifies browser compatibility for polyfill in this property. It is a string or an array of strings that follow Browserslist. The example above refers to browsers that have been released since January 1, 2023 and are not dead. A browser is not dead if it has not been without official support or updates for 24 months.modernPolyfills
: Enables polyfill for modern JS functions.renderLegacyChunks
: Disables polyfill for legacy browsers. Depending on your situation, you may decide whether to include this line.
Demo App
To better illustrate how to include modern polyfills, we’ll walk through the process of building a demo app.
In this demo app, we will be targeting stable browser releases in January 2023. In other words, we would like the app to be usable on any stable versions of modern browsers that have been released since January 1, 2023.
Project Setup
Create a new Vite project. Replace
vanilla-ts
withvanilla
if you prefer vanilla JS over TypeScript.npm create vite@latest polyfill-app -- --template vanilla-ts
Install project dependencies.
cd polyfill-app && npm install
If you use TypeScript, edit
tsconfig.json
and replace any"ES20*"
in"target"
and"lib"
with"ESNext"
. This is to prevent the TypeScript compiler from not recognizing later modern functions.Add a modern JS function usage. In this demo, we’ll use
Array.prototype.with
, which is not available in stable versions of modern browsers released in January 2023. Editsrc/counter.ts
(orsrc/counter.js
if you use vanilla JS) and replacecounter = count
withcounter = [count].with(0, count)[0];
This line does exactly what
counter = count
does. Its only purpose is to insert a use ofArray.prototype.with
.
If you run npm run build
now, you will see no polyfill.
Add Automatic Polyfills
Install the Vite legacy plugin:
npm install --save-dev @vitejs/plugin-legacy
Create the
vite.config.ts
(orvite.config.js
if you use vanilla JS) file. Add the following content: (Removeas const
if you use vanilla JS)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
import { defineConfig } from "vite"; import legacy from "@vitejs/plugin-legacy"; const legacyPluginOptions = { modernTargets: "since 2023-01-01, not dead", modernPolyfills: true, renderLegacyChunks: false, } as const; export default defineConfig({ plugins: [legacy(legacyPluginOptions)], build: { target: ["chrome109", "edge109", "firefox109", "ios16.3", "safari16.3"], }, });
The Overview section has already explained most of the
content of this file. We also filled the build.target
option with browsers released in
January 2023 so that syntax transformation also aligns with our intended supported browsers.
Running npm run build
now, you should see Vite generates a polyfill JS file. Running
DEBUG='vite:legacy' npm run build
reveals which functions are polyfilled:
[@vitejs/plugin-legacy] modernTargets: since 2023-01-01, not dead
vite v5.2.12 building for production...
✓ 7 modules transformed.
rendering chunks (1)...[@vitejs/plugin-legacy] modern polyfills: Set(1) { 'core-js/modules/es.array.with.js' }
dist/index.html 0.54 kB │ gzip: 0.32 kB
dist/assets/index-DxRda7M6.css 1.22 kB │ gzip: 0.63 kB
dist/assets/index-DWjTM3Sh.js 3.07 kB │ gzip: 1.65 kB
dist/assets/polyfills-B1wrU7sj.js 10.13 kB │ gzip: 4.44 kB
✓ built in 655ms