Browser compability with core-js and eslint
javacripttest

Browser compability with core-js and eslint


It's tempting to assume everyone's on an evergreen browser, but older iOS devices still work well enough that you can't really ignore them — and they're missing a surprising amount. So how do you make sure you're not calling an API that isn't there?

Two pieces: core-js to add the missing bits at build time, and eslint-plugin-compat to yell at you when you reach for something you haven't polyfilled. This is the setup I landed on in a Vite project.

core-js polyfills

yarn add core-js -D

For a TypeScript ESM app, just import the polyfills at the top of your entry file. For URL, URLSearchParams and fetch:

import 'core-js/actual/url';
import 'core-js/actual/url-search-params';
import 'core-js/actual/fetch';

If the app is bundled with Vite you need to list the polyfills as externals in rollupOptions, otherwise the tree-shaker drops them:

module.exports = defineConfig({
  build: {
    rollupOptions: {
      external: ['core-js/actual/URL', 'core-js/actual/URLSearchParams', 'core-js/actual/fetch'],
    },
  },
});

The eslint rule

This is for eslint 9 and the new eslint.config.mjs format.

yarn add eslint-plugin-compat -D
// eslint.config.mjs
import globals from 'globals';
import pluginJs from '@eslint/js';
import tseslint from 'typescript-eslint';
import compat from 'eslint-plugin-compat';
 
export default [
  { files: ['**/*.{js,mjs,cjs,ts}'] },
  { languageOptions: { globals: globals.browser } },
  pluginJs.configs.recommended,
  compat.configs['flat/recommended'],
  ...tseslint.configs.recommended,
  {
    settings: {
      polyfills: ['URL', 'URLSearchParams', 'fetch'],
    },
  },
];

The plugin reads browserslist from package.json to decide what counts as supported. This config targets the 99.5% most common browsers:

{
  "browserslist": [
    "> 0.5%"
  ]
}

Run eslint and it'll flag anything you're using that isn't in all of those browsers — minus whatever's listed in polyfills.

npx eslint src