kieler/elkjs

Can't bundle for worker

Qix- opened this issue · 5 comments

Qix- commented

When bundling elk to be called not as a worker, but instead bundled as a larger codebase that is eventually used within a worker, elk has different export semantics and cannot be used whatsoever by the bundled code.

The culprit is this generated code:

  if (typeof document === 'undefined' && typeof self !== 'undefined') {
    var dispatcher = new Dispatcher(self);
    self.onmessage = dispatcher.saveDispatch;
  }
   else if (typeof module !== 'undefined' && module.exports) {
    Object.defineProperty(exports, '__esModule', {value:true});
    module.exports = {'default':FakeWorker, Worker:FakeWorker};
  }

Please, don't do this. To assume it's always meant to be run as a standalone worker just because it's within a worker context reduces modularity and re-usability, and just caused a good deal of headache.

The better approach would to be to generate two scripts - one that is the library and exports the same, always, and another that exports a worker wrapper around it.

Unfortunately, I currently do not have the time to rewrite the correspondings parts. Hence, suggestions how to adjust the current implementation are very welcome.

The generated code you point out results from the GWT wrapper code. The GWT wrapper code has likely to be adjusted to actually provide a proper module. Maybe even by adjusting the linker to include the module related parts.
The second step would then be to provide the worker wrapper.

Sometimes I got that error, I don't remember exactly when and in what circumstances, but I can share when I don't have this error (and similar with other modules) without changing the code. Hope that helps.

  "scripts": {
    "dev": "nodemon --watch \"src/**\" --ext \"ts,json\" --exec \"node --experimental-specifier-resolution=node --loader ts-node/esm src/app.ts\"",
    "build": "tsc --project ./",
    "start": "node --experimental-modules --experimental-specifier-resolution=node ./dist/app.js"
  },

I use typescript in my projects. If you don't - just ignore ts-specific stuff.
I think these flags --experimental-modules --experimental-specifier-resolution=node do the trick and the error goes away.

Has anyone had any luck trying this with React's CRA before? I'm not sure how we could pass --experimental-modules --experimental-specifier-resolution=node to webpack-dev-server

DPros commented

my solution for angular environment:
include elk in angular.json:

"allowedCommonJsDependencies": [
  "elkjs"
],
"scripts": [
  "node_modules/elkjs/lib/elk.bundled.js",
]

declare variable (it's a constructor) and initialize elk in .ts file:

declare const ELK: any;
...
private elk = new ELK();

@Qix- , thank you for your fork, it is actually exactly what I needed!

I've integrated your version into Wikidata Graph Builder (example graph). This graph is fully computed inside a webworker - everything starting from fetching data, up to drawing inside transferred OffscreenCanvas. Special thanks for removing layouts, now compressed worker is just 414 kb, which also includes drawing part. Now elkjs is actually a good alternative to dagre.