Getting Webpack 2 to support IE8 - internet-explorer-8

I want to use Webpack 2 in a large project which must still support IE8.
I've installed babel-preset-env so I can easily deprecate any IE < 11 in future, one by one, once each of the browsers becomes unsupported by this project.
According to the babel-preset-env readme "If you are targeting IE 8 and Chrome 55 [babel-preset-env] will include all plugins required by IE 8 since you would need to support both still."
As I understand it, I also need to install babel-polyfill mostly for its IE5 shim, but also for its polyfills for ES6 and 7 features that I may wish to use.
However having installed these things, my code still falls over on IE8 (in Browserstack) at the point where Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); is first run. A function I thought was getting 'fixed' by the shims.
Is it not getting shimmed properly? Have I missed out a step?

I had the same problem before and here is what I did to solve.
In es6 features,
a class can define a property with get and set to encapsulate a field.
but it is not woroking on IE8.
because the defineProperty method is not supported see the docs,
so we changed the whole code pattern to like below
let val1;
class className {
methodName() {
this.val2 = 'test';
//code here
}
getVal1() {
return val1;
}
setVal1(_val1) {
val1 = _val1;
}
getVal2() {
return this.val2;
}
setVal2(_val2) {
this.val2 = _val2;
}
}
module.exports = className;
and I recommend that adding 'es3ify' see the link,github es3ify to your webpack build for IE7/8

Related

How to implement message passing callbacks in an all-in-one (Edge/Firefox/Chrome) browser extension's content script?

Development Environment OS: Windows 7 Enterprise LTS
Browser compatibility minimum requirements: Should support all Edge, Firefox, Chrome browsers, as of 2018.
Current ongoing issue: Unable to run VM on dev workstation; Cannot run Windows 10 VMs to debug Microsoft Edge extensions.
To explain:
An "all-in-one browser extension" refers to a browser extension code that uses the same code with minor differences to work on various WebExtensions / Chrome Extensions supported browsers. At bare minimum, the same codebase should work and run on Edge, Firefox, and Chrome with very minor changes.
Callbacks on the content scripts for Edge/Firefox/Chrome extensions are handled differently.
For unknown reasons, I cannot run VM on my workstation machine. When VM is running, VM client is black. This is a localized issue on my end that I cannot resolve, so I'm forced to find a different solution/alternative.
How are they handled differently on the content scripts:
Edge: browser.runtime.sendMessage uses callbacks, and returns undefined.
Firefox: browser.runtime.sendMessage uses Promises, and returns a Promise.
Chrome: chrome.runtime.sendMessage uses callbacks, and returns undefined.
According to various references:
Firefox / Chrome / MS Edge extensions using chrome.* or browser.*
https://www.smashingmagazine.com/2017/04/browser-extension-edge-chrome-firefox-opera-brave-vivaldi/
On the content scripts, you can declare the following JavaScript snippet at the top in order to create a global variable that can be referenced everywhere else:
//Global "browser" namespace definition.
window.browser = (function() {
return window.msBrowser || window.browser || window.chrome;
})();
Unfortunately, because of the issue I'm experiencing (VM not running), I cannot tell if window.msBrowser is still being used. And this solution is not helpful for me when handling message callbacks when using namespace.runtime.sendMessage.
With all that said, my main question is: How to write a message passing function that can handle callbacks properly?
Currently, I'm using the following code:
function sendGlobalMessage(messageRequest, callback) {
if (chrome && window.openDatabase) {
//This is Chrome browser
chrome.runtime.sendMessage(messageRequest, callback);
}
else if (browser) {
try {
//Edge will error out because of a quirk in Edge IndexedDB implementation.
//See https://gist.github.com/nolanlawson/a841ee23436410f37168
let db = window.indexedDB.open("edge", (Math.pow(2, 30) + 1));
db.onerror = function(e) {
throw new Error("edge is found");
};
db.onsuccess = function(e) {
//This is Firefox browser.
browser.runtime.sendMessage(messageRequest).then(callback);
};
}
catch (e) {
//This is Edge browser
browser.runtime.sendMessage(messageRequest, callback);
}
}
}
I truly felt this is a hacky solution, because the code is based off of browser platform exclusive quirks in order to separate chrome.runtime.sendMessage and browser.runtime.sendMessage API calls, so as to handle callbacks in their respective platforms. I really wanted to change this.
So I'm asking what better ways are there, out there, that is useful to detect the different platforms, and handle message passing callbacks properly at the same time?
Thanks in advance.
I believed I solved it.
EDIT: The FINAL final version (updated and more stable, less message passing):
//Global "browser" namespace definition, defined as "namespace". Can be renamed to anything else.
window.namespace = (function() {
return window.browser || window.chrome;
})();
function sendGlobalResponse(message, callback){
if (window.namespace === window.chrome) {
//Chrome
window.namespace.runtime.sendMessage(message, callback);
}
else if (window.namespace === window.browser) {
//Using instanceof to check for object type, and use the returned evaluation as a truthy value.
let supportPromises = false;
try {
supportPromises = window.namespace.runtime.getPlatformInfo() instanceof Promise;
}
catch(e) { }
if (supportPromises){
//Firefox
window.namespace.runtime.sendMessage(message).then(callback);
}
else {
//Edge
window.namespace.runtime.sendMessage(message, callback);
}
}
}
(Original Post):
The final version (Now obsoleted):
//Global "browser" namespace definition.
window.namespace = (function() {
return window.browser || window.chrome;
})();
function sendGlobalResponse(message, callback){
if (window.namespace === window.chrome) {
//Chrome
window.namespace.runtime.sendMessage(message, callback);
}
else if (window.namespace === window.browser) {
let returnValue = window.namespace.runtime.sendMessage({});
if (typeof returnValue === "undefined"){
//Edge
window.namespace.runtime.sendMessage(message, callback);
}
else {
//Firefox
window.namespace.runtime.sendMessage(message).then(callback);
}
}
}
In the second if statement, by checking to see if the return value of a window.browser.runtime.sendMessage is a Promise or undefined, we can detect if the platform is Firefox or Edge.
I think this is the only solution to handle message passing callbacks/message responses on the content scripts.
I really couldn't think of a better solution than this. So I'll be using this from now on.
But if anyone else knows a better way, a way where you don't need to send out 1 extra dummy message for Firefox and Edge per function call, that would be great!
It sucks that anything inside the content script is not persistent, and even if you store information about what platform the code is being run on, you still have to fetch the information from the background script before filtering out which runtime.sendMessage function to call on, so it doesn't really save much time.

Running Dart Sass on Gulp or Grunt

Ruby Sass is going away (unless a new maintainer takes it on) and is being replaced by a Dart implementation, according to this post:
Announcing Dart Sass
Does anyone know if there are plugins already in progress for Gulp or Grunt?
I was working on a personal project several months ago and wanted dart-sass with gulp so I made my own rudimentary function for until someone else came along and made something better. I don't remember which version dart-sass was on at the time, but here's the function anyway. It just sits right in the gulpfile.
function sassify(options) {
return through.obj(function (file, enc, cb) {
options = options || {};
options.file = file.path;
// if (file.sourceMap) {
// options.sourceMap = true;
// options.outFile = output.path('css');
// }
sass.render(options, function (err, result) {
if (err) {
console.error("Sass Error: " + err.message);
}
else {
file.contents = result.buffer;
// if (file.sourceMap) {
// applySourceMap(file, result.map);
// }
}
cb(err, file);
});
});
}
At the time, dart-sass didn't have source maps yet so I just plugged that stuff in and commented it out for when they do.
I used the function this way:
gulp.task('build:css', function () {
gulp.src(input.sass)
// .pipe(sourcemaps.init())
.pipe(sassify())
// .pipe(sourcemaps.write(output.path('cssmap')))
.pipe(concat(output.path('css')))
.pipe(gulp.dest('.'));
});
Using dart-sass from gulp should be straightforward:
https://www.npmjs.com/package/dart-sass#from-npm
npm install dart-sass
var sass = require('dart-sass');
sass.render(...)
Don't know about grunt though.
Since the news of Ruby Sass' deprecation and first official release of Dart Sass, I recently contributed the grunt-dart-sass package to the npm registry, and it looks like another user has contributed gulp-dart-sass. Since these are user-contributed packages, they were not created by the makers of Dart Sass themselves but still interface with the Dart Sass API. Hopefully, the grunt-contrib-sass project will also upgrade their package to use Dart Sass soon enough.

Is it possible to migrate preferences from a Firefox XUL addon to an SDK addon?

I'm down to the (hopefully) last hurdle in the process of migrating our extension from XUL to Firefox SDK, but I've got one last sticking point:
Preferences.
There are a number of preferences set that simply MUST be migrated when the SDK version of the addon is installed over the top of the XUL addon. These preferences are not exposed to the end user for various reasons. The preference namespacing between the two architectures are completely different. For example -
A "version_number" preference in XUL is named arbitrarily by the developer, and appears as such in about:config :
my.preference.name
However, in SDK, they are scoped to the extension in question:
extensions.[extension ID].my.preference.name
Can preferences from XUL addons be migrated for re-use inside SDK addons? If so, how?
While it didn't seem possible to read from preferences outside the SDK addon's namespace, it WAS possible to write into the EXPECTED namespace in the old XUL extension. The solution we came up with was to publish a small, final point release of the old XUL addon with a small bit of extra logic responsible for carrying out this migration before we publish the new SDK version to AMO.
Here's a pseudocode representation of our approach:
ContentScript.js
function initNewFFInstallation() {
...
if (checkIsUpgrade()) {
var keys = getPrefKeys()
migratePrefs(keys);
}
}
Utils.js - acts as a bridge to expose Overlay functionality to the content script
Util.prototype.getPrefsBranch = function() {
return Components.classes["#mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefService).
getBranch("my.prefs.ns.");
}
Util.prototype.getV2PrefsBranch = function() {
return Components.classes["#mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefService).
getBranch("extensions.[SDK_ADDON_ID].");
}
Util.prototype.setBoolPref = function(key, val) {
this.getPrefsBranch().setBoolPref(key, val);
this.getPrefsBranch().setBoolPref(key, val);
}
Util.prototype.setCharPref = function(key, val) {
this.getPrefsBranch().setCharPref (key, val);
this.getV2PrefsBranch().setCharPref (key, val);
}
//copies all the preferences over
Util.prototype.migratePrefs = function(boolPrefKeys, charPrefKeys) {
boolPrefKeys.each(function (key) {
this.getV2PrefsBranch().setBoolPref(key, this.getPrefsBranch().getBoolPref(key));
});
charPrefKeys.forEach(function (key) {
this.getV2PrefsBranch().setCharPref(key, this.getPrefsBranch().getCharPref(key));
});
}
Then in our scriptcompiler.js, which actually injects the scripts onto the page, the util methods are hooked onto the SafeWindow object.
injectScript: function(script, unsafeContentWin) {
var safeWin=new XPCNativeWrapper(unsafeContentWin);
var sandbox=new Components.utils.Sandbox(safeWin, {"sandboxPrototype":safeWin});
sandbox.window=safeWin;
sandbox.document=sandbox.window.document;
sandbox.unsafeWindow=unsafeContentWin;
var util = new Util();
//...other APIs
sandbox.migratePreferences=app_gmCompiler.hitch(util , "migratePreferences");
try {
Components.utils.evalInSandbox("(function(){"+script+"})()", sandbox);
} catch (e) {
}
}

Load an external JS library into a page using Greasemonkey

I want a translator in my Firefox. I find some code from internet. but it doesn't run in my Firefox. I have installed Greasemonkey.
function loadBingTranslator() {
script = document.createElement('script');
script.src = 'http://dict.bing.com.cn/cloudwidget/Scripts/Generated/BingTranslate_Selection_ShowIcon.js';
script.onload = initBingTranslator;
document.body.appendChild(script);
};
function initBingTranslator() {
BingCW.Init({
MachineTranslation: true,
WebDefinition: true
});
}
loadBingTranslator();
Such a script must account for the GM sandbox, and also (usually) allow time for the library to load and initialize.   See Avoid Common Pitfalls (in Greasemonkey).
So, you would use this library like so:
//--- Load the library.
var D = document;
var appTarg = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
var jsNode = D.createElement ('script');
jsNode.src = 'http://dict.bing.com.cn/cloudwidget/Scripts/Generated/BingTranslate_Selection_ShowIcon.js';
jsNode.addEventListener ("load", initBingTranslatorOnDelay, false);
appTarg.appendChild (jsNode);
//--- Allow some time for the library to initialize after loading.
function initBingTranslatorOnDelay () {
setTimeout (initBingTranslator, 666);
}
//--- Call the library's start-up function, if any. Note needed use of unsafeWindow.
function initBingTranslator () {
unsafeWindow.BingCW.Init ( {
AppID: "GM Foo",
MachineTranslation: true,
WebDefinition: true
} );
}
Issues, some specific to this question:
onload is not available; See the pitfalls. Event handlers cannot be set this way in GM. Also, addEventListener() is the best practice anyway.
Accessing JS (including libraries we load) in the page scope, requires unsafeWindow.
That app appears to want an AppID.
Sometimes, libraries like this can be loaded in the GM scope instead of the page scope, using the // #require directive.
I did not try that with this library, but with others, it may be possible.   Do not try this with untrusted libraries, as they gain extra abilities to infect your machine, once inside the GM scope.
Don't use reserved words, like "script", for variable names.
My JavaScript Console is outputting a "Component is not available"
line 10: script.onload = initBingTranslator;
So I fixed changed it to ... = initBingTranslator() because it is a function.
Now it says "BingCW is not definded"
Line 15: BingCW.Init({
MachineTranslation: true,
WebDefinition: true
});
And it is right, not sure if something is missing or this is supposed to only work in IE, I would find a Google translator solution personally (or just use an existing add-on).
Bing Dictionary hasd published a Firefox addon.
You can use it directly.

Ajax call: What is the difference between new ActiveXObject("Msxml2.XMLHTTP") and new ActiveXObject("Microsoft.XMLHTTP")?

I hope both the object invocations are referring to the ActiveXObject.
But why are we passing two different parameters to work in IE.
1. Msxml2.XMLHTTP and
2. Microsoft.XMLHTTP
Are they both same ? Or Are they browser dependent(IE7 and IE8) ?
I used both. I did not get any exception. Both are looking same for me. I am using IE 8.
Both are actually outdated. There are various versions of Microsoft's venerable MSXML ActiveX object (I believe the last one was version 5.0 and came with some version of Office.) The versions have minor differences in behavior, and bug fixes that usually don't come into play in AJAX scenarios.
Starting with IE7, Microsoft supported the standardized "XmlHttpRequest" object that other modern browsers had adopted. See http://msdn.microsoft.com/en-us/library/ms537505(VS.85).aspx. You should definitely be using that as IE7 is now the de-facto lowest common denominator. IE6 has been declared dead by most major organizations, so there's no reason to support the old Microsoft-specific ActiveX ProgIDs.
And of course, there is very little reason these days to roll your own AJAX calls, as libraries like jQuery and ASP.NET Ajax do it for you, abstracting away these obscure browser quirks. I would strongly suggest learning one of those libraries.
Jordan Rieger
jquery (at least 1.4.2) has problem on $.ajax() calling. It makes great memory leakage (like fountain)
tragedy code:
if ( window.ActiveXObject ) {
jQuery.ajaxSettings.xhr = function() {
if ( window.location.protocol !== "file:" ) {
try {
return new window.XMLHttpRequest();
} catch(xhrError) {}
}
try {
return new window.ActiveXObject("Microsoft.XMLHTTP");
} catch(activeError) {}
};
}
resolution:
if ( window.ActiveXObject ) {
jQuery.ajaxSettings.xhr = function() {
if ( window.location.protocol !== "file:" ) {
if ( window.ActiveXObject ) {
try {
return new window.ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
try {
return new window.XMLHttpRequest();
} catch(xhrError) {}
}
try {
return new window.ActiveXObject("Microsoft.XMLHTTP");
} catch(activeError) {}
};
}

Resources