How to serve web app that supports specific browsers? - DO OK

How to serve web app that supports specific browsers?

Building websites or web apps for all major browsers means extra work to do because you must ensure that all of the code you write is supported in each browser.

Nowadays we use new JavaScript features specified by ECMAScript in most projects. This means that if we need to support legacy browsers, then we have to translate new features into the code that older browsers can understand. This process is called transpilation. To do it we can use Babel - the most popular toolchain to convert ECMAScript 2015+ code into a backward compatible version of JavaScript in current and older browsers or environments (such as Node.js).

A similar situation happens with CSS. There are CSS vendor prefixes that allow supporting new CSS features before they are formally added to CSS specification. Browser manufacturers have a chance to test and experiment with new ideas. Thanks to CSS vendor prefixes developers can use the new features before they are fully supported in all browsers. To achieve this we can use Autoprefixer - the postprocessor that adds vendor prefixes to CSS rules.

How to set up our project to determine supported browsers? Use Browserslist - the single configuration for all front-end tools (i.a. Babel or Autoprefixer) that need to know what browsers you support. To achieve this, follow the steps below.

Specify which browsers you want to support

You must start by defining the browsers that you are going to support. Using Browserlist, the only thing you have to do is add configuration to your package.json file. All tools will find target browsers automatically.


  "browserslist": [
    "> 0.5%",
    "last 2 versions"

Above configuration means that you support browsers versions which have global usage greater than 0.5% or the last two versions of each browser. Here you can see exactly what browsers you are targeting based on the above configuration string. Pay attention to the fact that these selected browsers are union, not an intersection. If you want to achieve a combined set you must use and operator (combiner):

"> 0.5% and last 2 versions"

For more information, you can read Browserlist documentation that includes a lot of query combinations to select desirable browsers versions.

Configure JavaScript transpiling

As I mentioned before, Babel compiles code that contains new syntax into the code that legacy browsers can understand. It can be done in two ways:

  • by polyfills which prepend ES5 code to emulate modern functionality on older browsers that don’t natively support it (e.g. Object.assign);
  • by plugins which transform ES2015+ syntax (such as array functions) to older syntax and cannot be polyfilled.

Your package.json should contain the following dependencies. Be careful with the version of packages. They are current at the time of writing this article and can be newer in the future.

  "dependencies": {
    "core-js": "^3.0.1",
    "regenerator-runtime": "^0.13.2"
  "devDependencies": {
    "@babel/core": "^7.4.3",
    "@babel/preset-env": "^7.4.3",
    "babel-loader": "^8.0.5"


@babel/core is the core of Babel compiler. Its configuration can be defined in babel.config.js file in the root directory of your project.

babel-loader includes Babel in the Webpack build process:

module: {
  rules: [
      test: /\.js$/,
      loader: 'babel-loader'

core-js is a set of polyfills that provide any newer ECMAScript features. Whereas regenerator-runtime is a separate library that includes support for generators and async functions. You should add them at the top of the entry point to your application:

import 'core-js/stable';
import 'regenerator-runtime/runtime';

Until Babel 7.4.0 you could use @babel/polyfill but now it is deprecated.

@babel/preset-env identifies which transforms and polyfills are necessary for browsers defined by Browserslist configuration in your package.json file. To configure @babel/preset-env add the following code to babel.config.js:

presets: [
  ['@babel/preset-env', {
    corejs: 3,
    useBuiltIns: 'entry'

useBuiltIns option configures how Babel handles polyfills. By default (false value) all polyfills are included to bundle. With the entry option value Babel imports individual polyfills needed for the target browsers. You can also use usage value for adds specific imports for polyfills when they are used in each file. In this case, you don’t need to import core-js and regenerator-runtime libraries. Unfortunately, it is still an experimental way and can lead to some problems.

Configure CSS prefixing

Configuring Autoprefixer is quite simple. You probably already have CSS settings in your Webpack configuration. It depends on our project specifications and could look like that:

  test: /\.s?css$/,
  use: [

The crucial tool for us is postcss-loader. It is Webpack loader for PostCSS - a tool for transforming styles. Whereas Autoprefixer is a PostCSS plugin to parse CSS and add vendor prefixes. To configure this plugin you need to add postcss.config.js to your project with the following content:

module.exports = {
  plugins: [

That’s it. We can enjoy prefixed rules in our CSS. For example:

Browserslist config CSS output
last 2 Chrome versions
.block {
  display: flex;
  align-items: center;
last 2 Chrome versions,
last 2 IE versions
.block {
  display: -ms-flexbox;
  display: flex;
  -ms-flex-align: center;
  align-items: center;

Impact on the size of production build

Pay attention to the browsers that you want to target. If you, for example, don’t need to support Internet Explorer, exclude it from your Browserslist configuration. It will have an effect on the bundle size.

I built a very simple project in React. First with only last 2 Chrome versions entry in Browserslist configuration:

Then I extended target browsers by adding last 2 IE versions entry:

As you can see it is a huge difference in bundle size. Supporting last 2 Internet Explorer versions caused adding a lot of polyfills and transforming code to older syntax for backward compatible. Whereas CSS file has been extended by necessary vendor prefixes. This means that your result files will be larger. So, be aware of how legacy browsers supporting affects the production build.


In this article, you have learned how to configure web app project to support specific browsers. Now you can consciously use Browserslist configuration and manage browsers versions that you are supporting.

If you have any questions about browsers’ support in web apps, feel free to reach out to us or leave a comment.

Wave the uncertainty and get opportunities with Value-Focused Workshop
When the clock struck midnight on January 1, 2020, most of us optimistically looked ahe...
12.10.2020, min read
Dmitrij Żatuchin
Read more
What is business analysis?
07.10.2020, min read
Dmitrij Żatuchin
Read more

Our website has cookies. more info