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

Proposed enhancements to Electron compatibility/features (?) #291

Open
fpguillet opened this issue Feb 21, 2022 · 0 comments
Open

Proposed enhancements to Electron compatibility/features (?) #291

fpguillet opened this issue Feb 21, 2022 · 0 comments

Comments

@fpguillet
Copy link

As I need to write some GUI tools for lab usage with Julia computations, I settled on Blink+Electron. The GUIs are in between lightweight WebApp and full Desktop app. At first (and second?) glance it seems I need to write a tailored main.js, be able to load a framework (eg Photon), all of which don't seem to be feasible with Blink, at least not easily.
So I hacked my way through the code and came up with the following design, which is fully compatible with the current one. I'm not sure if I should pull a request, besides it's just a hack which needs rewriting/refactoring if it's to be kept.
1st point is electron executable. Current Blink Electron version is 4.0.4, current stable Electron version is 17.0.1. I don't know if there's a reason for sticking to 4.0.4 but I (maybe naively) think anyone should be able to choose which electron version it runs apart from the default 4.0.4. So the Window constructor could take into account the Electron.exe path.
2nd point It should also be possible to provide an alternate main.js (eg for adding dialog functionalities, IPC comms) and main.html while still keeping Blink functionality.
electron.exe path and main.js path can be specified changing the shell constructor, which would take a (possibly empty to keep defaults) Dict containing paths, in turn passed to init function :

function shell(; debug=false, shellOpts = Dict())::Electron
  ...
  proc = init(shellOpts; debug=debug)
  ...
    
function init(shellOpts; debug = false )
  epath = haskey(shellOpts, :epath) ? shellOpts[:epath] : electron()
  mainjs = haskey(shellOpts, :mainjs) ?  shellOpts[:mainjs] : resolve_blink_asset("src", "AtomShell", "main.js")
  ...
  proc = (debug ? run_rdr : run)(`$epath $dbg $mainjs port $p`; wait=false)

A main.html file could also be indicated in the Window constructor and parsed through 'Mustache' as is the original file (rather than be loaded 'as is' using loadurl). I added a key to the options dictionary which is quite crude because those options are for electron window creation. Anyway, if the key is present then a mainhtml global variable is set and the main.html ends up loaded through the same mechanism as the original main.html :
maintp() = Mustache.template_from_file(mainhtml == "" ? joinpath(dirname(@__FILE__), "main.html") : mainhtml)

Final point is the ability to load resources from main.html file. The load! function already exists, of course, but if the loaded file in turns specifies other files these are not loaded because they can't be found. It would be more appropriate IMO if the loading mechanisms in html files were kept functional. Mustache placeholders can be used in the specified main.html to point to directories where the resource files are thanks to AssertRegistry. These directories are listed in window constructor, again through the options directory. Code goes :

using AssetRegistry
const blinkassets = Dict{String, String}()

function Window(a::Shell, content::Page, opts::AbstractDict = Dict(); async=false)
  global mainhtml
  mainhtml = haskey(opts, :mainhtml) ? opts[:mainhtml] : ""
  respath = haskey(opts, :respath) ? opts[:respath] : ""  
  for key ∈ keys(respath)
    blinkassets[key] = AssetRegistry.register(respath[key])
  end
...

function page_handler(req)
  ...
  return render(maintp(), merge(d("id"=>id, "optional_create_window_callback"=>callback_script), blinkassets) )
...

And Window constructor call is then (example) :

sOpts = Dict(:epath => "/Path/to/electron.exe",
        :mainjs => "/Path/to/mymain.js")

w = Window(shellOpts = sOpts, Dict(:title => "Test", :width => 1200, :webPreferences => Dict(:nodeIntegration => true, :contextIsolation => false),
    :mainhtml => "/Path/to/mymain.html",
    :respath => Dict(   "mainpath" => "/Path/to/MyProject/mainpath/",
                        "respath" => "/Path/to/MrProject/some/other/resourcepath/")))

and finally the main.html code :

<!DOCTYPE html>
<html>
  <head>
    <title>aTitle</title>

    <!-- Stylesheets -->
    <link rel="stylesheet" href="{{respath}}/css/photon.css">

    <!-- Javascript -->
    <script>var id = {{id}}</script>
    <script>{{optional_create_window_callback}}</script>
    <script src="blink.js" charset="utf-8"></script>
    
  </head>
  <body>
  <!-- some body content, renderer.js is loaded last because it may refer to objects declared in the body -->
  <script src="{{mainpath}}/renderer.js" charset="utf-8"></script>
  </body>
</html>

It works well AFAIK, as loading photon.css also loads the fonts located in another folder underneath "respath". IPC communication between main and render works, as well as Electron <-> Julia communication.

I post these lines in case they are of interest to anyone. Sorry if it's naive or awkward, I'm relatively new to Julia and no computer science guy anyway.

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

No branches or pull requests

1 participant