6 ms·
Spinneret: A modern Common Lisp HTML generator
- deleted 3y ago[deleted]
- Capricorn2481 3y agoAre there people here that prefer Common Lisp to Clojure for webdev specifically and would like to tell us why?
- aidenn0 3y agoSure: 1. I've been using CL for longer than Clojure has existed 2. SLIME is better than any Clojure dev setup I've seen 3. Maybe I'm misunderstanding things, but if I get how Leiningen works, I need to restart my REPL any time I want to add dependencies? 4. Kind of a minor thing, but working in a Lisp-1 hits the "uncanny valley" of programming for me; I accidentally shadow an important function at least once an hour when working in Clojure or Scheme.
- Capricorn2481 3y ago> 3. Maybe I'm misunderstanding things, but if I get how Leiningen works, I need to restart my REPL any time I want to add dependencies? That is correct, though a lot of people are moving to `deps.edn` which recently lets you add dependencies on the fly.
- koito17 3y agoThis isn't a tools.deps specific functionality. Pomegranate has always allowed one to dynamically add dependencies to a running Clojure REPL. Now that add-lib was added in Clojure 1.12 alpha, people do not need to use pomegranate to dynamically add dependencies. In fact, Leiningen itself can make use of add-lib.
- capableweb 3y agoI'm no CL expert but I've written my fair share of Clojure code, just as a preface. > I accidentally shadow an important function at least once an hour when working in Clojure You mean that you accidentally "overwrite" (declare again) a function with the same name as the one you're now declaring, but you didn't mean to? If so, I'm not sure how that'd be possible. In Clojure you're always in a namespace, and you'd only have one function with that one name in that namespace, and if you're declaring a function with the same name in a different namespace, you now correctly have two functions with the same name, but in different namespaces. Unless your editor<>repl connection somehow ignores the current ns, I'm not sure how you'd end up in that situation. > SLIME is better than any Clojure dev setup I've seen This I'm also curious about, what exactly SLIME gives you that for example Conjure for neovim wouldn't already? Maybe something about continuations perhaps? That seems to be the only feature I've seen from Common Lisp (besides actually being able to compile to binaries) that I'd love to have in Clojure.
- aidenn0 3y ago> You mean that you accidentally "overwrite" (declare again) a function with the same name as the one you're now declaring, but you didn't mean to? I mean I use let to bind a variable with the same name as a function. This is idiomatic in Common Lisp, and totally breaks things in most other languages. > This I'm also curious about, what exactly SLIME gives you that for example Conjure for neovim wouldn't already? Maybe something about continuations perhaps? That seems to be the only feature I've seen from Common Lisp (besides actually being able to compile to binaries) that I'd love to have in Clojure. I watched a video and it does seem rather complete, but [1] indicates there is no debugger? That's a rather glaring omission. I also don't see a profiler mentioned, and SLIME with SBCL gives me a profiler (down to the assembly level if needed). I'm sure Java in general has great profiling tools, but how are the integrated into the Clojure system? As an aside, by "continuations" did you mean "restarts"? First-class continuations are a feature of scheme, not CL. Indeed a huge boost to CL productivity is simply allowing you to handle an exception before the stack is unwound. 1: https://github.com/Olical/conjure/wiki/Client-features https://github.com/Olical/conjure/wiki/Client-features
- 3y ago
- mksybr 3y ago> 3 https://github.com/clj-commons/pomegranate https://github.com/clj-commons/pomegranate https://stackoverflow.com/questions/16409182/any-way-to-add-dependency-to-lein-project-without-repl-restart https://stackoverflow.com/questions/16409182/any-way-to-add-... => (use '[cemerick.pomegranate :only (add-dependencies)]) nil => (add-dependencies :coordinates '[[incanter "1.2.3"]])
- fiddlerwoaroof 3y agoThis works except when it doesn’t: my experience is that it seemed like the JVM is fundamentally static at its core in a way that makes it hard to implement a CL-style environment using Clojure’s hosting strategy. Boot build comes really close, here, but the community never really adopted it.
- deleted 3y ago[deleted]
- mmmm2 3y agoI started off with Clojure and then moved to Common Lisp. They're both good languages. My Clojure is rusty, so I'll just list some positive things I found about using Common Lisp. This is from my experience creating a small website that runs on AWS with: - nginx - SBCL - hunchentoot - easy-routes - cl-json - cl-sqlite - ... Most of the positives come from Common Lisp's condition system and built in debugger. I like the ability to hit an unexpected condition, pause, poke around at things, re-compile, and retry the code. This can be very useful for something interactive like a website. It took me a while to get the hang of it, but once you learn it it's quite powerful. You can also apply the same techniques to the production server with minimal fear you're going to break stuff. Common Lisp is designed with the idea that developers will change state on the fly, so it has mechanisms in place to make this easy and reasonably safe. SBCL is also "fast", at least when compared to Python or Ruby, but I imagine Clojure is too. I would assume most other benefits would be similar with Clojure (Macros, html generation, etc.)
- fulafel 3y agoWould you or someone else happen to have a link to a screencast with this dev flow? The restarts sound vaguely useful but how they concretely help (vs reloading based workflow) could be cool to see.
- vindarel 3y agoThat's a short video I made to show this: https://www.youtube.com/watch?v=jBBS4FeY7XM https://www.youtube.com/watch?v=jBBS4FeY7XM It's a feature that is useful everyday, if only to speed up trivial things.
- kazinator 3y agoI ported CL-WHO (another HTML generator for Common Lisp) to TXR Lisp, under the name TL-WHO. In TL-WHO, there is a deftag inspired by Spinneret. https://www.kylheku.com/cgit/tl-who/about/#the-deftag-macro https://www.kylheku.com/cgit/tl-who/about/#the-deftag-macro deftag lets you define macros targeting tags in the HTML structure, which expand into combinations of other tags.
- vindarel 3y agoMore HTML generators for CL: https://github.com/CodyReichert/awesome-cl#html-generators-and-templates https://github.com/CodyReichert/awesome-cl#html-generators-a... there are lispy ones (Spinneret), Django-like ones (Djula, I like it, easy to use and extend), HTML-based allowing for inline Lisp code (Ten), JSX-like ones (lsx, markup), and more.
- neilv 3y agoIf Scheme/Racket people are feeling inspired, you could look at two that I made, and make something with different properties, informed by Spinneret: * Static syntax-based: https://docs.racket-lang.org/html-template/ https://docs.racket-lang.org/html-template/ * Dynamic data-based: https://docs.racket-lang.org/html-writing/ https://docs.racket-lang.org/html-writing/ I like that Spinneret focuses on HTML5. My work started over 20 years ago, with HTML always being quirky, and also sometimes used in conjunction with my permissive HTML parser. So there's a need to maintain backward-compatibility with how things worked before, including weird non-open-source things. (With the parser, I've also recently gotten requests to support 20yo HTML, for dealing with legacy data.) Doing something all new, tailored to HTML5 or something higher-level, would be able to do some things better. (But I strongly recommend trying to stick with SXML representation/syntax at some level, though, since it's a de-facto standard in the Scheme world, and can be used in a way compatible with representing HTML5.)
- tagfowufe 3y agoHey, thanks for contributing to Racket. I'm about to finish the first third of 'How To Design Programs' [0], and am slowly becoming a fan. Always love to see Racket being mentioned! [0] htdp.org
- ducktective 3y agoSo how does developing a modern website using CL looks like? If I understood correctly, this produces the pages on server-side (so SSR). But how does "styling" and "interactivity" comes into place?
- medo-bear 3y agoIt generates HTML from common lisp s-expressions. This is useful because s-expressions are much easier to write and manipulate, especially with a package like paredit. https://paredit.org/ https://paredit.org/
- fiddlerwoaroof 3y agoI’ve been using spinneret + htmx + lass[1] + parenscript (as needed) + hunchentoot for various interactive applications for a while. I don’t have a ton to show, but it’s a nice quick way to quickly produce one-off apps. And, with htmx’s websocket capabilities, you can use the browser as a sort of repl sidecar for visualizing things (together with something that generates svg) [1]: https://github.com/Shinmera/LASS https://github.com/Shinmera/LASS
- aidenn0 3y agoHave you written up anything about htmx with lisp? My last CL webapp used MithrilJS and parenscript, but htmx looks like a better fit.
- fiddlerwoaroof 3y agoNot really, I’ve intended to come up with a sort of framework for automatically serving partial pages when the relevant headers are present, but it’s pretty straightforward to use. The only slightly tricky part is spinneret’s attribute validation
- aidenn0 3y ago> The only slightly tricky part is spinneret’s attribute validation I'm firmly in camp cl-who, so not a problem for me :)
- kruhft 3y agoNo examples. Bad name. Why is it better than cl-who and parenscript together? Nice job though. The code is clean.
- medo-bear 3y agoI see examples
- junon 3y agoIf you scroll just a tiny bit there is a large, complete example.
- svetlyak40wt 3y agoSpinneret is better than CL-WHO at least in it's string escaping policy. All values are escaped by default whereas with CL-WHO you need to wrap with CL-WHO:ESC all string values. Thus CL-WHO is vulnerable to XSS attack by default.
- svetlyak40wt 3y agoParenscript is other tool. Mainly it generates Javascript. However it has support for CL-WHO like templating for generating HTML on client side.
- kruhft 3y agoI looked through the code and found some parenscript, or at least something that reminded me of parenscript alot. Just bringing up some history. I don't know the age profile of the developers or readers anymore. Just trying to look smart.
- deleted 3y ago[deleted]
- schemescape 3y agoAm I out of line for disliking the number/size of dependencies Spinneret pulls in?
- mtreis86 3y agoASDF depends-on ("parenscript" "alexandria" "cl-ppcre" "global-vars" "serapeum" "trivia" "trivial-gray-streams") That doesn't seem excessive. I didn't look to see how many imports each gets. Need the utility libraries? Probably not. Embrace the NIH. Need both trivia and PPCRE tho? They both pattern match.
- hayley-patton 3y agoTrivia pattern matches (a la ML, probably weaker than tree regular expressions) on data structures/trees, PPCRE regular expressions on strings.
- deleted 3y ago[deleted]
- oladon 3y agoI'm generally not a huge fan of templating "languages". (Probably because they're almost never actual languages, and typically when they are, they turn into symbol soup that doesn't look anything like the end result, structurally speaking.) That said, I've been using Spinneret for a side project[1] for a while, and overall I'm very happy with it. It's nice to have macros like deftag and all the other magic powers of Common Lisp, and because of CL's syntactic simplicity, the templates remain easy to read and reason about while getting a lot done. I recommend giving Spinneret a try! [1] rpanytime.com