Hi There!
Thanks a lot for your work on this amazing library.
I've been fighting a lot with the browser builds, for several reasons:
rm -rf node_modules, which is too oftenSo, that's my problem, and here is my solution, which aims to be as simple as it gets
dist/mqtt.js to the source files, so I can easily require(mqtt/dist/mqtt). Names can be discussed but the important thing is to have that file availableThere are other variations of this solution but I think this works and it's super simple and you already got the script to generate those dist files, the only remaining thing to do would be to un-ignore dist and to fix all the pre-commit checks that fail on those dist files
What do you think?
There might be more fancy solutions and Im open to anything but this requires minimal work and provides maximum satisfaction
Other easy solution is to add a postinstall hook that creates the build every time someone installs the package
Hey @franleplant, I understood your solution but I did not understand the problem you are facing.
You can easily do require('mqtt/dist/mqtt'), it should work. It's inside the package in the lastest versions, so there should be no problem.
Wow, apparently I'm blind, I need 馃憮 . I did found however this in the gitignore https://github.com/mqttjs/MQTT.js/blob/master/.gitignore#L10 which might have confused me.
So, two more things before closing
dist/mqttUnable to resolve module `./store` from `Users/flp/code/MyProject/node_modules/mqtt/dist/mqtt.js`
This is the way Im importing it
const mqtt = require('mqtt/dist/mqtt')
The mqtt dist are made with browserify and my project uses webpack and react native, there might be some incompatibilities with the module systems?
Thanks a lot for your help
@franleplant that is highly possible. You probably have to have your webpack build it together with your application
So, after all, Im not using webpack, React Native uses it's own build system (analogue to Webpack and Browserify): Packager
Some more relevant information about other's peoples problems: https://github.com/facebook/react-native/issues/1871
Potential solution I've tested is ReactNativify but in the end it didn't work with mqtt lib.
TLDR
Since React-Native uses Packager, a lot of hybrid node.js packages that depend on node.js modules or their shims via browserify/webpack do not work on React Native.
@franleplant In the end what was your solution for MQTT on React Native?
hey @keyeh so after a lot of battling I ended up using https://github.com/rh389/react-native-paho-mqtt
It's rather immature and I've already had submit a patch but it's all that we got. Kudos to the author though, very responsive and nice to work with.
I'd love to use mqtt.js but I didn't find a way to easily make it work with React Native Packager.
Also the lib needs to accept WebSocket and LocalStorage implementations as parameters, since the React Native environment is different from the Browser, so things such as localStorage don't exist.
Paho let's you use whatever store that implements an interface as a replacement for LocalStorage.
I hope this helps.
I'm going to be working on React-Native support within the next two weeks, I had an initial attempt that let me compile the module successfully, but it resulted in runtime errors. I'll post here when I have progress.
@RangerMauve let me know if there is something I can take a look, give you feedback, give you PRs, because Im right now working on an RN App that uses mqtt, so I can live test it.
@franleplant Thanks for the offer! Here's the PR I did to get the ball rolling and discussion around it: https://github.com/nodejs/readable-stream/pull/258
The original problem was that readable-stream was trying to require the stream module which was causing RN's bundler to freak out because it didn't see that module anywhere in its dependency graph (since it's a node thing).
I added a fix to explicitly exclude the stream module for RN, but now the issue is that excluding it still returns an empty object, which will cause util.inherits to freak out.
My idea (when I get around it it, or somebody else does), is to add a check so that if Stream is required properly, we should add a check to see if it actually has some stream-related property defined before using it.
Something like
var Stream;
(function () {
try {
Stream = require('st' + 'ream');
} catch (_) {} finally {
if (!Stream) Stream = require('events').EventEmitter;
}
// This is the addiition
if(!Stream.on) Stream = require('events').EventEmitter;
})();
You can try modifying the file in your node_modules folder to see if it works and if there's other issues that pop up.
Cool, Im going to investigate a bit next week, if I can make my self some time.
Thanks a lot for your participation!
Well, I'm going to get it to work by the end of April for sure since it's relevant to my day job. We've just been focusing on a react-native-web version first, so I hadn't gotten around it to it yet. :P
Sorry for using this thread as a forum, feel free to kick me out but this info is interesting for mqtt and react native and the community and does not require any effort from the mqtt.js maintainers.
So, I tried to make mqtt.js work with React native and went through a bunch of hoops but I think I made some progress, Im stuck in a place right now which if I understand how to get out I will update this post with it, but perhaps someone can help me with this.
These are the steps that I took to get to the point where I am now.
1 npm install mqtt
2 Run this mqtt readme example somewhere in your app: https://github.com/mqttjs/MQTT.js#example
3 Install native dependencies
npm install url events path buffer assert
In your package.json add these to your deps
"fs": "git://github.com/mafintosh/browserify-fs.git#06414a74bc0e1f3a92f1891ae27f5594692967b8",
"os": "git://github.com/CoderPuppy/os-browserify.git#af8f17481c8097e679ea24700c6bf18d497ba3a1",
These point to today's master's top of each repo, you can update the commit hash accordingly.
This step basically says to your dependency tree (i.e. mqtt.js dependencies) that when doing
require('fs') use instead this require('browserify-fs'), it is pretty dirty but requires minimal effort
Make sure it looks something like this
import React from 'react';
import { AppRegistry } from 'react-native';
// Define globally required stuff
GLOBAL.Buffer = require('buffer').Buffer;
// Some dependencies require process to be defined, so we comply with that
GLOBAL.process = {
browser: true,
env: {
NODE_ENV: __DEV__ ? 'development' : 'production',
}
}
// Make sure to use require instead of import syntax since the former
// will respect the order of things
const App = require('./app');
AppRegistry.registerComponent('MyApp', () => App);
Get stuck with this error:
Cannot read property 'prototype' of undefined
Which basically refers to this file
node_modules/websocket-stream/server.js
var inherits = require('inherits')
// Server is undefined, and that is the problem
var WebSocketServer = require('ws').Server
var stream = require('./stream')
module.exports = Server
function Server(opts, cb) {
if (!(this instanceof Server)) {
return new Server(opts, cb)
}
WebSocketServer.call(this, opts)
var proxied = false
this.on('newListener', function(event) {
if (!proxied && event === 'stream') {
proxied = true
this.on('connection', function(conn) {
this.emit('stream', stream(conn, opts))
})
}
})
if (cb) {
this.on('stream', cb)
}
}
// In here, inherits tries to access WebSocketServer.prototype to
// do the inheritance but WebSocketServer is undefined
inherits(Server, WebSocketServer)
Im going to try to keep bashing at this, but if anyone has some insights they will be highly appreciated.
@RangerMauve probably this could be a very simple approach for resolving the mqtt.js in React Native problem
That error is kind of weird. It shouldn't be requiring that file and instead should be getting stream.js in websocket-stream directly. What OS are you developing on?
Also, are you using the latest version of MQTT.js?
Also, what version of React-Native are you using for bundling?
OSX
The file looks pretty unconditional to the operative system or anything for that matter
Are you 100% sure that the error is within that file and not in here? Can you post a stack trace?
100% sure because Im not doing anything magical, Im just following the stack trace. The first item is the inherits function def, and then it's that pointed file.

Make sure you follow my steps to see in you can replicate this problem. The problem with the stream might have been solved by steps 3 or 5.
What version of MQTT.js and websocket-stream are you seeing in your package.json?
That file shouldn't even be imported because websocket stream specifies a browser field in it's package.json which should prevent it from loading server.js and instead only load stream.js.
It could be that either websocket-stream or packager are out of date if that alias isn't being effected.
Edit: Not package.json, node_modules folder
mqtt@^2.5.0:
resolved "https://registry.yarnpkg.com/mqtt/-/mqtt-2.5.0.tgz#399078217ea361ae923d8de407c981ab8290968e"
websocket-stream@^3.3.3:
resolved "https://registry.yarnpkg.com/websocket-stream/-/websocket-stream-3.3.3.tgz#361da5404a337e60cfbc29b4a46368762679df0b"
Greped from my yarn lock
That's weird, Im going to try to update my react native cli
Also, I think I saw that one of the problems with packager is that it doesnt recursively apply the "browser" field resolve, I need to find the issue where they disscuss about it though
My react native version is the latest:
react-native --version
react-native-cli: 2.0.1
react-native: 0.42.2
I would recommend to follow my steps to see where you get to
Hmm, sadly I don't have time today since I've gotta work on other stuff, but as I said, I'll be getting to it in about a week.
In the meantime, there's definitely something fishy happening with the packager not respecting the browser field. Maybe also look into updating your react-native version of the project to something a little newer.
AFAIK even though the CLI is installed globally, the scripts defined in your project for npm run start should be using the local version of the CLI in node_modules. When I was mucking about with the packager for a different reason, I had to modify it in my project rather than globally. I may be wrong, though, depending on how you're running your project.
I've been dealing with the "property of undefined" issue for the last week.
My findings on this is that it is a problem with React Native's packager not using correctly the browser field in package.json.
This only happens when you are trying to override the main file in your package.json. To give an example:
"main": "mqtt.js",
"browser": {
"./mqtt.js": "./lib/connect/index.js"
}
works fine with webpack, but with React Native, mqtt.js is not overriden correctly by lib/connect/index.js.
I made a test where you would create an extra hop to avoid using the main file in the browser field. That would be:
index.js
module.exports = require('./mqtt');
package.json
"main": "index.js",
"browser": {
"./mqtt.js": "./lib/connect/index.js"
}
This worked for me, but it is just a hack. The real problem seems to be the packager on React Native is not correctly replacing mqtt.js for client since it is also the package.json's main file.
@alexleonescalera Good find! You should open an issue in their repo so that somebody looks into it. :D
good work @alexleonescalera, just to double check, by adding this "./mqtt.js": "./lib/connect/index.js" to the React Native app package.json you can use mqtt.js without further problems?
I don't think so. The mapping from mqtt.js to lib/connect/index.js happens in the MQTT.js project's package.json, not in your React Native's package.json (unless I understood incorrectly your question).
Some additional info:
From playing around with MQTT.js and websocket-stream inside the node_modules folder in my React Native project, it seems that the react-native field inside package.json is automatically generated somehow. Still, the issue comes in.
I'm currently trying to come up with shareable code, since my findings are based on proprietary code. I'll open an issue on React Native project once I have this.
Just for insight, here is how my MQTT node_modules/mqtt/package.json file looks like inside my React Native project.
package.json.txt
Refer to lines 57 (browser), 135 (main) and 167 (react-native).
FYI: opened an issue on React Native:
https://github.com/facebook/react-native/issues/13474
Managed to get this project running in React Native, though I needed to fork and do some minor changes.
The fork is available with instructions on getting it up and running via github and npmjs
As mentioned in the readme, this works for TCP connections but not WebSockets, that's still a work in progress.
if anyone has an alternative (read: easier) way to get it working in React Native please let me know. Simply using the browserify build caused the react native packager to choke for me, and none of the above approaches completely worked.
Note: I have tested this using RN 0.47.1
Would you like to send a PR to improve the support for RN in here? You shouldn鈥檛 have to fork to make it run there, it would simplify maintenance if we work together.
Hello @nofarius
I just tried using your fork. No luck connecting to a broker yet. However, when the app is run with debugger attached, it throws
Exception has occurred: TypeError
TypeError: process.send is not a function
at postMessage (/Users/cltsang/Documents/IotApp/.vscode/.react/debuggerWorker.js:40:13)
at sendReply (/Users/cltsang/Documents/IotApp/.vscode/.react/debuggerWorker.js:107:7)
at executeApplicationScript (/Users/cltsang/Documents/IotApp/.vscode/.react/debuggerWorker.js:92:7)
at /Users/cltsang/Documents/IotApp/.vscode/.react/debuggerWorker.js:113:7
at process.<anonymous> (/Users/cltsang/Documents/IotApp/.vscode/.react/debuggerWorker.js:35:9)
at emitTwo (events.js:125:13)
at process.emit (events.js:213:7)
at emit (internal/child_process.js:774:12)
at _combinedTickCallback (internal/process/next_tick.js:141:11)
at process._tickCallback (internal/process/next_tick.js:180:9)
Is it just my setup? Or is it that using rn-mqtt means losing the ability to debug? If it's related, I'm using the RN 0.49.3
@nofarius @mcollina : did this ever get any further? I'm stuck using paho on react native right now and would obviously love to transition to MQTT.js
@PCaponetti I have it working with MQTT.js 2.4.0 and websocket-stream ^3.3.3
Not sure why. :P
@mcollina Hi.
How exactly did you get it to work?
@irfanka I am not a react-native user. If anyone wants to devote the effort of making this module work as-is with react-native, I'm more than encouraging them to do this. I have absolutely no bandwidth to help.
@irfanka @mc
I'm using the following modules and making sure they are imported before anything else:
import {Buffer} from "buffer"; global.Buffer = Buffer;import process from "process"; global.process = process;In addition, I'm using
1.14.1 (had some issues with reconnecting with 2.4.0^3.3.32.2.30.0.2I don't remember how we got to this combination, but we just kept fiddling with things until it worked. Haven't had time to investigate using the latest MQTT.js, but this could be a good starting point.
In addition, we listen on AppState.addEventListener("change", etc...) and invoke mqttClient._checkPing() if the state is active in order to force the connection to attempt to reconnect when the app comes into focus because the JS timers don't work while it's in the background.
I have it working with MQTT.js 2.4.0 and websocket-stream ^3.3.3
@RangerMauve Are you successfully set up MQTT.js in react native (both iOS & android) specially websocket in production?
@behrad Yes, it's been up and running for a few months now without too many issues.
We found that when the app goes in the background the timers for the keepalive don't run, so we force Android to attempt to reconnect when it regains focus.
Other than that it's working perfectly.
Nice, let us test https://github.com/mqttjs/MQTT.js/issues/573#issuecomment-355039873 and see how it goes. I may post you results if any issues 馃憤
@RangerMauve I'm currently attempting to take advantage of MQTT in a react native project, I follow your steps, but receiving the following error on core-util-is.
Buffer is not defined on util.js
Did you experience the same problem?
Yes. You will have it complaining about some node specific global variables being missing. Make a new file that defines global.process, global.Buffer and global.self. make sure to import this file before anything else.
So I did everything that @RangerMauve did plus add the url module as well and I also installed version 1.14.1 as well, but I'm getting this error:
bundling failed: UnableToResolveError: Unable to resolve module `events` from
`/Users/richardlai/Profab/Spark/node_modules/mqtt/lib/client.js`:
Module does not exist in the module map
EDIT also had to install the following modules:
events
util
Also make sure you're doing:
import { Buffer } from 'buffer'
instead of
import Buffer from 'buffer'
before you globalize it
I'm now getting this error when I try to use it like this:
var client = mqtt.connect({
servers: [{ host: 'localhost', port: 1883 }],
username: 'blah',
password: 'pw',
})
Error:
Could not determine host. Specify host manually.
@rclai Thanks for the update! I'll add a doc somewhere once we have the steps figured out. It's been months since we set it up so I was probably missing some things. 馃摝
I always use the URL method of connecting in our app.
Also, please note that I've only got the websocket version of MQTT working since React-Native is basically a browser environment and doesn't provide Node's TCP stack.
Good point, don't know why I didn't realize that. I switched over to passing the URL in the first argument.
There's a part of the mqtt code that's trying to parse the websocket URL that breaks:
function buildBuilderBrowser (mqttClient, opts) {
var url, parsed;
if ('undefined' !== typeof (document)) { // for Web Workers! P.S: typeof(document) !== undefined may be becoming the faster one these days.
parsed = _URL.parse(document.URL);
} else {
throw new Error('Could not determine host. Specify host manually.');
}
// ...
}
Did you have to polyfill the document object somehow?
__EDIT__: Oddly enough I did this:
global.document = {
URL: 'http://localhost:1884',
}
And it worked, but why does it need document.URL for? Isn't it supposed to use the URL that I passed to it?
I'm not sure, actually. Maybe @mcollina Has more insight on what's happening there.
Maybe it has to do with you using the object form of mqtt.connect instead of passing in a string URL.
Yeah, but I am passing it as a string now and it still needs that weird global.document polyfill I did.
I think that might just be something that needs to be done for this to work. Getting stuff that was made for node or for the browser to work in React-Native is a bit of a dark art at the moment. 馃槄
Any news on this? I'd love to have detailed info on how to integrate with React Native. Maybe we can add instructions in the readme?
Thanks.
Try following the steps I had in https://github.com/mqttjs/MQTT.js/issues/573#issuecomment-355039873
import {Buffer} from "buffer"; global.Buffer = Buffer;
@RangerMauve
Where should I put this line to make sure imported before anything else.
I try to put index.js(root), but it's not work.
There only way i found is put to 'node_modules/core-util-is/lib/util' but it's not recommend way
@tomzaku I usually have a separate file, bootstrap.js, which I have all my weird global-adding code. Then I make sure that it's the first file that gets imported in index.js.
The way import works is different then require because all of your dependencies are loaded and executed before your current file gets to execute. That's why all your bootstrapping code should be in a different file that's guaranteed to be the first one to be imported.
This is what my bootstrap.js looks like:
import global from "global";
import {
Buffer
} from "buffer";
import process from "process";
global.Buffer = Buffer;
global.process = process;
if(!global.self)
global.self = global;
@RangerMauve Can we use this solution (or other) to use mqtt://rabbitmqBroker to send messages to RabbitMQ broker, through react-native app? Or it only works with use of websockets(ws://rabbitmqBroker)?
@angelos3lex I haven't used a non-websocket broker with this technique yet, so I can't say for sure, but you might be able to get it to work by using the react-native-tcp library and aliasing net to react-native-tcp to have mqtt.js use it when it loads.
Let me know if you get it to work or have any trouble setting it up.
install
npm install react-native-tcp --save
react-native link react-native-tcp
npm i stream-browserify stream -g
npm install buffer
npm install url events path buffer assert
npm install mqtt --save
edit node_modules/mqtt/package.json
"browser": {
"./mqtt.js": "./lib/connect/index.js",
"fs": false,
"tls": false,
"net": "react-native-tcp"
},
app.js
global.Buffer = global.Buffer || require('buffer').Buffer;
global.process.version = '';
var mqtt = require('mqtt')
var client = mqtt.connect('mqtt://test.mosquitto.org')
client.on('connect', function () {
client.subscribe('presence', function (err) {
if (!err) {
client.publish('presence', 'Hello mqtt')
}
})
})
client.on('message', function (topic, message) {
// message is Buffer
console.log(message.toString())
client.end()
})
install
npm install react-native-tcp --save react-native link react-native-tcp npm i stream-browserify stream -g npm install buffer npm install url events path buffer assert npm install mqtt --saveedit node_modules/mqtt/package.json
"browser": { "./mqtt.js": "./lib/connect/index.js", "fs": false, "tls": false, "net": "react-native-tcp" },app.js
global.Buffer = global.Buffer || require('buffer').Buffer; global.process.version = ''; var mqtt = require('mqtt') var client = mqtt.connect('mqtt://test.mosquitto.org') client.on('connect', function () { client.subscribe('presence', function (err) { if (!err) { client.publish('presence', 'Hello mqtt') } }) }) client.on('message', function (topic, message) { // message is Buffer console.log(message.toString()) client.end() })
It works in Android ,
but I get "mqtt stream error:received bad response code from server 403" in ios
Try using Websockets instead of TCP
Also, rn-nodeify might help with getting modules to work properly.
i used rn-nodeify but got error
@RangerMauve
Error: Could not determine host. Specify host
Code
export const DEFAULT_MESSAGING_OPTION = {
// Authentication
// username: 'emqx',
// password: 'emqx',
keepalive: 100000,
protocol: 'mqtt',
port: 1883,
clean: true
}
export const MESSAGING_URL = '66.42.60.2'
socketInstance = mqtt.connect(MESSAGING_URL, options)
socketInstance.on('connect', function () {
console.show('Connected to', MESSAGING_URL)
socketInstance.subscribe('presence', function (err) {
if (!err) {
socketInstance.publish('presence', 'Hello mqtt')
}
})
})
shim.js
if (typeof __dirname === 'undefined') global.__dirname = '/'
if (typeof __filename === 'undefined') global.__filename = ''
if (typeof process === 'undefined') {
global.process = require('process')
} else {
const bProcess = require('process')
for (var p in bProcess) {
if (!(p in process)) {
process[p] = bProcess[p]
}
}
}
process.browser = false
if (typeof Buffer === 'undefined') global.Buffer = require('buffer').Buffer
// global.location = global.location || { port: 80 }
const isDev = typeof __DEV__ === 'boolean' && __DEV__
process.env['NODE_ENV'] = isDev ? 'development' : 'production'
if (typeof localStorage !== 'undefined') {
localStorage.debug = isDev ? '*' : ''
}
// If using the crypto shim, uncomment the following line to ensure
// crypto is loaded first, so it can populate global.crypto
// require('crypto')
script
node_modules/.bin/rn-nodeify --install url,process,buffer,events,util --hack --yarn
There seems to be a weird character in your strings, is that on purpose?
@RangerMauve Thanks! i fixed that issue. but Client doesn't connect and no error is emitted
You're sure you got the right host/port and that your broker supports websockets?
@RangerMauve yes, you can try it
http://mqttfx.jensd.de/index.php/download
IP:66.42.60.2
port: 1883
my setup
https://i.gyazo.com/ee8bbd8541401609da7bf0ad8861f456.png
@RangerMauve Thanks! i fixed that issue. but Client doesn't connect and no error is emitted
Exact same problem, anyone has an update?
@vasupol11 @RangerMauve it worked with "react-native-mqtt-client" and "rn-nodeify"
run below script after "npm install"
node_modules/.bin/rn-nodeify --install stream,net,url,process,buffer,events,util --hack
Example:
import connect from 'react-native-mqtt-client'
export default async (clientId) => {
// const clientId = await deviceInfo.getUniqueID()
return eventChannel(emitter => {
try {
if (socketInstance !== null) {
socketInstance.end()
socketInstance = null
}
const options = {
...DEFAULT_MESSAGING_OPTION,
clientId
}
console.show('MQTT Connect', MESSAGING_URL)
socketInstance = connect(MESSAGING_URL, options)
socketInstance.on('connect', () => {
console.show('MQTT Connected', MESSAGING_URL)
emitter({ type: MESSAGES.CONNECTED, url: MESSAGING_URL })
})
socketInstance.on('message', (topic, message) => {
console.show(`Message Topic ${topic}`, topic, message.toString())
try {
const data = JSON.parse(message.toString())
emitter({ type: MESSAGES.EVENT, topic, message: data, success: true })
if (listeners[topic] && typeof listeners[topic] === 'function') {
listeners[topic](data, topic)
}
} catch (err) {
}
})
} catch (err) {
console.problem(err)
}
return () => {
if (socketInstance !== null) {
socketInstance.end()
socketInstance = null
}
}
})
}
@zrg-team That's great to hear, thank you for sharing! :D
I'm afraid it doesn't work. @zrg-team @RangerMauve .
https://www.npmjs.com/package/@taoqf/react-native-mqtt
This will do, and easy to be used. Thanks you all.
Any update on this issue?
https://www.npmjs.com/package/@taoqf/react-native-mqtt
This will do, and easy to be used. Thanks you all.
This works. FINALLY 馃帀馃帀
Most helpful comment
install
edit node_modules/mqtt/package.json
app.js