jxcore / jxcore-cordova

JXcore / Node.JS plugin for Apache Cordova / PhoneGap
Other
233 stars 68 forks source link

LoadMainFile JX package #104

Open Minishlink opened 8 years ago

Minishlink commented 8 years ago

Hello there.

I'm trying to load a (not corrupted ;) cf jxcore/jxcore#651) jx package based on this package.json:

{
  "name": "A6",
  "version": "0.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "dependencies": {
    "express": "^4.13.3",
    "express-pouchdb": "^1.0.1",
    "leveldown-mobile": "^1.0.10",
    "pouchdb": "^5.1.0",
    "thali": "^2.0.2"
  }
}

I generate the package with jx package app.js --show-progress percent and copy the *.node in the correct folder. (see last paragraph)

I load it like this:

document.addEventListener('deviceready', function() {
    console.log('deviceready');
    var initJXCore = setInterval(function() {
        if (typeof jxcore == 'undefined')
            return;

        clearInterval(initJXCore);

        jxcore.isReady(function() {
            jxcore('app.jx').loadMainFile(function (ret, err) {
                if (err) {
                    console.error(JSON.stringify(err));
                } else {
                    console.info("jxcore ready");
                }
            });
        });
    }, 5);
});

And for testing purpose, my app.js only contains console.log("test");.

Logcat gives log.txt. In short, jxcore throws a "null" error, and "test" is not printed in logcat.

On my computer, running jx app.jx does print "test".

If it can help I can upload app.jx.

There are several reasons for loading a jx package:

At first I was creating the package with jx package app.js --extract-what "*.node" --extract-app-root --extract-verbose --show-progress percent. But doing so, I would get an error in logcat saying that the corresponding directory could not be created (as extraction tried to create a folder inside the apk, so yeah it cannot work).

Any ideas ? Thanks for your help.

ktrzeciaknubisa commented 8 years ago

I'm not sure if loadMainFile() call supports jx package directly, so I would recommend to keep a main file as javascript:

# index.html
jxcore('app.js').loadMainFile() 

but inside of app.js you may call:

# app.js
require('./app.jx');

Update: I meant app.js from loadMainFile() is different than app.js from inside of your package. Let's then rename the main file to avoid confusion: jxcore('start.js').loadMainFile()

ktrzeciaknubisa commented 8 years ago

But, if you have .node files and you hope to run it with jxcore-cordova, then see https://github.com/jxcore/jxcore/issues/654#issuecomment-158023036

Minishlink commented 8 years ago

So it seems it does work with jxcore('app.jx').loadMainFile( on my other computer. (I can access successfully the express server that way) I'm not sure yet what causes the issue on the first computer...

Now of course playing with the .node native module does not work as expected, as you pointed out. I guess I will use only memdown for the moment but I'd prefer to find a better solution.

If you compiled the .node using ndk-build, wouldn't the .node run well ?

Also, when doing the --extract-what method and also having the .node in the right location under www/jxcore, why does jxcore throws this:

11-19 22:03:01.908 18235-18235/app I/jxcore-log: extracting node_modules/leveldown-mobile/build/Release/leveldown.node
11-19 22:03:01.967 18235-18235/app  E/jxcore-log: Cannot create directory: node_modules/leveldown-mobile/build/Release

The .node being in the apk, jxcore should load it instead of extracting it from app.jx. It should show skipping leveldown.node (file already exists) just like on a computer, shouldn't it ?

Anyway I hope these discussions will help other newcomers like me. :)

ktrzeciaknubisa commented 8 years ago

So it seems it does work with jxcore('app.jx').loadMainFile(

Good to know :)

If you compiled the .node using ndk-build, wouldn't the .node run well ?

On same platform yes, but then the mobile where you deploy is a different machine.

It should show skipping leveldown.node (file already exists) just like on a computer, shouldn't it ?

The jx package extraction feature is meant for desktop apps only. It will not work on mobiles. Thus when you create a package for jxcore-cordova usage, you should skip extract options. Or better we should disable the extraction when running on mobiles. I didn't realize, that the extractable package wants to be extracted when using cordova :)

Just keep in www/jxcore the app.jx file and (for testing purpose) .node files in their own folders (starting from _nodemodules i guess).

Minishlink commented 8 years ago

I really don't get how leveldown-mobile can work then... I mean there must be a way to get it working since the project states it's compatible with JXcore. (cc @obastemur)

ktrzeciaknubisa commented 8 years ago

That's because leveldown is already embedded in jxcore-cordova plugin.

Minishlink commented 8 years ago

Uh. Cool so that means it works indeed. That was not very obvious... :/ For information, it still throws this error, though I don't know if it comes from jxcore or thali:

11-19 23:53:52.040 12512-12512/app E/jxcore: Error!: NativeModule.Roots[dir] is undefined
Stack: [{"_fileName":"fs.js","_functionName":"__hasFile","_lineNumber":"2241","_columnNumber":"5","_msg":"    at __hasFile@fs.js:2241:5"},{"_fileName":"fs.js","_functionName":"__existJX","_lineNumber":"2252","_columnNumber":"16","_msg":"    at __existJX@fs.js:2252:16"},{"_fileName":"fs.js","_functionName":"cb","_lineNumber":"147","_columnNumber":"11","_msg":"    at cb@fs.js:147:11"},{"_fileName":"fs.js","_functionName":"unknown","_lineNumber":2241,"_columnNumber":4,"_msg":"    at "}]

Thanks again for your help !

ktrzeciaknubisa commented 8 years ago

This is probably JXcore. How can I reproduce this?

Minishlink commented 8 years ago
// app.js
var fs = require('fs');
var express = require('express');
var path = require('path');
var os = require('os');
var PouchDB = require('pouchdb');
var ThaliReplicationManager = require('thali/thalireplicationmanager');

console.log('starting app.js');

var app = express();
app.disable('x-powered-by');

var dbPath = path.join(os.tmpdir(), 'dbPath');

var env = process.env.NODE_ENV || 'production'; // default to production

if (process.env.MOCK_MOBILE) {
  global.Mobile = require('thali/mockmobile.js');
}

if (process.platform === 'ios' || process.platform === 'android') {
  Mobile.getDocumentsPath(function(err, location) {
    if (err) {
      console.error("Error", err);
    } else {
      dbPath = path.join(location, 'dbPath');
      console.log("Mobile Documents dbPath location: ", dbPath);
    }
  });
}

var LevelDownPouchDB = PouchDB.defaults({db: require('leveldown-mobile'), prefix: dbPath});

app.use('/db', require('express-pouchdb')(LevelDownPouchDB, { mode: 'minimumForPouchDB'}));
var db = new LevelDownPouchDB('thali');

app.use(function allowCrossDomain(req, res, next) {
    res.header('Access-Control-Allow-Origin', 'http://127.0.0.1:5000');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header('Access-Control-Allow-Headers', 'Content-Type');
    next();
});

var server = app.listen(5000, function () {
    console.log('Express server started. (port: 5000)');

    var manager = new ThaliReplicationManager(db);
    manager.start(5000, 'thali');
});

The steps:

  1. cordova create test com.test.test test && cordova platform add android
  2. copy above package.json and app.js to test/app/jxcore
  3. jx npm install --production --autoremove "*.gz"
  4. jx package app.js --show-progress percent
  5. copy app.jx to test/www/jxcore
  6. in www/index.html copy above script (with event listener on "deviceready")
  7. cordova run android (having an Android device in debug mode, as it won't work in an emulator)
  8. Look at logcat.

At step 2, you could copy to test/www/jxcore and skip step 5 but running cordova run android will be enormously long due to the numbers of folders under node_modules.

Step 3 can fail sometimes due to thali installation. If it's the case, simply run jx npm install thali --production --autoremove "*.gz". And check that the other packages installed well.

Oh and I got the error null again one time this morning... But I haven't since. (EDIT: just got it two times in a row...)

ktrzeciaknubisa commented 8 years ago

Thanks for this detailed instructions. I was able to reproduce this. It happens for jxcore-cordova 0.0.7 (since Thali installs this exact version). Then I upgraded binaries to 0.0.8 but the app crashed:

11-23 14:39:06.976: W/jxcore-log(2172): Process ARCH ia32
11-23 14:39:06.976: W/jxcore-log(2172): --------- beginning of crash
11-23 14:39:06.977: A/libc(2172): Fatal signal 11 (SIGSEGV), code 1, fault addr 0x3b0029 in tid 2172 (m.example.hello)

so I guess this needs to be fixed before we start looking at NativeModule.Roots[dir] is undefined error.

I'm reopening for now.