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-tswithvanillaif 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.jsonand 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.jsif you use vanilla JS) and replacecounter = countwithcounter = [count].with(0, count)[0];This line does exactly what
counter = countdoes. 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.jsif you use vanilla JS) file. Add the following content: (Removeas constif you use vanilla JS)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15import { 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

