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

Electron build of JBrowse desktop #520

Merged
merged 45 commits into from
Oct 30, 2019
Merged

Electron build of JBrowse desktop #520

merged 45 commits into from
Oct 30, 2019

Conversation

garrettjstevens
Copy link
Collaborator

@garrettjstevens garrettjstevens commented Sep 24, 2019

This started out as a bit of a crazy idea, but now I kind of hope it works out. Basically this makes a new create-react-app (CRA) app for jbrowse-sv-inspector-desktop and builds it in electron. The development version works fine, and I'm working on getting it to build a production version.

As I was working on getting a new electron project going, I tried to start from scratch, but there were so many webpack, babel, etc. things to set up. There are some boilerplates out there, but none of them were great. Really, nothing as nice as what CRA put in place for us in jbrowse-web.

Then I found this article on creating an electron app using CRA. It's not exactly what we want, but has some good ideas and gave me a good starting point. Currently you can try out yarn start in jbrowse-sv-inspector-desktop and it runs basically a copy of jbrowse-web in an electron window.

Things still to see:

  • Can we get good cross-platform builds out of this? (The article above uses electron-builder, which I'm experimenting with now)
  • Can we integrate the electron-specific features we want (file system access, etc.) in a safe way using this?

This article above also uses something called rescripts, which lets you hack your CRA setup without ejecting. I actually used it to un-eject jbrowse-web, so that both it and jbrowse-sv-inspector-desktop can take advantage of the latest CRA updates and we don't have to maintain the dev and build systems separately.

resolves #195
resolves #484
resolves #512

@garrettjstevens
Copy link
Collaborator Author

Brain dump from WIP:

  • Webpack "electron-renderer" target assumes nodeIntegration is true, which used to be the default for electron, but now is not. We want to avoid nodeIntegration for security reasons.
  • Tried to create a custom target. The target worked, but if a target isn't one of webpack's pre-defined ones, you lose a whole bunch of presets and some npm modules won't work because they think you're in a node environment.
  • Using "web" target for now, which works, it just doesn't take advantage of "Externals" in webpack, so it will probably make the bundled size bigger.
  • We want to use ipc calls to communicate between renderer and main processes. Renderer (which does not have access to node) sends an ipc call to Main (which has node access), Main then e.g. runs fs.open and returns the filehandle to the Renderer.
  • With nodeIntegration off, you can't import electron, which you need in order to do renderer<->main thread ipc calls.
  • Workaround is to use a "preload" process that imports electron and assigns it to a global variable.
  • Web workers can't see the global electron, though, and they're the ones that really need it since they do the file access.
  • There is a nodeIntegrationInWorker setting where you can enable node just in webworkers. This would be great, except compiling webpack with a "web" target clobbers the native node modules. __non_webpack_require__ does not seem to work.
  • Would be best to do webpack on the workers separately with the "webworker" target (or actually maybe "node" target?), but not sure yet if that works with this setup.
  • Using MainThreadRendering, I was able to get an example of the renderer<->main thread RPC calls mostly working.
  • For some reason, getting uncaught errors with an empty error object (no explanation, name, anything). Might be related to aborting.

@rbuels
Copy link
Contributor

rbuels commented Sep 30, 2019 via email

@garrettjstevens
Copy link
Collaborator Author

Error in the last bullet point above was not due to aborting, it just appeared that way at first. It was actually due to errors in the main process. It turns out errors that originate in the main process don't contain any information when passed to the renderer process. To see main process errors, you have to try/catch them and log the error, and then it will show up in the terminal window that electron is running from (won't show up in dev tools).

With GMOD/bam-js#42 incorporated, I now have a working version using a local BAM file and MainThreadRpcDriver.

@codecov
Copy link

codecov bot commented Oct 6, 2019

Codecov Report

Merging #520 into master will decrease coverage by 5.83%.
The diff coverage is 14.68%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #520      +/-   ##
==========================================
- Coverage   66.62%   60.79%   -5.84%     
==========================================
  Files         247      266      +19     
  Lines        8417     9300     +883     
  Branches     1930     2109     +179     
==========================================
+ Hits         5608     5654      +46     
- Misses       2591     3373     +782     
- Partials      218      273      +55
Impacted Files Coverage Δ
packages/alignments/src/CramAdapter/CramAdapter.ts 61.17% <ø> (ø) ⬆️
...ckages/sequence/src/TwoBitAdapter/TwoBitAdapter.ts 100% <ø> (ø) ⬆️
...lignments/src/BamAdapter/BamSlightlyLazyFeature.ts 67.02% <ø> (ø) ⬆️
...c/StructuralVariantChordRenderer/ReactComponent.js 94% <ø> (ø) ⬆️
packages/core/util/layouts/GranularRectLayout.ts 87% <ø> (+1%) ⬆️
packages/jbrowse-web/src/workerPolyfill.js 16.66% <ø> (ø) ⬆️
packages/circular-view/src/index.js 100% <ø> (ø) ⬆️
packages/bed/src/BigBedAdapter/BigBedAdapter.ts 89.28% <ø> (ø) ⬆️
...ackages/variants/src/VcfTabixAdapter/VcfFeature.ts 56.66% <ø> (ø) ⬆️
.../config/src/FromConfigAdapter/FromConfigAdapter.ts 100% <ø> (ø) ⬆️
... and 87 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 1babf91...8e64e7b. Read the comment docs.

@rbuels rbuels assigned rbuels and garrettjstevens and unassigned rbuels Oct 7, 2019
@garrettjstevens
Copy link
Collaborator Author

CORS-busting is working, dependent on GMOD/generic-filehandle#42. This is the gnomAD SV VCF, which doesn't work in jb-web because of CORS:

image

Once that PR is merged I'll mark this ready for review.

@garrettjstevens garrettjstevens marked this pull request as ready for review October 30, 2019 04:19
@garrettjstevens
Copy link
Collaborator Author

Start screen is working now, so I think this is ready for review.

@rbuels rbuels changed the title Electron build of JBrowse (to become sv-inspector) Electron build of JBrowse desktop Oct 30, 2019
@cmdcolin
Copy link
Collaborator

I added a couple comments.

Some other random ones

Would be good to get some sort of automated testing of the electron app. JBrowse 1 used spectron to do this and it actually works on travis-CI.

Also sometimes the app shuts down without warning and in the console it says "Maximum number of clients reached". Wondering if it's related to the screenshoting logic (maybe the screenshot is a client? not sure)

[1] [7673:1030/143057.530126:ERROR:CONSOLE(24)] "Empty response arrived for script 'devtools://devtools/remote/serve_file/@74afbfc65bd4d271bc09280abd5783ffe47444b9/product_registry_impl/product_registry_i
mpl_module.js'", source: devtools://devtools/bundled/shell.js (24)
[1] [7673:1030/143057.530200:ERROR:CONSOLE(109)] "Uncaught (in promise) Error: Could not instantiate: ProductRegistryImpl.Registry", source: devtools://devtools/bundled/shell.js (109)
[1] [7673:1030/143057.530212:ERROR:CONSOLE(109)] "Uncaught (in promise) Error: Could not instantiate: ProductRegistryImpl.Registry", source: devtools://devtools/bundled/shell.js (109)
[1] [7673:1030/143057.530218:ERROR:CONSOLE(109)] "Uncaught (in promise) Error: Could not instantiate: ProductRegistryImpl.Registry", source: devtools://devtools/bundled/shell.js (109)
[1] tracing_service_impl.cc: Configured tracing, #sources:2, duration:0 ms, #buffers:1, total buffer size:102400 KB, total sessions:1
[1] Maximum number of clients reached[7673:1030/143102.488372:ERROR:shared_x_display.cc(37)] Unable to open display
[1] wait-on http://localhost:3000 && electron . exited with code 0

@@ -9,14 +9,15 @@
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it may be better to not use this flag, not sure though

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure either, but I will say that this is the default tsconfig for a fresh typescript-enable CRA.

@@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "esnext",
"target": "es5",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might as well keep it as esnext?

@@ -90,41 +90,41 @@ export function stateModelFactory(pluginManager: any) {
configuration: types.frozen(),
})
.views(self => ({
get viewingRegionWidth() {
get viewingRegionWidth(): number {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, I like having automatically determined function return types, if there is a rule requiring them I would prefer to keep it off

session: PropTypes.observableObject.isRequired,
}

export default withSize()(observer(App))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The App.js from jbrowse-web does not use withSize. We may want a way to de-duplicate logic between jbrowse-web and jbrowse-desktop in some cases, not sure what the right approach is though

@@ -0,0 +1,1372 @@
{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like this config.json to be the same as JBrowse desktop so I can compare all tracks

@garrettjstevens garrettjstevens merged commit 37e3512 into master Oct 30, 2019
@cmdcolin cmdcolin deleted the cra_rescripts branch November 21, 2019 02:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants