diff --git a/README.md b/README.md index f13a9a98e..3012c2e2e 100644 --- a/README.md +++ b/README.md @@ -467,13 +467,13 @@ The arguments are: - `log`: custom log function. Default uses [debug](https://www.npmjs.com/package/debug) package. - `manualConnect`: prevents the constructor to call `connect`. In this case after the `mqtt.connect` is called you should call `client.connect` manually. - `timerVariant`: defaults to `auto`, which tries to determine which timer is most appropriate for you environment, if you're having detection issues, you can set it to `worker` or `native`. If none suits you, you can pass a timer object with set and clear properties: - ```js - timerVariant: { - set: (func, timer) => setInterval(func, timer), - clear: (id) => clearInterval(id) - } - ``` - + ```js + timerVariant: { + set: (func, timer) => setInterval(func, timer), + clear: (id) => clearInterval(id) + } + ``` + - `forceNativeWebSocket`: set to true if you're having detection issues (i.e. the `ws does not work in the browser` exception) to force the use of native WebSocket. It is important to note that if set to true for the first client created, then all the clients will use native WebSocket. And conversely, if not set or set to false, all will use the detection result. - `unixSocket`: if you want to connect to a unix socket, set this to true In case mqtts (mqtt over tls) is required, the `options` object is passed through to [`tls.connect()`](http://nodejs.org/api/tls.html#tls_tls_connect_options_callback). If using a **self-signed certificate**, set `rejectUnauthorized: false`. However, be cautious as this exposes you to potential man in the middle attacks and isn't recommended for production. @@ -905,6 +905,7 @@ Supports [WeChat Mini Program](https://mp.weixin.qq.com/). Use the `wxs` protoco ```js import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only' // import before mqtt. +import 'esbuild-plugin-polyfill-node/polyfills/navigator' const mqtt = require("mqtt"); const client = mqtt.connect("wxs://test.mosquitto.org", { timerVariant: 'native' // more info ref issue: #1797 diff --git a/esbuild.js b/esbuild.js index c05b0bfb1..f157201d7 100644 --- a/esbuild.js +++ b/esbuild.js @@ -21,15 +21,7 @@ const options = { polyfillNode({ polyfills: [ 'readable-stream' - ], - globals: { - global: false, - __dirname: false, - __filename: false, - buffer: true, - process: true, - navigator: true, // Needed for WeChat, ref #1789 - } + ] }), { name: 'resolve-package-json', diff --git a/src/lib/client.ts b/src/lib/client.ts index da9597b7f..b9fa98480 100644 --- a/src/lib/client.ts +++ b/src/lib/client.ts @@ -282,6 +282,10 @@ export interface IClientOptions extends ISecureClientOptions { * or pass a custom timer object */ timerVariant?: TimerVariant | Timer + /** + * false, set to true to force the use of native WebSocket if you're having issues with the detection + */ + forceNativeWebSocket?: boolean } export interface IClientPublishOptions { diff --git a/src/lib/connect/index.ts b/src/lib/connect/index.ts index 3acfbdf59..a25863f78 100644 --- a/src/lib/connect/index.ts +++ b/src/lib/connect/index.ts @@ -6,7 +6,7 @@ import MqttClient, { MqttClientEventCallbacks, MqttProtocol, } from '../client' -import IS_BROWSER from '../is-browser' +import isBrowser from '../is-browser' import { StreamBuilder } from '../shared' // Handling the process.nextTick is not a function error in react-native applications. @@ -16,24 +16,7 @@ if (typeof process?.nextTick !== 'function') { const debug = _debug('mqttjs') -const protocols: Record = {} - -if (!IS_BROWSER) { - protocols.mqtt = require('./tcp').default - protocols.tcp = require('./tcp').default - protocols.ssl = require('./tls').default - protocols.tls = protocols.ssl - protocols.mqtts = require('./tls').default -} else { - protocols.wx = require('./wx').default - protocols.wxs = require('./wx').default - - protocols.ali = require('./ali').default - protocols.alis = require('./ali').default -} - -protocols.ws = require('./ws').default -protocols.wss = require('./ws').default +let protocols: Record = null /** * Parse the auth attribute and merge username and password in the options object. @@ -152,6 +135,30 @@ function connect( } } + // only loads the protocols once + if (!protocols) { + protocols = {} + if (!isBrowser && !opts.forceNativeWebSocket) { + protocols.ws = require('./ws').streamBuilder + protocols.wss = require('./ws').streamBuilder + + protocols.mqtt = require('./tcp').default + protocols.tcp = require('./tcp').default + protocols.ssl = require('./tls').default + protocols.tls = protocols.ssl + protocols.mqtts = require('./tls').default + } else { + protocols.ws = require('./ws').browserStreamBuilder + protocols.wss = require('./ws').browserStreamBuilder + + protocols.wx = require('./wx').default + protocols.wxs = require('./wx').default + + protocols.ali = require('./ali').default + protocols.alis = require('./ali').default + } + } + if (!protocols[opts.protocol]) { const isSecure = ['mqtts', 'wss'].indexOf(opts.protocol) !== -1 // returns the first available protocol based on available protocols (that depends on environment) diff --git a/src/lib/connect/ws.ts b/src/lib/connect/ws.ts index 1e8060c9e..dc72cae69 100644 --- a/src/lib/connect/ws.ts +++ b/src/lib/connect/ws.ts @@ -3,7 +3,7 @@ import { Buffer } from 'buffer' import Ws, { ClientOptions } from 'ws' import _debug from 'debug' import { DuplexOptions, Transform } from 'readable-stream' -import IS_BROWSER from '../is-browser' +import isBrowser from '../is-browser' import MqttClient, { IClientOptions } from '../client' import { BufferedDuplex, writev } from '../BufferedDuplex' @@ -44,7 +44,7 @@ function setDefaultOpts(opts: IClientOptions) { if (!opts.wsOptions) { options.wsOptions = {} } - if (!IS_BROWSER && opts.protocol === 'wss') { + if (!isBrowser && !opts.forceNativeWebSocket && opts.protocol === 'wss') { // Add cert/key/ca etc options WSS_OPTIONS.forEach((prop) => { if ( @@ -298,4 +298,4 @@ const browserStreamBuilder: StreamBuilder = (client, opts) => { return stream } -export default IS_BROWSER ? browserStreamBuilder : streamBuilder +export { browserStreamBuilder, streamBuilder } diff --git a/src/lib/is-browser.ts b/src/lib/is-browser.ts index d614d8be5..cdf926a3e 100644 --- a/src/lib/is-browser.ts +++ b/src/lib/is-browser.ts @@ -25,9 +25,6 @@ const isStandardBrowserEnv = () => { return false } -const isTxikijsEnv = () => - typeof navigator !== 'undefined' && navigator.userAgent === 'txiki.js' - const isWebWorkerEnv = () => Boolean( // eslint-disable-next-line no-restricted-globals @@ -40,10 +37,7 @@ const isReactNativeEnv = () => typeof navigator !== 'undefined' && navigator.product === 'ReactNative' const isBrowser = - isStandardBrowserEnv() || - isWebWorkerEnv() || - isReactNativeEnv() || - isTxikijsEnv() + isStandardBrowserEnv() || isWebWorkerEnv() || isReactNativeEnv() export const isWebWorker = isWebWorkerEnv()