Ask HN: How to make a native GUI with a modern language?
HN has strong opinions against Electron so here are my requirements:
- I want to make a native looking GUI
- Cross platform (macOS, Windows, Linux)
- With a sane language (no C, C++ or Objective C)
- Ideally with a data flow looking like unidirectional data flow / Elm architecture
What options do I have?
144 comments
[ 3.0 ms ] story [ 185 ms ] threadI made something pretty complicated with tkinter and Python. It's not that hard to do but the result looks awful, it doesn't support many features people expect in 2022, and the documentation for using tk in Python is poor. You probably need to refer to the tcl/tk documentation and translate it in your head to apply to Python.
As much as people hate Electron, the rendering engine in a web browser is head and shoulders better than any other cross-platform system and I think it's a sane model for programming. The main trouble w/ Electron is that you have 30MB of runtime for any application, even if it something that could be coded in a 25k .EXE file based on Win32.
It uses the OS's browser so it doesn't have the bundle size issue you describe.
That's the pitch anyway. People can spend a lot of time on ios vs android in react native applications, so ymmv
Browsers have become a lot more standardized. What also helps a lot is that windows is now Chromium edge instead of IE or old edge. Testing tools have also come a long way.
It's the same as building web-apps.
You'll need to ship Microsoft's new Edge runtime thing, which is a separate package. You'll either have to include that giant package in your package or download it on demand, and the latter is very brittle and will fail if MS changes their URLs or you're installing inside a very heavily firewalled (whitelisted) environment. If your product runs in enterprise settings you will get complaints from IT people about how your single installer installs a "hidden" second installer that they don't want, especially since the Edge runtime runs some kind of system service (why?) all the time. You'll have to basically take over maintaining up to date Edge runtimes in your bundles and handling edge cases because Microsoft can't ship software for their own OS. People will complain that if they uninstall your app it does not fully uninstall because it leaves the Edge runtime.
Tauri just works everywhere else but the headaches on Windows defeat the purpose to some extent.
Of course I guess shipping anything for Windows is "welcome to hell." The only way to have a package that installs and runs reliably is to bundle Every. Single. DLL. And. Dependency... or statically link it.
Edit: I'm already using Electron, though I've been wishing I could move away from it.
Edit: And I've generally followed the "bundle every dependency" approach. As far as I can recall, the only dependency in a shipping product that I ever delegated to an external installer was the .NET Framework (before the .NET Core reboot). And IIRC, that did trip up a few users; thankfully, that was only a consumer app.
Not sure what time period the original commenter is referring to, this story has developed quite a bit over the past year, even into last month - https://blogs.windows.com/msedgedev/2022/06/27/delivering-th...
Edit: and if your alternative is Electron, WV2’s fixed runtime is the same concept as Electron in a static Chromium version - https://docs.microsoft.com/en-us/microsoft-edge/webview2/con...
JavaFX has the same problem? Or you rely on user's JREs already installed? I'd think 30MB really isn't much any more.
If you have 200 electron apps, that’s 200x30mb.
With Java, the JRE is reused so the binaries can be smaller.
JavaFX can still be installed in a JRE, so that the application does not need to bundle it. This is fine for internal distributions, or distributing to people willing to put up with the minor headaches of maintaining the JRE separate from the app.
But, consider, for example, NetBeans does not come with its own JRE. It's not a great leap, since it's a first most Java IDE, but if you wanted to use NetBeans for PHP, you'd still need to install a JDK separately just to run NetBeans. NetBeans doesn't use JavaFX, the point simply being that there are still large Java apps out there that require you to separately download the JRE/JDK. How much this is a hinderance to their adoption, I can't say.
The direction is towards all in one JRE/FX/App bundles, but that doesn't mean it's the only way.
If you can just deploy the app jar file, the apps can be quite tiny.
In the middle ground, https://jdeploy.com manages this. They host applications, but as I understand it you can deploy the infrastructure yourself and host it yourself.
You download the app, and their infrastructure will download the appropriate JRE (including JavaFX), and share it among all those apps that do, indeed, share it.
It has "up to date" systems for updating your app. When you download the app, you get an installer that does all the work.
This is great if you have a bunch of small apps you wish to distribute, as they're basically just the jar files. The first install is a kick, of course, and as you move through the JVM versions, they'll all incur an additional hit.
But if you distribute a dozen apps all on JDK 17, then the overall download should be quite small as the JRE is only downloaded once.
I have yet to use it, but it demos nice.
As for Fonts, they seem OK to me. I use macOS, but I've also looked at them casually on a Linux VM. However, there is one sticky bit with the fonts.
At least on macOS, the default font is terrible simply because, of all things, it doesn't support the different font faces. You can't do BOLD with the stock font. It's quite the nut until you figure that out.
So, I ended up embedding a font in my app. And it all worked. It rendered fine on my Mac, and the Linux VM, and it printed to the printer well as well.
I chose Source Sans Pro, which is one of the available Google fonts.
It's annoying that I had to go down that rabbit hole, but it is what it is.
There's some ramp up time with FX to be sure, but the combination of FX with the SceneBuilder to do layout works.
This is a recent screen shot of my app, I'm no UI guy (I majored in "Programmer Art" in college...), but it looks OK to me.
https://capture.dropbox.com/AuXy4deWZTAHGHk7
This is the default theme, there are others. The CSS part of FX is really nice.
I hold FX in high regard. I've certainly had my share of head flattening desk denting events with it, but it's nice, it works.
To put things in perspective, my first hard drive, back in 1989, was 30 megabytes. I think it did about 500Kbytes/sec for reads. I also had a 2400 baud modem.
Today, 30 megabytes is a 1 second download on a bad day.
It really felt like something created by someone but never used in the real world. Is it even used anywhere?
Possibly still is like that. But that gets around to your question... is anyone still around to notice?
https://en.wikipedia.org/wiki/Composite_artifact_colors#Appl...
I recently found this tutorial: https://tkdocs.com/tutorial/index.html and am going thru ut.
But the problem is the deployment story. It requires native libraries so you need to package it somehow. Ideally, one day GraalVM will support JavaFX. That day isn't here. So you need JavaPackager which is one of the more awful ways to deploy anything at scale.
It pains me to say it as a Java fan, but most people will be better off with Electron.
And as far as I know jpackage and the like should be able to package a javafx program just fine.
I shipped multiple. JDeploy solves some of those things but it's not as refined as native packaging.
I just let it package a "portable" (no need to install) directory of all dependencies and that's it. Users just download a ZIP and can use my programs.
The whole idea of using Java is to support something other than Windows. I use a Mac and all companies I worked with had all common OS's on desktops. The edge cases are the problem. This isn't a product for other engineers. At least not engineers who have experience with JVM conflict issues.
For end users and to get a smooth installer experience there's a huge distance. Customizing the installer in the packager is a nightmarish problem... Or at least it was the last time I did it.
The bundle is huge because it needs to include a JRE and JavaFX. The install process and bundle building is complex. Especially with signing. And you need to do it all for every platform.
1. Take care to ensure that you follow platform guidelines
2. Ensure that the view and controller are not tightly coupled
3. Ensure that whatever libraries you want to use have support for all platforms you want to support
4. Pray that you don't need something very platform specific (or need to use Bluetooth, which I am told is a huge pain)
Flutter Desktop seems promising, and at least good enough to create some cross-platform Desktop apps like Rows: [0]
[0] https://blog.rows.com/p/we-built-a-desktop-app
I happen to think Lazarus (based on Free Pascal) is great, but it's not a functional language at all.
While the Qt API is imperative (`self.layout.addWidget(self.text)`, ...), focusing on declative Qml whenever possible helps with a more declarative approach.
Heartbleed was reviewed twice by literal OpenSSL experts and security experts who were specifically looking at it to determine whether it was a security vulnerability or not and concluded (incorrectly) it was not. And now it's the poster child for bad software bugs.
It's really hard to write correct software in any language, and time has shown again and again that memory safety is just not something you can hope to do without if you care about security in the slightest.
Maybe look into Skia, it’s Googles abstraction layer for multiple graphics libraries on multiple platforms.
But if you are just learning, I wouldn’t concern yourself with any of those sort of environment conditions, just figure out how to make something that works on your preferred OS.
For example, if you use Windows, learn 2d rendering with direct x. Learn about event handlers for controller interaction. And of course read about MVC.
Now you can build completely native GUIs in the appropriate language for each platform. Start with the platform which will likely have the most users for the application. Bonus if the application is open source, other developers will build all kinds of native GUIs for you. Just look at how many GUIs are out there for things like PostgreSQL, Git, IRC, etc.
I know this doesn't exactly meet your requirements, but I think this is the way to go if starting something in August 2022.
Beware the bias of the loud minority. For every 1 noisy user, there may be 50 quiet users who are fine with the decision to use Electron.
Shipping beats not shipping every time, and if Electron is what you need, then do it. I say this as someone who does not like Electron, but also as someone who knows that writing comments on HN is 100x easier than actually shipping production software.
Beware the bias of the loud minority.
Hear hear.
Though depending on the application(s) in question, if JS and things that traspile to it are attractive to the developer then they could also consider an offline-first/-only web app. Not practical for everything and adds its own family of potential complications, but worth considering.
> but also as someone who knows that writing comments on HN is 100x easier than actually shipping
As someone who has a huge pile of projects just waiting to be started (and one or two languishing in a PoC state) I think your 100x factor is more than a little too small!
I have 16GB RAM and even then I feel the hog with Discord, Slack, VS Code, A note app taking up too much memory. Then there is unnecessary security risk of bringing all the browser issues along with it.
People shouldn't have to buy an expensive Mac books to use normal apps. That should be for MLOPS or other processing heavy tasks.
Also, an Electron app uses anywhere around 150+MB to 400ishMB ram on normal cases. For one app.An app like QOwnNotes uses only a small portion of it. 50MB-100MB max. So when you you add just 10 electron apps, the number just blows up.
I feel like whatever progress with performance we are making with processor is just cancelled out with things like Electron. That is just sad.
So no. I don't think this is a good example of loud minority scenario.
But I'd rather people ship something and refine the Electron version than never ship anything at all. Mostly because I believe more in indie devs than I do in the purity of software.
I spent a few hours last night on a personal project trying to get something relatively simple working as a SwiftUI macOS app. I needed to customise a bunch of components to get it close to what I wanted.
I decided to give Electron a go, and had what I wanted up and running quite literally in 5 minutes, and it starts and is responsive within 500ms. It's taken longer to figure out how to ship it as a .app package than to write the code. That's nothing short of amazing.
Why? The only way to get a truly native look and the ability to specialise for each OS. Maybe Windows does threading better than Linux and can be optimised in some way. Maybe Linux has some nicer native UI controls that could make that part better on Linux.
Otherwise cross-platform mostly means a UI that is not native looking on any platform. Haven't used QT recently but of all I used, that was the closest to what you are asking for (I was using C++ - sorry, it's not that bad!) but I think there are bindings in other languages, although they might well have some bugs compared to the basic C++ version.
Though overall, its not an uncommon issue. I've found myself in the same place multiple times, I've even considered using a lightweight game engine just for their UI features. But next time I run into it, I imagine Flutter will be what I go with
Edit: Just realising you said "native-looking". Not so sure about Flutter for that, I'm not sure such a thing exists.
If you don't actually care about creating platform native UIs, you'll always be creating something that is a second-class design while putting in first-class effort. Why?
Frankly, you're better off just learning the operating system platform native UI programming language and get over yourself if you want to create something that looks like it was actually designed for the OS you're using.
And really, it's immature and insulting to call languages insane. Suck it up, these are peoples' professions here. No one wants to read that.
There are some very powerful capabilities in Objective C (like swizzling) that can be of tremendous help when you have some oddball functionality to implement. This would be conceptually very similar to the monkey-patching that folks do with Python. Perhaps this is the sort of thing that makes it not sane to you?
Also java can run on any platform so javafx, etc..
Here is a simple Julia GTK project on GitHub: https://github.com/ordovician/RocketBuilder.jl
Some articles I wrote related to GTK programming with Julia and GTK in general:
- Understanding GTK Layouts: https://itnext.io/understanding-gtk-layouts-13e5a36256fa
- Hiccups Writing GTK3 GUI Code in Julia: https://towardsdev.com/hiccups-writing-gtk3-gui-code-in-juli...
If Julia is not your cup of tea then GTK can be used with Go and Swift as well.
Most cross platform frameworks won't really look 100% native. The only exception I know is wxWidgets, which provides an abstraction layer over the native toolkits. It's written in C++ but there are bindings for Python, Ruby and other languages. But even using this, apps might not feel truly native. There is more to nativeness than looks. It's also about subtle conventions and ways to do things. You only achieve this when you use a native framework and pay a lot of attention to the HIG guidelines of the OS.
My personal (and perhaps a bit unpopular) opinion is that native looking is a bit overrated. And it's mostly macOS users who look for this. Linux and Windows users already get a lot of diversity in their looks and feel because there is no single framework for those OSes.
More important than native looking is to have a GUI that is fast, efficient and accesible. The best option that provides this in a cross platform way is QT. Java Swing and JavaFX are also good options.
The most productive tool to have cross platform GUIs right now is Electron. That's just a fact. And it's the reason why so many modern products are using it. But as we all know, there is a price in efficiency.
There are a bunch of new projects in the works to improve cross platform GUI for modern languages. JetPack Compose Desktop, Flutter, Slint and many more. But these are not yet fully mature.
I would echo this. Consider applications like Photoshop or Blender, these don't really have a 'native' feel anywhere but their UX is generally responsive. On the other hand you have Electron applications that don't feel native and are also sluggish...
I was considering using it for some app that otherwise would be PWA. While I didn't use in-depth features and didn't run into any serious problems, it is likely that not everything will be perfect, but it is also likely that overall experience will be more pleasant.
https://tauri.app/
Check it out.