How do I load certain scripts for certain browsers? - javascript

I have an app up and running, and it works great in Chrome and Firefox. Safari is another story. For the sake of example, let's pretend this is my app:
'use strict';
const x = 3;
function test(){
let y = 4;
return y;
};
When I run it in Safari I get:
SyntaxError: Unexpected keyword 'const'. Const declarations are not supported in strict mode.
Then if I remove 'use strict' I get:
SyntaxError: Unexpected identifier 'y'
At this point I decided to take my first look into transpiling, so I installed Babel and I have my client-side code converted to ES5 and sitting in a new folder.
My question now is, what's the best practice for loading the original code if a user is using Chrome/Firefox, but loading the transpiled code if they're using Safari? Is my head even in the right place here?

To detect if safari is being used:
var safariCheck=Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
Then you can load the code you want for safari if the above statement qualifies.
If it does not you can load the Firefox or Chrome code.

The cleanest way to check feature is to use Modernizer
With this library you can check that browser have es6 feature ready with this code:
if (Modernizr.es6array) {
loadNewCode();
} else {
loadOldCode();
}
You can find more examples and documentation here.

Related

Is there a way to silence syntax errors in IE11 in a modern JS code?

We're developing a modern JS library which uses the ES6 syntax heavily and doesn't support IE11.
However we have a small number of users who want to use our library on IE11-compatible sites and we don't want to break their sites on IE11.
Question: is there some way to prevent our library from "exploding" on IE11? (All of the library functions can do nothing and return undefined if IE11 is detected)
For example, we were trying the following approach based on browser detection:
function libFunction() {
if(isIe11()) {
return;
}
// otherwise do some real stuff with ES6-heavy code
}
However the approach above doesn't work because IE11 throws syntax error even in the code that never gets executed, se we end up with errors like:
SCRIPT1002: Syntax error
File: main.db33ab01aedf59e2f70a.hot-update.js, Line: 47, Column: 1
Other approaches that we consider:
make our server return a fake implementation of our library if IE11 User-Agent is detected in the request headers. This will partially solve our problems, but won't help the users, who integrate our library into their bundle via NPM/webpack instead of getting it from our servers at runtime.
transiple our ES6 code to IE11-friendly code and polyfill all the APIs - we don't do that because we don't want the modern browser users to pay the price of the bloated ES5 code and polyfills.
override global error handler to silence the errors - this won't work, because the errors we get are syntax error, that are not handled by the error handler.
Is there any other possible solution?

How do I prevent IE from breaking when passing Console to IIFE

I have a script which needs to work in IE browsers < v11. Don't ask me why! It seems the console object is not available when IE does not have developer tools running and this causes problems.
I can't find a way of preventing the script from failing other than writing messy checks for undefined.
Here is some sample code using an IIFE:
var vm = (function ($, c, opts) {
}(jQuery, console, window.MyAppSettings));
I can't even test for undefined inside the IIFE as this seems to break before it is called. Is there any convention for this sort of thing?

Destructuring statement in chrome/chromium 44 not being recognised

As far as I know, this is valid EcmaScript6:
let obj = {foo: "foo", bar: "bar"};
let {foo, bar} = obj; // <- Syntax error here
Firefox runs this code just fine, but both Google Chrome and Chromium give me this error:
Uncaught SyntaxError: Unexpected token {
I know in firefox, scripts tags have to be flagged with "version=1.7" in the type attribute for this to work, but in Google Chrome this results in the script getting ignored. A normal script tag gives this error.
Does this mean this feature is not implemented in Google Chrome? Or am I missing something?
That's right. Currently, it isn't supported yet.
https://devdocs.io/javascript/operators/destructuring_assignment
Although Chrome doesn't support some new features of ES6 (check this table to see what is already supported on different browsers), you can use a polyfill/plugins to enable certain features on Chrome. You can find polyfill and plugins on Babel. Just read through the plugins documentation and implement the ones you want.

Javascript strict mode and versions

I want to use let in my code. Like so:
"use strict";
var b = 5;
for(let i =0;b > i; i++){
alert(i);
}
This is working in Chrome and IE. But not in Firefox.
Wrapping my code in script tags with the type attribute set to "application/javascript;version=1.7" like so:
<script type="application/javascript;version=1.7">
This fixes the problem in Firefox, but breaks the code in Chrome and IE.
The error Firefox gives me when i execute the first code snippet:
SyntaxError: let is a reserved identifier
Is there any way to support all browsers?
Avoid using let unless you're using a transcoder/transpiler to convert your js to code that is currently widely supported.
Let became standard in ECMA-262 but it'll be several years before a large enough portion of visitors support it natively to use it.
The following have basic support for let, everything below will break:
Chrome 41+
Gecko 2.0
IE11
Opera 17+
Safari ??
The above browsers likely have inconsistent implementations at this point, so it's best to avoid it.
Check out babel to transform.
Let as defined in ES2015 (ES6) is not yet supported in Firefox. It has an old version of let that is non standard and works slightly differently.
The current way to support it in all browsers is to use a transpiler like BabelJS.

Conditionally require code in commonJS AMD module

I'm trying to write a cross-browser extension for Firefox and Chrome. Firefox uses the commonJS specification and Chrome just lumps everything into the global namespace like a webpage.
In order to be able to write reusable code, I'm trying to use requireJS to lood code in the Chrome extension, that way I can write commonJS modules and have them work in both environments.
I'm running into a problem when I need to conditionally require modules. For example, Firefox provides access to a simple-storage module which you should use to access the local storage. In chrome, I need to use the localStorage API that they provide. So, I've been trying to do this:
// storage.js
define(function(require, exports, module){
var store;
try {
// This module will only be available in the FF extension.
store = require('simple-storage').storage
} catch(error) {
// If it's not available, we must be in Chrome and we
// should use the localStorage object.
store = localStorage
}
// Use the store object down here.
});
However this doesn't seem to work. When I try to load the Chrome extension I get the following error:
Is there a better way to require modules with a fallback?
There are two caveats here:
1) Detect if chrome is running
// detects webKit (chrome, safari, etc..)
var isChrome = 'webKitTransform' in document.documentElement.style
2) Requirejs will parse the define() function and search for require('module') calls. To prevent the error on chrome you have write the require in some way that when requirejs parses the function body it does not recognize the call as a module dependency:
if (isChrome)
// use localStorage
else {
// set the module name in a var does the trick,
// so requirejs will not try to load this module on chrome.
var ffStorageModule = 'simple-storage';
return require(ffStorageModule);
}

Categories