Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Importing into react-native without using web worker still causing error #319

Open
chanpod opened this issue Dec 17, 2024 · 9 comments
Open
Labels

Comments

@chanpod
Copy link

chanpod commented Dec 17, 2024

Describe the bug
I have this library working perfectly on web and realized I needed to check it on our mobile app (we share the layout code in a monorepo) and unfortunately I hit a snag :( I'm not using web workers so I don't think that's the issue. Was hoping you could point me in the right direction. Hopefully it's something simple like I just need a shim or wrapper for the bundled code to make it happy in react-native.

It doesn't seem like there's anything in the code that wouldn't be inherently incompatible with react-native. So I suspect it might just be a bundle issue and I just need to apply a wrapper of some sort. But some insight on potential issues would be greatly appreciated.

Screenshots
image

ELK Version
0.9.3

@chanpod chanpod added the bug label Dec 17, 2024
@chanpod chanpod changed the title Importing into react-native without using web worker still causing compile error Importing into react-native without using web worker still causing error Dec 17, 2024
@chanpod
Copy link
Author

chanpod commented Dec 17, 2024

I see I can pass in my own worker? Would passing in something like this work

https://github.com/nolanlawson/pseudo-worker

@chanpod
Copy link
Author

chanpod commented Dec 17, 2024

Update: Seems it IS just the worker! Which is good news I think.

const elk = new ELK({
  workerUrl: undefined,
  workerFactory: () => {
    return {
      postMessage: (message: any) => {
        console.log("postMessage", message);
        return message;
      },
      onmessage: (event: any) => {
        console.log("onmessage", event);
      },
    };
  },
});

If you do this the mobile app stops erroring. So I think it's really just that fake worker has something off about it triggering the error. So if I can just use a different worker I think it'll work fine in react native.

@chanpod
Copy link
Author

chanpod commented Dec 18, 2024

@soerendomroes I didn't actually get this working yet unfortunately. The above example code stops breaking the mobile app but it doesn't actually work. Whenever I get the postMessage it's just the graph data I passed into elk, not the processed data.

@soerendomroes soerendomroes reopened this Dec 18, 2024
@chanpod
Copy link
Author

chanpod commented Dec 18, 2024

Are there any examples of a custom worker anywhere? The "FakeWorker" in the source code has the Dispatcher dependency. I don't have access to that and given the postMessage isn't "posting" the compiled layout code it makes me think I need that dispatcher to work properly.

@chanpod
Copy link
Author

chanpod commented Dec 18, 2024

I modified the exportLayout to this

function exportLayout(){
  $clinit_ElkJs();
  function dispatchMessage(event) {
    const data = event.data;
    try {
      switch (data.cmd) {
        case 'algorithms':
          const algs = getLayoutData(new Collections$UnmodifiableCollection(new AbstractMap$2(SERVICE.layoutAlgorithmMap)));
          return { id: data.id, data: algs };
        
        case 'categories':
          const cats = getLayoutData(new Collections$UnmodifiableCollection(new AbstractMap$2(SERVICE.layoutCategoryMap)));
          return { id: data.id, data: cats };
        
        case 'options':
          const opts = getLayoutData(new Collections$UnmodifiableCollection(new AbstractMap$2(SERVICE.layoutOptionMap)));
          return { id: data.id, data: opts };
        
        case 'register':
          registerLayoutAlgorithms(data.algorithms);
          return { id: data.id };
        
        case 'layout':
          layout_11(data.graph, data.layoutOptions || {}, data.options || {});
          return { id: data.id, data: data.graph };
        
        default:
          return { id: data.id, error: new Error('Unknown command') };
      }
    } catch (err) {
      return { id: data.id, error: err };
    }
  }

function FakeWorker(url) {
  // Store the onmessage handler
  let messageHandler = null;

  const worker = {
    set onmessage(handler) {
      messageHandler = handler;
    },

    get onmessage() {
      return messageHandler;
    },

    saveDispatch: (event) => {
      try {
        const result = dispatchMessage(event);

        if (messageHandler) {
          messageHandler({ data: result });
        }
        return result;
      } catch (err) {

        const errorResult = { id: event.data.id, error: err };

        if (messageHandler) {
          messageHandler({ data: errorResult });
        }
        return errorResult;
      }
    },

    postMessage: (msg) => {

      setTimeout(() => {
        worker.saveDispatch({ data: msg });
      }, 0);
    },
  };

  return worker;
}
  
    Object.defineProperty(exports, '__esModule', {value:true});
    module.exports = {'default':FakeWorker, Worker:FakeWorker, dispatchMessage: dispatchMessage};  
}

And now it's working on mobile.

I copied the elkworker file and made those changes to the export layout function. and used it like this

import { Worker } from "./myElkWorker.js";
const elk = new ELK({
  workerFactory: () => {
//worker param doesn't matter. /sldworker.js is pointless
    return new Worker("/sldworker.js");
  },
});

I haven't tested to see if this breaks actual web workers (probably does) but this at least makes elk usable on react-native.

@soerendomroes
Copy link
Member

Are there any examples of a custom worker anywhere?

Sadly, I almost never use elkjs. Hence, I am a little unfamiliar with this.

Please, update this issue if you think that this is the appropriate solution or if this does not work.

@chanpod
Copy link
Author

chanpod commented Dec 19, 2024

@soerendomroes Do you happen to know where in the source code this FakeWorker is created? I might take a stab at submitting a proper PR to make the Worker more generic and exposing the Dispatcher. This would make the "bring your own worker" actually work (assuming I haven't done something wrong and this is all way overly complicated lol)

So I don't know that I would mark this as "answered" but the above is definitely working for me.

@soerendomroes
Copy link
Member

@chanpod
Copy link
Author

chanpod commented Dec 19, 2024

The modifications I made were to the root elk-worker.js file. My understanding is that's the generated file from the GWT (java transpiler?)

https://github.com/kieler/elkjs/blob/master/src/java/org/eclipse/elk/js/ElkJs.java

Here? The section I modified to make it work is commented out in that file though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants