Posted on • Edited on
Common Lisp GUI with Electron · quick how to
Yes, it is possible to bundle a Common Lisp web app into Electron, with any web server, so Hunchentoot is possible.
I have a working POC but was planning to write a detailed blog post with more details and a demo sorted out, so stay tuned ;)
Our method starts the Electron process, starts the Lisp web app as a subprocess on localhost on the given port, and opens this address inside the Electron window.
In a nutshell:
- follow Electron installation instructions,
- build a Lisp web app as a binary
- seehttps://lisp-journey.gitlab.io/blog/lisp-for-the-web-build-standalone-binaries-foreign-libraries-templates-static-assets/ (the process will be a tad simpler without Djula templates)
- bundle this binary into the final Electron build.
- and that's it.
I mean, you can run the Lisp web app from sources, but then ship all sources.
You can have a look athttps://github.com/mikelevins/electron-lisp-boilerplate for this, their main.js has the pattern, using child_process.
What about Ceramic?
You can ignore the Ceramic project, unfortunately, it's a wrapper around Electron (npm) tools and is broken and outdated. It will try to install an old Electron version and fail. That being said, the Ceramic org has a few useful helper projects we can use.
Example main.js
This file is adapted from the main.js you get after installation, to run an application as a subprocess.
console.log(`Hello from Electron 👋`)const{app,BrowserWindow}=require('electron')const{spawn}=require('child_process');// Suppose we have our app binary at the current directory.varbinaryPaths=["./openbookstore",];// Define any arg required for the binary.varbinaryArgs=["--web"];constbinaryapp=null;construnLocalApp=()=>{"Run our binary app locally."console.log("running our app locally…");constbinaryapp=spawn(binaryPaths[0],binaryArgs);returnbinaryapp;}// Start an Electron window.constcreateWindow=()=>{constwin=newBrowserWindow({width:800,height:600,})// Open localhost on the app's port.// We should read the port from an environment variable or a config file.win.loadURL('http://localhost:4242/')}// Run our app.letchild=runLocalApp();// We want to see stdout and stderr of the child process// (to see our Lisp app output).child.stdout.on('data',(data)=>{console.log(`stdout:\n${data}`);});child.stderr.on('data',(data)=>{console.error(`stderr:${data}`);});child.on('error',(error)=>{console.error(`error:${error.message}`);});// Handle Electron close events.child.on('close',(code)=>{console.log(`openbookstore process exited with code${code}`);});// Open it in Electron.app.whenReady().then(()=>{createWindow();// Open a window if none are open (macOS)if(process.platform=='darwin'){app.on('activate',()=>{if(BrowserWindow.getAllWindows().length===0)createWindow()})}})// On Linux and Windows, quit the app main all windows are closed.app.on('window-all-closed',()=>{if(process.platform!=='darwin'){app.quit();}})
What's left as an exercise: automatically bundle the binary into the Electron release.
Then, communicate from Lisp app <-> Electron window (optional though).
Any feedback and demos welcome, this was a quick post.
Happy lisping
ps: and Tauri?
I suppose it's the same process. Prove me wrong ;)
Will test and show an example soon©, if you have experience please share in the comments 🙏
https://lisp-journey.gitlab.io/
Top comments(1)

- LocationFrance
- Joined
There's a great recent project using Ceramic though!github.com/neomacs-project/neomacs/ a structural editor and browser.
For further actions, you may consider blocking this person and/orreporting abuse