Nyxt as a backend application framework?

I’ve been looking into some web programming with CL. There’s quite a lot of alternatives, even many options from a single author. I find Reblocks quite interesting, but I’m wondering if maybe Nyxt headless mode could be used for similar purpose?

This is a very intriguing idea. Of course you can imagine they dynamic nature of CL would allow you to do many things.

It definitely can be used for that purpose. We’ve thought of it, but haven’t actually done anything with that idea. So far we’ve sort of “reinvented” the wheel a little bit with our own UI framework, and that’s about it :smiley:

I mean, we already have our own infrastructure for applications, consisting of:

  • Internal pages as views (see define-internal-page[-command[-global]], buffer-load-internal-page-focus, and the internal-page class itself).
    • Panels as a type of internal pages too (see define-panel-command[-global] and panel class).
  • Commands as controllers (see define-command[-global], lambda[-mapped|-unmapped]-command, run[-async], and command class itself.
    • Also see ffi-add-context-menu-command.
    • Also see the FFI events, such as on-signal-notify-uri, on-signal-load-started, on-signal-button-press etc.
    • And, obviously, hooks like the essential request-resource-hook and buffer-loaded-hook.

Then, what’s left for MVC (in case you prefer this application architecture) is the model, which might be anything. But what could work well is something like our REPL architecture with cell class and cell actions.


This framework works well with HTML/CSS/JS generators, like Spinneret (which we use and have a huge interface library for—see spinneret-tags.lisp in Nyxt checkout), CL-WHO, and others. But it might be too restrictive for full-blown web frameworks like Reblocks of CLOG. These I’m not sure how to approach, but it should be possible to instrumentalize Nyxt for them too!

1 Like

Yes, looks like it works right out of the box!

(hunchentoot:define-easy-handler (nyxt-new :uri "/new") ()
  (setf (hunchentoot:content-type*) "text/html")
  (let* ((cmd (nyxt::find-command 'nyxt:new))
         (buf (funcall cmd))
         (model (nyxt:document-model buf)))
    (plump:serialize model nil)))

1 Like

It’s not quite the SPA of Reblocks or Clog, but maybe htmx could live it up: https://htmx.org/

That’s actually really cool. We could make a sort of demo and interactive manual that’s running on a real instance of Nyxt. People could hack with the REPL without even doing an installation. The possibilities…!

1 Like

Yeah, it’s really cool! Need to experiment with command interactions, partial updates, security (e.g. using GitHub - kanru/cl-isolated: A restricted environment for Common Lisp code evaluation) and more. But I find it intriguing!

@simendsjo I’m amazed by your creativity everytime!

I believe this topic deserves an article on our website.

2 Likes

Looks like it’s only going to work for https, and not on Safari or most mobile browsers.

See Navigator: registerProtocolHandler() method - Web APIs | MDN

navigator.registerProtocolHandler(
  "nyxt",
  "https://whatever-site-we-are-on/command/%s"
);

But with this, I assume we should be able to click around in the new/tutorial etc.

I got some time to hack on this again. I do a regex replace for all nyxt: and nyxt-resource: into calls to the backend Hunchentoot server, so now I’m able to navigate and fetch resources.

pretty cool, do you have like a short video or something we can see?