show an error message if browser is not supported - javascript

In my Vue.js app, I have the following in package.json
"browserslist": [
"> 1%",
"last 2 versions"
]
I believe this is used by Babel to customise the JavaScript that is generated (other build tools may also use it). Is it possible for me to leverage this list of supported browsers to show an error if the user attempts to load the app in an unsupported browser?
I could write some JavaScript that detects the user agent and shows an error if the browser is not supported, but this would likely require me to maintain the list of supported browsers in 2 places, which I'd rather avoid.

First and foremost I want to mention that it might be a bad idea to do this. Browsers are update at quite a fast pace and users might not be able to update often due to for example some company policy. A better approach would be to use feature detection, where you check if a specific feature is supported by the browser. This might be a bit more work, but gives an actual reason to tell people that their browser is not supported.
You can use the browserslist-useragent-regexp package to generate a regular expression from your browserslist configuration. You can write this regular expression to a file and use it to test if navigator.userAgent is supported by your configuration. The README file in the browserslist-useragent-regexp repository contains an example setup.
Another options is to use the browserslist-useragent package, you can give this tool a user-agent and a browserslist configuration to check if a specific user-agent matches the browserslist configuration. This option might need some more research as it seems to be aimed first at Node.js applications.
This option seems to be abandoned and has some dependencies which are no longer maintained, so proceed at your own risk. obsolete-webpack-plugin can also be used which requires less setup if you're already using Webpack 4 in your project. It can be used with HtmlWebpackPlugin and it creates a new chunk which will insert an HTML snippet in your page when a browser is not supported.

Related

What is the best way to load Babel?

I have a first generation iPad mini. It's a about 8 years old and although it displays my page correctly some functionalities that require JavaScript doesn't seem to work. If I understood correctly I need to load Babel or something like that. Is that true? But what's the best way to load Babel? should I just use a script tag like so:
<script src="https://unpkg.com/#babel/standalone/babel.min.js"></script>
Is that enough?
TL;DR: don't load Babel in the browser in a production env
It depends on what exactly doesn't work. If it's simply syntax and some ES6 classes/functions, that's probably solved by Babel which transforms syntax and has some polyfills. You can transpile your JS server-side if you're concerned about load times (which makes sense for older devices). If you can't do it on the server, you can just deploy a JS file you transpiled on your workstation. Also, if you go here and click on "In the browser", you'll see this:
Compiling in the browser has a fairly limited use case, so if you are working on a production site you should be precompiling your scripts server-side.
You should probably also have a look at CanIUse. Then you can decide how much time you want to invest in the first place. const for example is supported by 99.8% of users globally.
However, it can be that your page uses JS to do some complex interaction that depends on pointers, touch events and such. In that case you probably need to rewrite a lot of it. This does not apply to your situation, but generally may impact someone's decision on what browsers to support.

Handle browsers that do not support the `const` keyword

I've recently bumped into users that use old devices and whose browsers (mainly Safari 9) raise JS errors because they do not implement the const keyword that we use in our modern SPA app*.
I suppose a fix would be to let Babel recompile the whole app with regular var keywords, but I'm afraid of the speed loss of the website by doing so. Do you have any ideas/experience ith this ?
If we decide to support such broswers, is there a way to maybe compile a version of the website just for those browsers ? I've heard it was possible to use media queries for javascript files. Is it convenient ?
*We are hosting a ReactJS app at https://www.myjobglasses.com that comes from an ejected create_react_app
Use Babel to transpile the website code before uploading it. From my experience, it should not slow down your app significantly, even when targeting a bit older browsers.
Babel has a great tool to transpile code for particular browsers, called babel-preset-env:
https://babeljs.io/docs/en/babel-preset-env
As it uses this: https://github.com/browserslist/browserslist for checking, you can define different rules that your transpiling will follow, hence - you'll always have working code as a result, e.g. (taken from preset-env documentation):
{
"targets": "> 0.25%, not dead"
}
{
"targets": {
"chrome": "58",
"safari": "9"
}
}
Another idea - if you want to delve deeper, you can actually prepare two bundles and load them conditionally, based on browser version (so, essentially, for this specific case of Safari).
That would require you to somehow detect browser when connecting to the server (e.g. by User-Agent) and serve different bundles, but it's doable ;)
What about using a package like Modernizr? You could check if the client's browser supports certain feature that is well known to fail in Safari, and include it in you Modernizr support. It is pretty straight forward, I think. Check out Modernizr here
Also, this answer could be useful: https://stackoverflow.com/a/13480430/7868769

Transpiling or not transpiling Polymer 2 applications?

I am writing a Polymer 2 application. The default is to transpile ES6 to ES5 so that you can use ES6 syntax and be sure it will just work.
The problem with this is that everybody (even supporting browsers) get to receive transpiled code.
Two questions:
Is it just too crazy to say "no" to legacy browsers, and just stop transpiling?
Is there an easy-ish way to redirect specific browsers to a non-transpiled version of the app?
It really depends on the audience of the app you want to create. As for my own projects, I can see in my Google Analytics that there are still some people who are accessing it via Safari 8, 9 and even IE 11. I cannot just tell them to use a different browser because of several reasons... mostly financial reason (either personal or corporate)
Because of that, it is still a default for me to just transpile back to ES5 (given that I am using Webpack for now while waiting for the script type="module" to stabilize).
As for easiest way, they say if you use Polymer-CLI's serve function, it autotranspiles your code depending on the browser's capabilities.
Or you can have a simple javascript code that tries to check an ES6 method, then if it works, it loads the ES6 version of the bundled code... if not, it loads the ES5 version of the bundled code + the custom-elements-es5-adapter. But this one takes some performance hit because of the wait to parse the initial JS script to check before loading the necessary files instead of loading them right away (I haven't tested this though)
Or you can check in the server what type of browser is calling and then heuristically guess what type of version code you want to send.
As for performance for the overhead of the transpiled code, it's a bit miniscule, given that if you are just using Polymer.Element, you can get at least 12KB of code... then you'll have like 30+KB left to show content, which is more than enough to have a PRPL+50
The simple answer isL use prpl-server-node which does exactly what I was talking about, and more.
Specifically:
Differential Serving
Modern browsers offer great features that improve performance, but most applications need to support older browsers too. prpl-server can serve different versions of your application to different browsers by detecting browser capabilities using the user-agent header.
Builds
prpl-server understands the notion of a build, a variant of your application optimized for a particular set of browser capabilities.

Ensuring Javascript support for multiple libraries (e.g. Angular 1.5, jQuery 2.2.0, ckEditor 4.x, pdfjs 1.3.91)

We're told "feature detection" is much more betterer than filtering by browsers/versions... so how do you ensure support for specific versions of multiple libraries?!
I don't know what features I'm relying on directly, just what min requirements are for each library!? So when I have a constellation of libraries, what should I do to ensure the user's browser is going to support them all?
EDIT: It seems here's a partial answer, but what do you do in your production systems to warn users that their user experience may not be complete due to an old ass browser?
There is a great lib to do the Feature detection called: modernizr
However, I wonder how can you know exactly what features are required by those libs?
Usually I would just check the requirements by reading their docs, then I would check Can I Use / ECMAScript Compatibility Table to have glance of roughly how many people will be kicked out.
Also, if you use ES6+/CSS3+, Babel and PostCSS can do some polyfill for you automatically

Testing browser extensions

I'm going to write bunch of browser extensions (the same functionality for each popular browser). I hope, that some of the code will be shared, but I'm not sure about this yet. For sure some of extensions will use native API. I have not much experience with TDD/BDD, and I thought it's good time to start folowing these ideas from this project.
The problem is, I have no idea how to handle it. Should I write different tests for each browser? How far should I go with these tests? These extensions will be quite simple - some data in a local storage, refreshing a page and listening through web sockets.
And my observation about why is it hard for me - because there is a lot of behaviour, and not so much models, which are also dependent on a platform.
I practise two different ways of testing my browser extensions:
Unit tests
Integration test
Introduction
I will use the cross-browser YouTube Lyrics by Rob W extension as an example throughout this answer. The core of this extension is written in JavaScript and organized with AMD modules. A build script generates the extension files for each browser. With r.js, I streamline the inclusion of browser-specific modules, such as the one for cross-origin HTTP requests and persistent storage (for preferences), and a module with tons of polyfills for IE.
The extension inserts a panel with lyrics for the currently played song on YouTube, Grooveshark and Spotify. I have no control over these third-party sites, so I need an automated way to verify that the extension still works well.
Workflow
During development:
Implement / edit feature, and write a unit test if the feature is not trivial.
Run all unit tests to see if anything broke. If anything is wrong, go back to 1.
Commit to git.
Before release:
Run all unit tests to verify that the individual modules is still working.
Run all integration tests to verify that the extension as whole is still working.
Bump versions, build extensions.
Upload update to the official extension galleries and my website (Safari and IE extensions have to be hosted by yourself) and commit to git.
Unit testing
I use mocha + expect.js to write tests. I don't test every method for each module, just the ones that matter. For instance:
The DOM parsing method. Most DOM parsing methods in the wild (including jQuery) are flawed: Any external resources are loaded and JavaScript is executed.
I verify that the DOM parsing method correctly parses DOM without negative side effects.
The preference module: I verify that data can be saved and returned.
My extension fetches lyrics from external sources. These sources are defined in separate modules. These definitions are recognized and used by the InfoProvider module, which takes a query, (black box), and outputs the search results.
First I test whether the InfoProvider module functions correctly.
Then, for each of the 17 sources, I pass a pre-defined query to the source (with InfoProvider) and verify that the results are expected:
The query succeeds
The returned song title matches (by applying a word similarity algorithm)
The length of the returned lyrics fall inside the expected range.
Whether the UI is not obviously broken, e.g. by clicking on the Close button.
These tests can be run directly from a local server, or within a browser extension. The advantage of the local server is that you can edit the test and refresh the browser to see the results. If all of these tests pass, I run the tests from the browser extension.
By passing an extra parameter debug to my build script, the unit tests are bundled with my extension.
Running the tests within a web page is not sufficient, because the extension's environment may differ from the normal page. For instance, in an Opera 12 extension, there's no global location object.
Remark: I don't include the tests in the release build. Most users don't take the efforts to report and investigate bugs, they will just give a low rating and say something like "Doesn't work". Make sure that your extension functions without obvious bugs before shipping it.
Summary
View modules as black boxes. You don't care what's inside, as long as the output matches is expected or a given input.
Start with testing the critical parts of your extension.
Make sure that the tests can be build and run easily, possibly in a non-extension environment.
Don't forget to run the tests within the extension's execution context, to ensure that there's no constraint or unexpected condition inside the extension's context which break your code.
Integration testing
I use Selenium 2 to test whether my extension still works on YouTube, Grooveshark (3x) and Spotify.
Initially, I just used the Selenium IDE to record tests and see if it worked. That went well, until I needed more flexibility: I wanted to conditionally run a test depending on whether the test account was logged in or not. That's not possible with the default Selenium IDE (it's said to be possible with the FlowControl plugin - I haven't tried).
The Selenium IDE offers an option to export the existing tests in other formats, including JUnit 4 tests (Java). Unfortunately, this result wasn't satisfying. Many commands were not recognized.
So, I abandoned the Selenium IDE, and switched to Selenium.
Note that when you search for "Selenium", you will find information about Selenium RC (Selenium 1) and Selenium WebDriver (Selenium 2). The first is the old and deprecated, the latter (Selenium WebDriver) should be used for new projects.
Once you discovered how the documentation works, it's quite easy to use.
I prefer the documentation at the project page, because it's generally concise (the wiki) and complete (the Java docs).
If you want to get started quickly, read the Getting Started wiki page. If you've got spare time, look through the documentation at SeleniumHQ, in particular the Selenium WebDriver and WebDriver: Advanced Usage.
Selenium Grid is also worth reading. This feature allows you to distribute tests across different (virtual) machines. Great if you want to test your extension in IE8, 9 and 10, simultaneously (to run multiple versions of Internet Explorer, you need virtualization).
Automating tests is nice. What's more nice? Automating installation of extensions!
The ChromeDriver and FirefoxDriver support the installation of extensions, as seen in this example.
For the SafariDriver, I've written two classes to install a custom Safari extension. I've published it and sent in a PR to Selenium, so it might be available to everyone in the future: https://github.com/SeleniumHQ/selenium/pull/87
The OperaDriver does not support installation of custom extensions (technically, it should be possible though).
Note that with the advent of Chromium-powered Opera, the old OperaDriver doesn't work any more.
There's an Internet Explorer Driver, and this one does definitely not allow one to install a custom extension. Internet Explorer doesn't have built-in support for extensions. Extensions are installed through MSI or EXE installers, which are not even integrated in Internet Explorer. So, in order to automatically install your extension in IE, you need to be able to silently run an installer which installs your IE plugin. I haven't tried this yet.
Testing browser extensions posed some difficulty for me as well, but I've settled on implementing tests in a few different areas that I can invoke simultaneously from browsers driven by Selenium.
The steps I use are:
First, I write test code integrated into the extension code that can be activated by simply going to a specific URL. When the extension sees that URL, it begins running the tests.
Then, in the page that activates the testing in the extension I execute server-side tests to be sure the API performs, and record and log issues there. I record the methods invoked, the time they took, and any errors. So I can see the method the extension invoked, the web performance, the business logic performance, and the database performance.
Lastly, I automatically invoke browsers to point at that specific URL and record their performance along with other test information, errors, etc on any given client system using Selenium:
http://docs.seleniumhq.org/
This way I can break down the tests in terms of browser, extension, server, application, and database and link them all together according to specific test sets. It takes a bit of work to put it all together, but once its done you can have a very nice extension testing framework.
Typically for cross-browser extension development in order to maintain a single code-base I use crossrider, but you can do this with any framework or with native extensions as you wish, Selenium won't care, it is just driving the extension to a particular page and allowing you to interact and perform tests.
One nice thing about this approach is you can use it for live users as well. If you are providing support for your extension, have a user go to your test url and immediately you will see the extension and server-side performance. You won't get the Selenium tests of course, but you will capture a lot of issues this way - very useful when you are coding against a variety of browsers and browser versions.

Categories

Resources