awwx / meteor-offline-data

Meteor offline data project.
MIT License
111 stars 9 forks source link

Reactively not shared across browser windows in node-webkit #28

Open JarnoLeConte opened 10 years ago

JarnoLeConte commented 10 years ago

This is my first post on Github, so let me know when i'm doing things wrong.

I created an native desktop application using node-webkit, that lets you write desktop apps with HTML, CSS and JavaScript. I embedded the Meteor framework including the offline-data packages. You can do really cool stuff with these frameworks.

Now I'm opening 2 node-webkit windows that are pointing to the same url running the same Meteor application. It looks great at first sight. The same Offline.Collections are loaded and contains the same content. However I found out that reactive contexts are not shared across this two windows, but the same application opened in a browser (Google Chrome) doing so, so I was wondering why that is?

Node-webkit is built on Chrome, so what is the difference? Where the offline-data packages depends on? Which of this dependencies are present in the browser but not in node-webkit? I'm confused because the Offline.Collections are working correct but the reactively not.

awwx commented 10 years ago

Thanks for the detailed description!

offline-data has two mechanisms for communicating across windows: it will use a shared web worker if it is supported by the browser, or it will fallback to using https://github.com/awwx/meteor-browser-msg (which uses the local storage "storage" event to send messages to the other browser windows).

The first thing to check is Offline.persistent. If this is false, then offline-data doesn't think the browser supports it, and the API will act like a regular Meteor.Collection. https://raw.github.com/awwx/meteor-offline-common/v0.1.2/offline.litcoffee shows the code which checks if offline-data can be supported. If Offline.persistent is false, check

If Offline.persistent is true, then offline-data thinks it should work, but something isn't working.

What is the value of Offline._usingSharedWebWorker? If false, but Package['browser-msg'].supported is true, then offline-data is trying to use browser-msg. (But if offline-data is using the shared web worker, browser-msg isn't used at all).

If browser-msg is being used, it is possible that your environment isn't supporting the local storage "change" event. You can try the https://github.com/awwx/meteor-browser-msg/tree/v1.1.0/test/consecutive-messages test to see if browser-msg is working.

JarnoLeConte commented 10 years ago

It looks like that the offline-data package is fully operational, because: Offline.persistent = true Offline._usingSharedWebWorker = true That mains that something isn't working correctly.

Just for sure, I mention that the offline storage works correct. When you save something in one window it will be visible in the other after manually render the template. But the automatic render (reactively) doesn't working.

Is there something not working in the package? What can I try? Or is it a restriction of node-webkit (I guess not)?

JarnoLeConte commented 10 years ago

Update: I noticed that offline reactively isn't the only thing that isn't working. In node-webkit there is also no synchronization with the server. Before I only used the Offline.Collection without declaring a Meteor.Collection on the server, but I tried to do so (including publish and subscriptions), an now it looks like there is no synchronization at all. In node-webkit only the local storage data is accessible when using Offline.Collection. Again, the same application in the browser is working correctly.

It is maybe obvious but I noticed that the callback 'worker.port.onmessage' (in worker-client.litcoffee) is never called in other windows. And I don't know how to debug worker-boot.js

awwx commented 10 years ago

Let's try using browser-msg instead of the shared web worker, as that will tell us if the problem is with the shared web worker.

First run the https://github.com/awwx/meteor-browser-msg/tree/v1.1.0/test/consecutive-messages test and check that browser-msg is working in your environment.

Then download https://github.com/awwx/meteor-offline-todos/blob/master/disable-worker.json and run your application with

meteor --settings disable-worker.json

You should see that Offline.persistent is still true and Offline._usingSharedWebWorker is now false.

If things are now working then there's some bug using the shared web worker.

JarnoLeConte commented 10 years ago

I followed your steps -> browser-msg test & example work correctly -> I'm now running my project without workers Problem solved! This is one possible solution. Thanks so far!

But I'm still interested in making the SharedWorker work. The browser-msg is (a little) slower.

awwx commented 10 years ago

Good, now we know the problem is somewhere with the shared web worker.

Try the first example in http://www.w3.org/TR/workers/#shared-workers-introduction (Live at http://www.whatwg.org/demos/workers/shared/001/test.html) This will tell you whether shared web workers are working at all in your node-webkit environment.

On line https://github.com/awwx/meteor-offline-data/blob/v0.1.2/worker-boot.js#L152 you can add

WebWorker.log("hello from " + WebWorker.id);

The id is generated when the web worker starts up.

If you try this in Chrome you'll see "worker log: hello from 369815389" in the console (with a different id). If in Chrome you then open a second window, you'll see the same message, with the same id. Both windows are talking to a shared web worker, and both are talking to the same web worker.

In node-webkit, do you get the log message at all, and if you do, does it have the same id in both windows?

Web workers are painfully hard to debug because they have no console log. Literally, console.log does not exist in the web worker environment. And, uncaught exceptions thrown in the shared web worker are not reported back to the calling window -- they just disappear. So there could be a bug in worker-boot.js and you wouldn't see anything if it happens before the shared web worker starts sending messages to the calling window. In Chrome, you can browse to chrome://inspect/ and click on a running shared web worker to debug it. You can set breakpoints and step through code, so if you don't get the log message, you may be able to step through the code and find out on which line it is failing.

JarnoLeConte commented 10 years ago

Sorry, It looks like that it has nothing to do with the offline-data package. Its just the limitation of node-webkit that don't have an implementation of SharedWorkers, I think. The example on w3.org show no results in the node-webkit environment. Unfortunately, nobody mentioned that node-webkit haven't a SharedWorker implementation. It's a bit confusing because the SharedWorker constructor is already present in the JavaScript context. On the other side the normal web worker is already implemented, but that doesn't make the offline-data package working of course.

Maybe I must do a work around that make use of node.js workers instead of the client-side web workers. Or I can use the browser-msg package. The slowness of browser-msg is maybe also a side-effect of node-webkit, because I experienced that the normal web workers are slow too. It seems like they blocking the UI, what is strange behavior for workers ;)

I appreciate your help. Especially the detailed answers you provide. Your offline package is still really useful for my project. Thanks!

awwx commented 10 years ago

Right, it's possible that node-webkit might be single-threaded (as well as something broken with their shared web worker implementation).

Is it possible to detect the node-webkit environment? For example, by looking at the user agent string (https://github.com/awwx/meteor-useragent)?

Lot's of browsers have different bugs, and it's a last resort, but sometimes we need to do browser detection to work around bugs.

Closing this issue means finding a way to have offline-data work with node-webkit, such as by avoiding using shared web workers if they aren't working. (offline-data should fallback all the way to being nothing but a wrapper around Meteor.Collection if needed. What we don't want to be is in a situation where an application works with standard Meteor in a browser but breaks if offline-data is used).

JarnoLeConte commented 10 years ago

No, the useragent gives us Chrome information. Further there is no indicator that lets you know that you are in a node-webkit window. The only useful properties that are accessible in a window:

Maybe the most useful property to detect a node-webkit window: