protobufjs / protobuf.js

Protocol Buffers for JavaScript & TypeScript.
Other
9.74k stars 1.4k forks source link

Doesn't works with qml #818

Open uralbash opened 7 years ago

uralbash commented 7 years ago

protobuf.js version: 6.7.0

I have a QML file that imports a JavaScript library


// protobuf
import "qrc:/protobuf/node_modules/protobufjs/dist/protobuf.js" as PB

...

console.log(PB.load) // undefined

But it always undefined.

https://stackoverflow.com/a/38714434/1026990

dcodeIO commented 7 years ago

I am not familar with QML unfortunately. If you find something out, i.e. how this can be solved, let me know!

pkoretic commented 6 years ago

QML .js modules do not have window or global property and they also do not support module.exports and exports but that is the default behavior, i.e.

lib.js

function load() {
   ...
}

main.qml

import "lib.js" as Lib
Lib.load()

protobuf.js wraps everything inside an anonymous function (as it is expected these days) and because of that nothing gets exported for QML to use. QML .js also does not have require which is somewhat replaced by the import directive.

So when trying to import protobuf.js 6.8.6, first error that is shown:

protobuf.js:7756: TypeError: Cannot assign to read-only property "constructor"

Normally I would just remove anonymous function wrap to use it in QML and then fix what pops up but this is somewhat convoluted to do here. Would you be able to help with some idea given the information about QML?

Thanks

dcodeIO commented 6 years ago

The outer function is defined here and included here - if that helps.

pkoretic commented 6 years ago

I did manage to get a minimal version running for my needs, the wip work is here so it doesn't get lost given my lack of free time to work on this https://github.com/pkoretic/protobufjs-qml

It required replacing uint8array with array given that qml has support uint8array for but it doesn't work properly and resolving some other quirks

.proto is built as pbjs -t static -w closure -o compiled.js message.proto

then an explicit import has to be added to compiled.js

.import "protobuf.js" as Protobuf
var $protobuf = Protobuf

and then it can be used "normally" as:

.import "proto.js" as PROTO
var Message = PROTO.$root["Message"]

I guess the first easy thing to do next would be to write a custom wrapper and then go from there.

sharyu commented 6 years ago

@pkoretic Hi, I also run into this issue and thanks for your script. I see you have modified protobuf.js a lot. But there are still some functions missing, such as util.isInteger, util.isObject, etc. I don't know whether it will cause bug. Are you still working on fixing this script? Or will you write a custom wrapper for it?

pkoretic commented 6 years ago

Hi @sharyu, yes, working on it, I just removed things I didn't need at the time, those functions are used for .verify, I will get whole minimal version working this week I would say

pkoretic commented 6 years ago

@sharyu I have updated it to include all the upstream code hopefully if you want to test that

sharyu commented 6 years ago

@pkoretic Thank you for your great job! I've tested some cases it works fine. But when I use it in real product, the pbjs generated static code is too large and QT throws native error. It should be QT's issue, and I've asked for help in their forum: https://forum.qt.io/topic/90089/meet-error-when-running-large-js-script I'm also trying to use protobuf c and expose values to QML. Need to test which way has better performance.

pkoretic commented 6 years ago

Interesting, I was only using it with smaller .proto files. I would go for an official c++ protobuf and expose it like you did. For portability (ios & android) this seemed as the best way for me although a protobuf c seems like a nice option to try, directly including the sources without having to cross compile for every platform. There is also this https://github.com/nanopb, although seems limited