14 ms·
Clojure on the Desktop
- vikeri 7y agoVery interesting to use a redux (re-frame) like programming model for building native desktop UI's. I have done some basic stuff with it and it sure seems powerful. For anyone interested there will be a virtual meetup 16:th of April 6PM CEST: https://www.meetup.com/sthlm-clj/events/269204900 https://www.meetup.com/sthlm-clj/events/269204900
- rubber_duck 7y agoNot really native - it's JavaFX. I love clojure but personally flutter seems way more viable for the use cases I could imagine using this.
- brabel 7y agoAs someone who used to like JavaFX and maintain a few desktop apps that use JavaFX, I have to say you're totally right. Google seems to be putting huge amounts of effort on Flutter, and it can already run on the desktop (still early stages and in alpha I believe)... JavaFX is mostly orphan right now. Oracle seems to have no interest in it... so it seems to be currently being mostly advanced by Gluon[1], which honestly, does not have the muscle to pull out something competitive with Flutter or Electron. JavaFX still has fundamental pieces missing... like setting an icon for the app or opening some URL in the system browser[2] (without using horrible hacks, which is what I've been doing - which get you lots of warnings since the module system was introduced, and may stop working soon). Not to mention no support for auto-updates, the fact that jpackage is still in "incubator" stage[3] and intentionally does not have JavaFX-specific features at all (it's just barely usable with JavaFX), the SceneBuilder, which could be such a great tool to develop UIs, similar to Lazarus, but it's nowhere as good, being in about the same unfinished state it was in around 2014, terrible documentation and lack of adoption (most examples you find online are from circa 2015, when JavaFX got a little traction)... These things all make JavaFX a very hard sell for non-developers apps (if you're a developer who does not mind installing the appropriate JVM version to run the app, JavaFX works quite well - a 1MB jar can give you A LOT of features - one of my apps, my favourite and really useful, is only a 340KB single jar and works on any JVM 8+ - and looks as modern as any Electron app). It's sad but the best way to get professional apps developed and distributed nowadays seems to be, by far, Electron (because of JS, and its stupid browser-based architecture)... but I am hoping Flutter will break Electron's hegemony soon as I have great experience developing Flutter apps on mobile and the web... Just try the online pad[4] to get a taste of what it looks like! It's amazing. [1] https://gluonhq.com/products/javafx/ https://gluonhq.com/products/javafx/ [2] https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8091107 https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8091107 [3] https://openjdk.java.net/jeps/343 https://openjdk.java.net/jeps/343 [4] https://dartpad.dartlang.org/ecb28c29c646b7f38139b1e7f44129b7 https://dartpad.dartlang.org/ecb28c29c646b7f38139b1e7f44129b...
- tosser678 7y agoHow does TornadoFX compare? it seems more focused on enterprise apps though
- brabel 7y agoTornadoFX is just a Kotlin wrapper around JavaFX. It makes writing apps much nicer, but has considerable cost in terms of even more memory usage and, obviously, due to the Kotlin runtime and lots of Kotlin wrappers for most JavaFX classes, app size.
- pjmlp 7y agoIn that regard I think React Native has much better future than Dart/Flutter, specially with Microsoft backing it now, unless Fuchsia actually gets released.
- hopia 7y agoWhy is that? You mean that you're worried about Google calling quits on Flutter sometime soon?
- pjmlp 7y agoFlutter is all about being the last opportunity to sell Dart, and I doubt that Chrome (PWAs) and Android (JetPack Composer) teams are that happy about its existence, given the political answers when questioned about Flutter on their own Q&A sessions.
- hopia 7y agoI don't think purely about Dart, originally it seemed to be aimed as a technically more robust cross-platform competitor to React Native. Its implementation has good merit in that regard. That said, it may well not survive nearly as long as RN will, time will tell.
- sdegutis 7y ago
- phronmophobic 7y agoIf you're interested in desktop alternatives for clojure, check out https://github.com/phronmophobic/membrane https://github.com/phronmophobic/membrane. It's different from javafx in that all the event handling code is pure clojure. For graphics, it uses skia, https://skia.org/ https://skia.org/.
- capableweb 7y agoLove the example with the spacer, guess we're back to building UIs with tables soon as well! (defn counter [num] (horizontal-layout (on :mouse-down (fn [[mouse-x mouse-y]] (swap! counter-state inc) nil) (button "more!")) (spacer 5 0) (label num (ui/font nil 19)))) Otherwise, haven't heard about Skia before, so thanks for sharing that, looks really nifty.
- phronmophobic 7y agoThanks! More complicated layout strategies are easy to integrate, but spacer works really well for examples since most people can intuit what the result will look like. Skia has worked well so far. Since it's used by Chrome, Android, and Firefox under the hood, it means that I can reach a lot of platforms "for free".
- rvz 7y agoHmmm... Lets see the HN Reader example then... 95MB for the macOS DMG. 177MB for the actual example app. For a typical hello world application like the HN example, it appears that it would be no better than running an electron-made version given that they both include their own versions of their respective runtimes. In this case, this includes the entire Java runtime which Clojure needs to run. I think I would be better off with using either C++ with Qt5 or even FreePascal with the Lazarus IDE for this instead.
- mister_hn 7y agoAs suggested in the article, the usage of jpackage comes with a lot of drawbacks: - still a JRE is shipped (you MUST tailor it to the bare minimum with the flags) -> can be + ~30-40MB - OpenJFX/JavaFX relies on Qt (especially for the WebView) -> can grow up to + ~70MB - all the legal documents and docs are shipped together (you have to remove them with a post-process script) -> + ~5-10MB Using JVM for desktop apps is expensive in terms of space. Time can be reduced consistently thanks to the graal native compiler, but still a C++ project outperforms Java GUI applications by 500%
- pjmlp 7y agoOpenJFX/JavaFX uses WebKit for the WebView, Java never had any dependency to Qt. https://github.com/openjdk/jfx/blob/master/modules/javafx.web/src/main/native/CMakeLists.txt https://github.com/openjdk/jfx/blob/master/modules/javafx.we... I wonder where that 500% number came from, and yes C++ does blazing fast against Java in micro-benchmarks, except that on project delivery, developer salaries, time to market, additional costs for bug fixes (including memory corruption ones), available libraries, hardware costs for build performance also play a very big role.
- mister_hn 7y agoIndeed but Java Isn't that better compared to C++ when it comes to all those factors. There aren't memory corruption bugs, but the average number of Null pointer exceptions in fairly big projects can be daunting and relevant. Of course, Rust and Go here a big game changers in this way
- vijaybritto 7y agoThis looks nice and promising for multi core apps. But, 85Mb for a demo app? It sounds heavy and might end up like intelliJ IDEs I think. How about compiling to binaries with Graal native? Can it be done?
- vlaaad 7y agoYes, it can be done: JavaFX developers created a library that deals with various pitfalls of compiling it to GraalVM: https://github.com/gluonhq/substrate https://github.com/gluonhq/substrate I think using jpackage is easier to start with since there are less cutting-edge moving parts involved, and it imposes fewer restrictions on the runtime.
- vijaybritto 7y agoI hope this one picks off quickly! Electron needs serious competition
- vijaybritto 7y agoI justed checked the RAM/CPU usage on my windows machine. Its 580Mb/5% constantly!! This is way higher than electron tbh! :(
- slifin 7y agoI wonder if graalvm can be applied to the output of proton native which allows you to use ClojureScript to compile react code into QT but still in the context of JavaScript if graalvm can get a native binary out of that it'd be cool https://gist.github.com/polymeris/0112389243890709108c4b8b0a186f46 https://gist.github.com/polymeris/0112389243890709108c4b8b0a... https://github.com/roman01la/proton-native-cljs https://github.com/roman01la/proton-native-cljs
- depaulagu 7y agoyou've been cited on https://www.reddit.com/r/programmingcirclejerk/comments/g0ioco/i_wonder_if_graalvm_can_be_applied_to_the_output/ https://www.reddit.com/r/programmingcirclejerk/comments/g0io...
- piokoch 7y agoI've installed the application, it needs 840 MB of the memory. Firefox with more than 100 tabs opend consumes 1.2 GB, IntelliJ with a huge java project consumes 1.6 GB. I understand that this is proof of concept application, but what eats so much RAM? Is that the data that was read or the framework itself?
- fnord123 7y agoClojure.
- AA-BA-94-2A-56 7y agoCase clojed.
- vlaaad 7y agoPlease don't post shallow dismissals, especially of other people's work. A good critical comment teaches us something. https://news.ycombinator.com/newsguidelines.html https://news.ycombinator.com/newsguidelines.html I explained the situation in a reply to grandparent comment if you are interested to know why it is like that.
- fnord123 7y ago>Please don't post shallow dismissals, especially of other people's work. Nothing's been dismissed. The post is about a throw away program in a nascent React-on-JVM environment. People want to know why it uses so much memory. It's Clojure. Clojure is a memory hog. Case clojed. Please don't be disheartened. It's a nice show and tell and resulting discussion.
- vlaaad 7y agoIt does not need 840 MB of memory — it uses it because the purpose of this example is to show that packaging is now easy, and non-essential parts were left out to keep it simple. I just tried limiting it to 50 MB and it runs just fine.
- nico_h 7y agoAnyone knows how Jpackages compares to good/bad old JNLP or is that complementary?
- kitd 7y agoMost interesting takeaway for me was jpackage working with GH actions. V useful. Who needs a local build system now? ;)
- ptrik 7y agoSame here. Have been trying to build something similar with GitHub Actions and this is a nice reference.
- lenkite 7y agoPlease note that the Gluon Client Plugin can be used to create native JavaFX desktop apps which take far less memory. https://docs.gluonhq.com/client https://docs.gluonhq.com/client When Clojure resolves all outstanding Graal issues, one could use Clojure for native apps too, but there are several bug tickets open on Clojure wrt Graal.
- geokon 7y agoI wonder if anyone has tried cljfx->Android with Gluon's stuff
- capableweb 7y agoLast time I tried, cljfx (actually JavaFX in general) doesn't play too nice with GraalVM, I'm not sure Gluon actually addresses that, so it'll be hard to add another layer (Android) when the basic layer doesn't work.
- geokon 7y agois it part of the same pipeline? Graal is compiling to native while Gluon on Android I assume is running JFX on Dalvik instead of JVM (it possible I don't get how Gluon gets JFX to run on Android)
- Klonoar 7y agoThis is going to sound subjective, but: you can't claim that something is a good desktop-app building experience in 2020 and lead with something that looks like... that. Browsers have simply set the bar too high.
- dezzeus 7y agoI've just started designing something very similar in my free time, but for Go (golang): interface around native GUI + WebKit webview + React + bindings. I'm glad that we are slipping away from Electron...
- capableweb 7y agoHm, as far as I know, the problem most people have with Electron is not around the language, React or bindings but the fact that there is a embedded browser in there that adds a lot to the size and memory consumption (and security issues). I'm curious to hear why you're glad we're going away from Electron into something that seems to be about the same thing, albeit a different language?
- dezzeus 7y agoI expect it to be a little better trade-off given the following points: 1. JS is kept for what it's meant to be and do; nothing more. 2. A WebKit webview is probably lighter than Chromium + NodeJS. 3. The whole thing should be managed to be linked as a shared library, avoiding many pitfalls of Electron's applications (by means of a semantic-versioned library). 4. The whole solution is really language-agnostic, despite my efforts with Go.
- dgellow 7y agoHave you checked React Native for Windows and macOS? It goes even further as it get rid of the webview https://microsoft.github.io/react-native-windows/ https://microsoft.github.io/react-native-windows/ Native widgets, bridge between JS thread and the native world. That gives you good performances and the flexibility of JS/Typescrit and React to glue things together. (I haven’t tried yet, but that looks quite nice on paper)
- dezzeus 7y agoOf course I have, but that's not exactly what I was aiming for... ;)
- jiofih 7y ago> browser-based technology struggles to utilize multiple cores in the same VM instance > javascript VMs choke on processing large amounts of data, which leaves them a better fit for advanced interactive forms than compilers or data processing pipelines 2005 called and wants it’s quotes back. It is trivial to spawn worker processes today and VM performance is only 2-5x behind compiled ones, often closer. Not to mention WASM. The elephant in the room is not JavaScript or it’s VM but the browser engine. EDIT: seems like JavaFX has its own browser-like “scene graph” and embeds WebKit, so this will suffer from the same bloat in memory use and app sizes?
- StreamBright 7y agoThe real question is why though. Why should we use the HTTP/HTML/JS/CSS universe to deliver interactive applications to users. I only see downsides here. Not to mention that we pull these things into native applications like it was great to begin with. WASM might be able to address some of the shortcomings of this stack, not sure.
- jiofih 7y agoBecause it is an extremely effective model for building UIs. As I mentioned above even this project uses a similar architecture, only backed by Clojure. Any UI toolkit will have similarities with the web stack. The real issue is the size of these monster engines, but a lightweight engine that only supports the subset needed for apps is possible - see Sciter, and I have high hopes for https://ultralig.ht/ https://ultralig.ht/
- StreamBright 7y ago>>Because it is an extremely effective model for building UIs. Is it? Have you ever tried? I think it is extremely hard to build reponsive UIs that work on every platform and there are no UX problems. We have to deal with a giant amount of boilerplate in many cases because using vanilla things (JS especially) won't cut it anymore. I am not even sure how many frameworks are targeting this space and try to solve the typical issues with these technologies and fail miserably. I think some of these issues are finally started to be handled the right way (Elm or ReasonML) but there are still some painpoints left (CSS). The question still, is it worth it? Couldn't we do better? The performance implications (energy consumption) for an average website is just hilarious. We should have a day where everybody disables JS and measure how much percentage of our computing capacity is going to render websites because we do not want to move away from HTML which was not (by any strectch of imagination) designed for this to start with. If anything, this should be a concern to most of us.
- dimitar 7y agoMost of the comments are about the startup RAM use and distributable size, which is a criticism shared with Electron. The demo app is not attempting to address these particular weaknesses. The point of the article is there are some applications where processing speed is important where Clojure's and JVMs concurrency and long running and large dataset performance is very important. And the ecosystem appears to be ready to make it possible to create apps where these strengths vis-a-vis Electron are combined with the other strengths of Clojure compared to low level languages (expressive syntax, interactive development).
- grandinj 7y agoI routinely run my fairly and complex java UIs clamped to 256M of memory, and startup time is measured in a handful of seconds. Distribution size is not great I'll admit, unless you go to considerable effort to slim the JRE down.
- deleted 7y ago[deleted]
- didibus 7y agoI feel distribution size like, users should have a JRE on their machine. Same way native apps expect you to already have a bunch of existing modules already installed as well. Or at least, if many apps were all using Java, you'd only install a JRE once, and then keep getting the non JRE bundles, so size of distribution would be a lot less. What I mean is, at least for Java apps, this is a possibility. In Electron world, even though almost everyone has Chrome installed, you can't share it, you need to keep bundling the whole thing over and over again.
- slgeorge 7y agoYeah it's really interesting because it's a fully worked example of packaging a desktop application using a hosted approach. Personally, I'm more comfortable with that stack. Also worth looking at is Vlaaad's Cljfx (https://github.com/cljfx/cljfx https://github.com/cljfx/cljfx). And I just want to say the number of examples that Vlaaad has created for the project is amazing and really helpful - it's a great example of helping others on-board to use your project - thanks Vlaad.
- pengwing 7y agoWhy do you package a javascript VM at all? You could have a local server written in clojure listening on localhost:<someport>. The entire js-driven UI could just be in a browser tab.
- elcritch 7y agoOne issue with that is the lack of encryption and/or security between UI and the local server. Also I always forget the port for the local host style apps. If PWA's were easier on desktops that'd help.
- wildermuthn 7y agoI once led a mid-sized team in building a desktop application with Clojure. It might sound nuts, but we used both the JVM and Electron, using both Clojure and ClojureScript. We solved all the performance issues we’d experienced with Electron by restricting it to serve as a desktop GUI API. Literally nothing was in Electron except a small package for handling these API requests: set a menu, open a window, load a page, etc. Even inside an open window, the ClojureScript code was loaded from and communicated with the JVM, rather than being bundled into Electron. You want your desktop app to both look great and perform great. Restricting Electron to its basics while moving everything else into another system is definitely one option to consider.
- sdegutis 7y agoI honestly cannot imagine how that would be more performant than just using Electron by itself the typical way, unless this was a very CPU intensive application like a video editor.
- karatestomp 7y agoLast I checked, due to how Electron’s structured, you basically have to decouple “logic” from the UI anyway, which makes it relatively easy/natural to make the “logic” side just a thin translation layer talking to some other language.
- efficax 7y agonot sure what you mean here. You can write a full fledged app in Electron without any 'backend'
- karatestomp 7y agoLast I checked it runs a process (I think a full process, not just a thread?) for the UI and another for the rest of the application, and the two talk via calls to IPC functions.
- truth_seeker 7y agoWhy did you guys use JVM at all ? If it's for multi-core computation purpose it can be with Worker Threads in JS or CLJS.
- sdegutis 7y ago> outperforms plain React a lot of the time due to optimizations that re-render components only when their inputs change Is this not exactly how React also works?
- mst 7y agoNot quite, because if react is re-rendering a component it re-renders all its subcomponents as well whether they've changed or not - the DOM diffing stuff means it won't screw with the DOM for stuff that hasn't changed, but it still has to regenerate it to find out.
- sdegutis 7y agoSo reagent skips this by only re rendering a parent of only the parent changed and only re rendering the child of the child’s j out changed? (Presumably using its atoms for props then too and not just state?) This somehow sounds error prone.
- mst 7y agoThat sort of thing is honestly pretty pleasant to write and test in lisp like languages. I wouldn't want to try and write it in javascript, but I'm entirely willing to believe that clojure/cljs got it right.
- sdegutis 7y agoI don't see what s-expressions have to do with this concept. It should be just as doable and nice in JS...
- truth_seeker 7y ago>>browser-based technology struggles to utilize multiple cores in the same VM instance, while Clojure’s immutability by default, concurrency primitives and core.async make writing multi-threaded code a breeze; Are you kidding me ? You can achieve concurrency in either with Chromium or NodeJS by using worker threads. There are libraries (like Thread.JS for example) which provides a layer of abstraction over Worker Threads and Thread Pool to even make the job simpler. or You can use CLJS + core.async + web worker. >> javascript VMs choke on processing large amounts of data, which leaves them a better fit for advanced interactive forms than compilers or data processing pipelines; Worker Threads were shipped in January 2015. This is March 2020. >> Clojure’s REPL-aided development with fast feedback loop is perfect for tinkering with UI, as opposed to compile-and-restart-the-app-and-then-navigate-the-UI-to-see-your-change approach of other languages. Now, this is clear lie. I have been writing Single Page Application which updates the UI instantly since 2012. Ever heard of GruntJS ? GulpJS ?? WebPack ??? All of them provide a eco system of plugins which facilitate progressive build
- derefr 7y agoThe “problem of concurrency” isn’t about solving embarrassingly-parallel problems by spawning async threads and letting them run. Every runtime can indeed do that, but that isn’t worth mentioning when talking about “concurrency”, because you can also do that by just spawning multiple of your runtime itself. (I.e. if you’re not doing any IPC of note, then there’s no difference between multithreading and multiprocessing. In the web case: you could just use an iframe.) The “problem of concurrency” is really the problem of having cheap IPC between your threads (i.e. the ability to pass around large amounts of data using small messages/handles), so that you can shape your threads into architectures like a staged data-flow pipeline, or a set of schedulers for an actor system. JS does not have cheap concurrency. (What would cheap concurrency in JS look like? Well, the ability to make an ArrayBuffer immutable, and then pass the immutable ArrayBuffer to another Worker Thread “by reference”, would be a good start. Add “mutably-immutable by copy-on-write” ArrayBuffers on top, and you could actually afford to pass ‘ownership’ of an ArrayBuffer back and forth, writing to it across multiple threads. Then you’d have something that you could maybe run a multithreaded WASM program on top of and have it run to completion before the heat-death of the universe.)
- teataster 7y agoSome people just hate Clojure for some reason. I had a coworker of mine rewrite my whole Clojure project in Java just se we would not deploy Clojure.