DEV Community

Cover image for Outdated browser detection with Browserslist
Dmitry Salahutdinov for Amplifr.com

Posted on • Updated on

Outdated browser detection with Browserslist

The standard way to configure target browsers with Node.js is Browserslist. It is possible to add the following:

{
  "browserslist": [
    "last 2 version",
    "not dead"
  ]
}
Enter fullscreen mode Exit fullscreen mode

to the package.json or the .browserslistrc config file:

# Browsers that we support
last 2 version
not dead
Enter fullscreen mode Exit fullscreen mode

Those two similar examples mean that the target browsers are two last version and the browser is not dead.

This config is used by many front-end tools, such as Autoprefixer, Babel and many others.

But in this article I am going to write about the Browserslist Useragent frontend tool for finding if a given user agent string satisfies a Browserslist browsers:

Install the browserslist-useragent:

npm install browserslist-useragent
Enter fullscreen mode Exit fullscreen mode

and you can determine by User-Agent string if you browser matches:

const { matchesUA } = require('browserslist-useragent')

matchesUA(userAgentString, options)

// with browserslist config inferred
matchesUA('Mozilla/5.0 (Windows NT 10.0; rv:54.0) Gecko/20100101 Firefox/54.0')
//returns boolean

// with explicit browserslist
matchesUA('Mozilla/5.0 (Windows NT 10.0; rv:54.0) Gecko/20100101 Firefox/54.0', { browsers: ['Firefox > 53']})
// returns true
Enter fullscreen mode Exit fullscreen mode

Imaging we have the .browserslistrc config file like this:

last 2 versions
not IE 11
not ExplorerMobile 11
not last 1 OperaMini version
not OperaMobile 12.1
not dead
Enter fullscreen mode Exit fullscreen mode

We can get the array of detailed browsers rules with the help of browserslist:

const browserslist = require('browserslist')
const fs = require('fs')

fs.writeFileSync('./browsers.json', JSON.stringify(browserslist()))
Enter fullscreen mode Exit fullscreen mode

For the sample above it will produce the json file with:

[
  "and_chr 67",
  "and_ff 60",
  "and_qq 1.2",
  "and_uc 11.8",
  "android 67",
  "android 4.4.3-4.4.4",
  "baidu 7.12",
  "chrome 69",
  "chrome 68",
  "edge 17",
  "edge 16",
  "firefox 62",
  "firefox 61",
  "ios_saf 11.3-11.4",
  "ios_saf 11.0-11.2",
  "op_mob 46",
  "opera 55",
  "opera 54",
  "safari 11.1",
  "safari 11",
  "samsung 7.2",
  "samsung 6.2"
]
Enter fullscreen mode Exit fullscreen mode

That is the way to determine the browsers matchings with Node.js.

Why do we need to check the browsers version on both sides: backend and frontend?
In the case of your modern javascript frontend would not be loaded on the old browser - we can still use the backend rendering to write some HTML notifying user about the issue:

The outdated browser html block sample

❗This HTML block would work in any browser no matter how old it is.

And if your backend is written with Ruby - use can still use the port of the original tool to the Ruby - browserslist-useragent gem. It works the same way its Node.js version - recognises the family and the version from the User-Agent header string and matches it with the browserslist-rules produced by the Browserslists tool.

Single project

The usage is straightforward - it just needs you to generate the browsers.json file before.


class ApplicationController
  def supported_browser?
    @browsers ||= JSON.parse(Rails.root.join("browsers.json").read)
    matcher = BrowserslistUseragent::Match.new(@browsers, request.user_agent)
    matcher.browser? && matcher.version?(allow_higher: true)
  end
  helper_method :supported_browser?
end
Enter fullscreen mode Exit fullscreen mode

Then add this code to you Rails-application layout template:

- if !supported_browser?
  .div 
div( style: "position: fixed; bottom: 0; right: 0; padding: 8px 10px; background: #e9502f; color: white; width: 100%; z-index: 10; text-align: center;" )
    .div
      = t('unsupported_browser')
Enter fullscreen mode Exit fullscreen mode

❗This old-fashioned style is deliberately chosen: 'style'-attributes will work mostly everywhere!

Here it is. It will work well for the Rails projects where all the frontend and backend live together as one solid project.

Separated frontend and backend projects

If you have separated projects for Ruby backend and Node.js frontend, you will prefer to get browsers.json over HTTP. You will need to do the following:

  • serve the /browsers.json path to render the browserslist output by putting it to the public folder:
fs.writeFileSync(
  path.join(__dirname, 'public', 'browsers.json'),
  JSON.stringify(browserslist(undefined, { path: path.join(__dirname, '..') }))
)
Enter fullscreen mode Exit fullscreen mode
  • get in over HTTP in the ruby-backend code:
browsers = JSON.parse(Faraday.get('http://frontend-domain.local/browsers.json').body)
matcher = BrowserslistUseragent::Match.new(browsers, request.user_agent)
matcher.browser? && matcher.version?(allow_higher: true)
Enter fullscreen mode Exit fullscreen mode

Or use the faraday-http-cache to cache the results of the http request. It will force to make one request per the Rails application instance only:

# caches http response locally with etag
http_client = Faraday.new do |builder|
  builder.use Faraday::HttpCache, store: Rails.cache
  builder.adapter Faraday.default_adapter
end

browsers = JSON.parse(
  http_client.get('http://frontend-domain.local/browsers.json').body
)
...
Enter fullscreen mode Exit fullscreen mode

That's it. This solution will use one browserslist.rc config in the frontend repository, which will automatically be shared over the backend.

More details abort the browserslist_useragent gem you will find here.

Thanks for reading!

Oldest comments (4)

Collapse
 
andyw8 profile image
Andy Waite

FYI "browsers" is mispelled as "browers" in 3 places.

Collapse
 
dsalahutdinov profile image
Dmitry Salahutdinov

Thanks Andy. Fixed. ☺️

Collapse
 
dsalahutdinov profile image
Dmitry Salahutdinov

Unsupporting old browsers is very reasonable for the services with saas-service with modern complicated UI.

Collapse
 
jaot profile image
Jakob Ott

appreciated, we don't want outdated browsers anywhere.