THRIFT-5003: Websocket Connection in Browsers with nodejs code

* changed this to self in forEach callback

* updated minimum node version to 8.16.2 (Maintenance LTS until December 2019)
changed ws_connection.js to work in the browser, with isomorphic-ws
added exports for `wsConnection`, `createWSConnection`, `createWSClient`

* added exports for WSConnection to browser.js

* extended the sample of nodejs code in the browser with webpack

* tested and updated node version to LTS 10.18.0 Dubnium
discussion based: https://github.com/apache/thrift/pull/1927#discussion_r358140463
diff --git a/lib/nodejs/README.md b/lib/nodejs/README.md
index ed306c1..c087440 100644
--- a/lib/nodejs/README.md
+++ b/lib/nodejs/README.md
@@ -75,8 +75,8 @@
 
 thrift --gen js:node,ts,es6,with_ns
 
-```
-import * as thrift from 'thrift/browser';
+```javascript
+import * as thrift from 'thrift';
 import { MyServiceClient } from '../gen-nodejs/MyService';
 
 let host = window.location.hostname;
@@ -108,4 +108,35 @@
   });
 ```
 
-Note that thrift/index.js must be renamed or skipped for browsers.
+Bundlers, like webpack, will use thrift/browser.js by default because of the 
+`"browser": "./lib/nodejs/lib/thrift/browser.js"` field in package.json.
+
+### Browser example with WebSocket, BufferedTransport and BinaryProtocol
+```javascript
+import thrift from 'thrift';
+import { MyServiceClient } from '../gen-nodejs/MyService';
+
+const host = window.location.hostname;
+const port = 9090;
+const opts = {
+  transport: thrift.TBufferedTransport,
+  protocol: thrift.TBinaryProtocol
+}
+const connection = thrift.createWSConnection(host, port, opts);
+connection.open();
+const thriftClient = thrift.createWSClient(MyServiceClient, connection);
+
+connection.on('error', (err) => {
+  console.error(err);
+});
+
+thriftClient.myService(param)
+  .then((result) => {
+    console.log(result);
+  })
+  .catch((err) => {
+    ....
+  });
+```
+
+
diff --git a/lib/nodejs/lib/thrift/browser.js b/lib/nodejs/lib/thrift/browser.js
index 67ce853..82e5469 100644
--- a/lib/nodejs/lib/thrift/browser.js
+++ b/lib/nodejs/lib/thrift/browser.js
@@ -23,6 +23,11 @@
 exports.createXHRConnection = xhrConnection.createXHRConnection;
 exports.createXHRClient = xhrConnection.createXHRClient;
 
+var wsConnection = require('./ws_connection');
+exports.WSConnection = wsConnection.WSConnection;
+exports.createWSConnection = wsConnection.createWSConnection;
+exports.createWSClient = wsConnection.createWSClient;
+
 exports.Multiplexer = require('./multiplexed_protocol').Multiplexer;
 
 exports.TWebSocketTransport = require('./ws_transport');
diff --git a/lib/nodejs/lib/thrift/ws_connection.js b/lib/nodejs/lib/thrift/ws_connection.js
index 052cbd4..8ee8f6e 100644
--- a/lib/nodejs/lib/thrift/ws_connection.js
+++ b/lib/nodejs/lib/thrift/ws_connection.js
@@ -17,18 +17,16 @@
  * under the License.
  */
 var util = require('util');
-var WebSocket = require('ws');
+var WebSocket = require('isomorphic-ws');
 var EventEmitter = require("events").EventEmitter;
 var thrift = require('./thrift');
-var ttransport = require('./transport');
-var tprotocol = require('./protocol');
 
 var TBufferedTransport = require('./buffered_transport');
 var TJSONProtocol = require('./json_protocol');
 var InputBufferUnderrunError = require('./input_buffer_underrun_error');
 
 var createClient = require('./create_client');
-
+var jsEnv = require('browser-or-node');
 exports.WSConnection = WSConnection;
 
 /**
@@ -69,7 +67,7 @@
  * @throws {error} Exceptions other than ttransport.InputBufferUnderrunError are rethrown
  * @event {error} The "error" event is fired when a Node.js error event occurs during
  *     request or response processing, in which case the node error is passed on. An "error"
- *     event may also be fired when the connectison can not map a response back to the
+ *     event may also be fired when the connection can not map a response back to the
  *     appropriate client (an internal error), generating a TApplicationException.
  * @classdesc WSConnection objects provide Thrift end point transport
  *     semantics implemented using Websockets.
@@ -80,7 +78,6 @@
   EventEmitter.call(this);
 
   //Set configuration
-  var self = this;
   this.options = options || {};
   this.host = host;
   this.port = port;
@@ -113,14 +110,13 @@
 };
 
 WSConnection.prototype.__onOpen = function() {
-  var self = this;
   this.emit("open");
   if (this.send_pending.length > 0) {
     //If the user made calls before the connection was fully
     //open, send them now
     this.send_pending.forEach(function(data) {
-      self.socket.send(data);
-    });
+      this.socket.send(data);
+    }, this);
     this.send_pending = [];
   }
 };
@@ -184,7 +180,7 @@
 };
 
 WSConnection.prototype.__onData = function(data) {
-  if (Object.prototype.toString.call(data) == "[object ArrayBuffer]") {
+  if (Object.prototype.toString.call(data) === "[object ArrayBuffer]") {
     data = new Uint8Array(data);
   }
   var buf = new Buffer(data);
@@ -207,7 +203,7 @@
  * @returns {boolean}
  */
 WSConnection.prototype.isOpen = function() {
-  return this.socket && this.socket.readyState == this.socket.OPEN;
+  return this.socket && this.socket.readyState === this.socket.OPEN;
 };
 
 /**
@@ -215,11 +211,15 @@
  */
 WSConnection.prototype.open = function() {
   //If OPEN/CONNECTING/CLOSING ignore additional opens
-  if (this.socket && this.socket.readyState != this.socket.CLOSED) {
+  if (this.socket && this.socket.readyState !== this.socket.CLOSED) {
     return;
   }
   //If there is no socket or the socket is closed:
-  this.socket = new WebSocket(this.uri(), "", this.wsOptions);
+  if (jsEnv.isBrowser) {
+    this.socket = new WebSocket(this.uri());
+  } else {
+    this.socket = new WebSocket(this.uri(), "", this.wsOptions);
+  }
   this.socket.binaryType = 'arraybuffer';
   this.socket.onopen = this.__onOpen.bind(this);
   this.socket.onmessage = this.__onMessage.bind(this);
@@ -245,8 +245,8 @@
   var host = this.host;
 
   // avoid port if default for schema
-  if (this.port && (('wss' == schema && this.port != 443) ||
-    ('ws' == schema && this.port != 80))) {
+  if (this.port && (('wss' === schema && this.port !== 443) ||
+    ('ws' === schema && this.port !== 80))) {
     port = ':' + this.port;
   }