Anyone used PackageCompiler to build a distributable app with an Interact/Blink GUI?

I have some code that I run a couple of times per month and I’d like to be able to build a GUI for it, compile it as an app, and then distribute the .exe to others in my organization (non-programmers) so that they can make use of it. Normally, I would write an API for this, get that running on a server, and then build a web-based front end that calls the API. In this case, however, I’m not going to be able to do that and it will have to be something that a user can run on their desktop.

I’m wondering if anyone has built anything with Interact/Blink and successfully compiled it with PackageCompiler.jl for Windows 10? If so, is there a git repo you could share?

My needs are actually very simple, I just need a simple GUI that allows users to pick two different files from their desktop, a button that will execute the code, and maybe a space for the user to enter in the directory where they would like the output file to be saved.


I just had a look at the Blink.jl docs and for what you are planning to do, it does seem like a rather straightforward solution (especially given your prior knowledge in web dev). However, I couldn’t find any mention of behaviour with PackageCompiler.jl but why not just test it with a quick example app yourself (e.g. a button that runs a julia calc in the background and updates the html accordingly to its output)?

Edit: You could also use QML.jl or Gtk.jl if you want to build a native app instead of an electron app.


I did this once in order to get convinced that writing such GUIs was indeed possible. This was my first and only time using Blink and Interact, and I did not really use this UI for anything useful. But here is the code in case it would be helpful for you to get started with this framework:

using Interact
using Blink
using CSSUtil
using WebIO

# Not sure how to display plain text messages without defining such custom widgets...
htmldiv(name, observable) = Widget{name}(OrderedDict(),
                                         output=map(val->dom"div"(string(val)), observable))
htmlspan(name, observable) = Widget{name}(OrderedDict(),
                                          output=map(val->dom"span"(string(val)), observable))

# Two parameters, linked to slider widgets
x = slider(1:10, label = "x", value = 1)
y = slider(1:10, label = "y", value = 1)

# A third parameter, computed by combination of the other two
param = Observable(0)

function update_xy(_=nothing)
    param[] = x[] + y[]
on(update_xy, x)
on(update_xy, y)
update_xy()  # First manual update to display a consistent state on UI startup

# A widget allowing to choose a file path
f = filepicker(label="Choose a file..."; multiple=false, accept="*")

# A button to run the computation
b = button("Go")

# A message displayed at the bottom
message = Observable("")

# This condition will be used to notify the main task when the computation is done
done = Condition()

# Mock-up computation happening on button click
on(b) do _
    for i in 5:-1:1
        message[] = string("Performing long computation involving parameter $(param[]) ",
                            "and file $(f[]): $i")
    message[] = "Computation complete!"

    # Notify the main task

# Create the window and layout the widgets in it
w = Window()
ui = pad(1em,
                  vbox(x, y,
                       hbox(node(:span, "param : x + y = "), htmlspan(:param, param)))),
              pad(1em, f),
              pad(1em, b),
              pad(1em, htmldiv(:message, message))))
body!(w, ui)

# Wait until the computation is finished


At the time when I made this experiment, I tested this on Linux and generated a system image for it. AFAIR I did not have any problem with PackageCompiler. I’m not sure whether I actually tested this on Windows.

Again, this might very well be un-idiomatic, and I’ll probably not be able to answer any follow-up question you might have. But hopefully someone more knowledgeable will chime in and we’ll both learn something!


So I finally got around to testing this out and it’s not working for me. When I launch the executable it starts to load the electron window but then aborts before loading any of the widgets (buttons, file pickers, etc.). Because what I need is so simple, I think I’m going to try to re-do this as a command line utility rather than having a GUI. I’m hoping that will be easier…

1 Like