How to start Phoenix application without showing terminal in Windows 11

Background

I am creating a simple Phoenix umbrella application to run on a client’s Windows 11 machine and my objective is to have something like an .exe file for running said application.

Code

I am creating the application and releasing it using Elixir’s normal release procedure, using the commands:

mix phx.new demo --umbrella --no-ecto --no-dashboard --no-gettext --no-mailer
cd demo_umbrella
mix deps.get

# set MIX_ENV=prod before doing this last step!
mix release demo

For those of you curious, this is the releases function I am using inside my mix.exs:

  defp releases,
    do: [
      demo: [
        applications: [
          demo_web: :permanent,
          runtime_tools: :permanent
        ],
        include_executables_for: [:windows]
      ]
    ]

Now, this basic setup will create a .bat file: _build\prod\rel\demo\bin\demo.bat that I can start and stop via the following commands: _build\prod\rel\demo\bin\demo {start | stop}.

Problems & Research

Users that know programming can simply open a terminal in Windows, type _build\prod\rel\demo\bin\demo start and the application will launch (accessible via localhost:4000).

But users normally don’t have such knowledge. So I want something as close to an .exe file as possible.

I have tried using Bakeware:

And its spiritual successor, Burrito:

Unfortunately, both fail to work for Windows 11. This leads me to try the shortcut approach.
Here I create Windows shortcut to demo.bat and I specify in the target path the commands:

Which in this case will be %windir%\system32\cmd.exe /c start "" "%CD%\demo.bat" start

Now, all is fine and dandy, but there is a problem:

  1. the console always appears.

Questions

So this leaves me to the following questions:

  1. How do I prevent the console from showing?
  2. Does demo.bat include the erlang VM and the elixir version needed to run the application? Or do I need to have those installed in the client’s machine ?
  3. I am under the impression that Elixir releases are supposed to include everything needed (https://elixir-lang.org/getting-started/mix-otp/config-and-releases.html):

A release is a self-contained directory that consists of your application code, all of its dependencies, plus the whole Erlang Virtual Machine (VM) and runtime. Once a release is assembled, it can be packaged and deployed to a target as long as the target runs on the same operating system (OS) distribution and version as the machine that assembled the release.

, but in case this bat file does not include everything, how do I fix this?

Release inclde everything needed for you to be able to run it on the target system. You can do that using the .bat. It’s however not meant to build a single/standalone executable (.exe / binaries on other os’s).

Yes(ish). It includes everything so an OTP/Elixir installation is not necessary. There might be other lower level dependencies left though, which are still required, but often expected to exist on target systems.

What do you think it doesn’t include, that would be needed to run the release?

1 Like

I’m surprised burrito doesn’t work. I’ve used it on windows a bunch of times.

Elixir Desktop uses a vbscript to launch the app. It’s not a pretty solution imo but it works.

So, burrito doesn’t build on WIndows anymore. I pushed a PR to fix the issue you’re hitting but there are other hurdles in the Zig code. Best to build from a linux box for now.

Since my use case is an Elixir Desktop application, I am unsure that :wx and all of its dependencies will be inside the bat created.

I searched the code for any files with a .vb extension but could not find. Can you point me to the file where this happens?

I understand that you can theoretically convert a VB6 script into an .exe file, so this could actually work, even if a lot of manual work is needed.

Since I am doing this for Windows clients, I need to do everything in a Windows machine. This is sadly not a viable option for me :frowning:

:wx will be in the release (if you setup the dependency in mix.exs). I don’t think wxwidgets specifically are included in the release. How external (native) dependencies are handled always depends on the application integrating with that dependency. That’s nothing elixir (or OTP for the matter) could affect in a general application independant way.

Also nothing will be “in the bat” specifically. The release only works as a whole with all the files within it. The bat is only the entry point.

While cross compilation is not necessarily an easy topic it is not impossible to build for windows from linux.

1 Like

This is very important and something I don’t quite understand.
Say I have created my release files using mix realease. What files do I need to put in my clients machine, for the client to be able to run the application?

I take it from your comment that I will need more than simply demo.bat.
What folders do I need ?

Do I need the full _build/prod folder? Maybe something less?

Why would this be preferable? If the support for Windows is not ideal in Windows machines, how would cross-compilation improve the situation? If you have some articles/ideas on this, I would really like to check them out.

Answer

Following an SO post:

I was able to create a shortcut that achieves my purposes, using VB as well. At the very least, this will launch the application. Closing may be another concern and I still need to test this with Elixir Desktop. However, these are questions that likely deserve their own posts, so if I find the need, I will leave them for later.

Instructions

  1. Follow instructions to create the project from the question above (you may need to enable server options in config/prod.exs)

  2. Go to demo_umbrella\_build\prod\rel\demo\bin where the newly created demo.bat file is

  3. Create a file called invisible.vbs and add in the following content:

CreateObject("Wscript.Shell").Run "" & WScript.Arguments(0) & "", 0, False
  1. Create a Windows shortcut, that looks like this:

Screenshot 2023-10-13 114923

The value on the Target field is:

%windir%\system32\wscript.exe invisible.vbs "demo.bat start"

  1. Upon clicking the shortcut, the application will be launched behind the scenes and you will be able to check it under localhost:4000.

This shortcut will run the files from the folder it is in, so you can safely move things around provided you always keep it in the same folder the rest of the files are.

Being a shortcut, it also means you can change the icon to anything you want.

1 Like

If you stick to the default release root then everything within _build/MIX_ENV/rel/YOUR_APP is “the release”. You need everything in there in the same places relative to each other. Or said otherwise. Don’t attempt to move pieces within that folder. You can add the :tar release step in mix.exs to get a .tar archive of the same contents, though as a single archive file.

I didn’t quickly find any documentation on :wx if you need to install wxwidgets on a target machines as well, or if it’s only a build time dependency. If you have a spare machine you could probably test it though.

I wasn’t arguing that it’s preferable, but that it’s not impossible. How difficult it would be depends on what all you need to build and actually cross compile.

1 Like

This is rather interesting. However, if I choose to do it that way, how will I be able to create a shortcut to demo.bat ?

Would I not have to unzip the file before? (thus ending with the same thing?)

You don’t. It’s not meant to be “an executable”, but just an easier way to ship to a target computer as one and extract there.

1 Like

Maybe (/ probably) not what you are going for, but I think that is how self contained and single file apps in the dotnet (v6 and up?) world work: When building a single file executable all the necessary files for the release - and there might be lots of them - are just hidden in an included archive. When the user executes the EXE file the contents are first extracted and then some “bootstrapper” file is run once everything is in place (in some temporary directory).

So if you don’t mind build something like that in another language you could probably do the same to get a single-file elixir-based windows executable without a terminal.

Livebook also uses dotnet for their desktop application. Though livebook is only a menubar app.

That is exactly what burrito is.

Sorry, I got the vbs from their product built with elixir desktop, not elixir desktop itself.

In rel/overlays there is a bat and vbs.

coolapp.bat

@echo off
setlocal enabledelayedexpansion

pushd .
cd "%~dp0"
set ROOT=%cd%
popd

!ROOT!\bin\coolapp.bat start

coolapp.vbs

' This avoids a flashing cmd window when launching the bat file
strPath = Left(Wscript.ScriptFullName, Len(Wscript.ScriptFullName) - Len(Wscript.ScriptName)) & "coolapp.bat"
' Debug: MsgBox(strPath)
Set WshShell = CreateObject("WScript.Shell")
WshShell.Run chr(34) & strPath & Chr(34), 0 
Set WshShell = Nothing

But yeah, it’s not a nice solution and an exe is preferred.