[HN Gopher] Django, HTMX and Alpine.js: Modern websites, JavaScr...
       ___________________________________________________________________
        
       Django, HTMX and Alpine.js: Modern websites, JavaScript optional
        
       Author : czue
       Score  : 282 points
       Date   : 2021-11-23 15:37 UTC (7 hours ago)
        
 (HTM) web link (www.saaspegasus.com)
 (TXT) w3m dump (www.saaspegasus.com)
        
       | jamesgeck0 wrote:
       | It's worth noting the security tradeoffs of these micro-
       | frameworks.
       | 
       | HTMLX uses innerHTML/outerHTML extensively, meaning that XSS is a
       | real concern. Any sanitation of user-generated content must
       | happen server-side. This how traditional server-side frameworks
       | generally work, but it's the opposite of how sanitation tends to
       | be handled in large JS frameworks such as Angular.
       | 
       | https://htmx.org/docs/#security
       | 
       | Alpine.js requires an alternative syntax to avoid running afoul
       | of unsafe-eval Content-Security Policy. With this more verbose
       | syntax, there no inline expressions in templates; everything is
       | bound to attributes in Alpine.data instead.
       | 
       | https://alpinejs.dev/advanced/csp
        
         | ketzu wrote:
         | > it's the opposite of how sanitation tends to be handled in
         | large JS frameworks such as Angular.
         | 
         | But they still do server side input validation, right?
         | Otherwise, _that_ would be a security concern.
        
       | btown wrote:
       | An alternative that requires even less server-side work is to use
       | PJAX https://www.npmjs.com/package/pjax which is the spiritual
       | successor to Turbolinks from the early Rails days. It's really a
       | two-step process:
       | 
       | - create a quick JS file that loads and configures PJAX to
       | automatically intercept links and - wherever you would have
       | $(function() {}) ensure that it's also triggered on the PJAX load
       | event, and is idempotent (e.g. check if you initialized a
       | component before initializing it again)
       | 
       | Then you just render pages server-side like it's 2000, without
       | any pjax-specific code needed in your templates themselves.
       | 
       | If you're building a data-focused product either solo or with a
       | small team, it allows you to focus on your Python code, and
       | anything frontend is as easy as accessing the variable in a
       | Django template. Of course, it's a massive accumulation of
       | technical debt - when you're successful you'll need to rewrite in
       | a modern framework for maintainability and agility. But when you
       | need to "punch above your weight class" and just get a product
       | out into the world, it can be an amazing technique.
        
         | hermes8329 wrote:
         | Since when is Django not a modern framework?
        
           | acdha wrote:
           | I read that as a modern JavaScript framework. I think there's
           | definitely a good debate about what "modern" means in that
           | case because I think it's less about "modern" and more along
           | the lines of "suitable for a large team working on complex
           | client-side functionality". Reaching for that prematurely can
           | add a massive toolchain to your critical path, which adds a
           | lot of frictional cost you might not see sufficient benefit
           | from.
           | 
           | One of the challenges we have is that people tend to hear
           | about practices from very large tech companies because they
           | have enough people to have things like developer evangelists
           | and time to write lengthy blog series or produce videos. That
           | often leaves people without the nuance that some of the
           | tradeoffs make more sense when you have 50 developers
           | including a dedicated support group but smaller teams might
           | not make back the cost of entry. I like posts like this for
           | reminding people that there are other options which might be
           | appropriate for different projects, especially since even at
           | large organizations it's usually easy to find small projects.
        
             | hermes8329 wrote:
             | I figured they meant js frameworks. This is definitely my
             | slanted point of view but I rarely consider anything
             | JavaScript modern. Django 4 seems much more so
        
         | recursivedoubts wrote:
         | pjax (first released 8 years ago) preceeded turbolinks (6 years
         | old), and was the inspiration for it
         | 
         | htmx is an attempt to drive HTML forward as a hypermedia, so it
         | exposes explicit, client-side attributes, rather than hiding
         | them as with pjax/turbolinks, although there is an attribute,
         | hx-boost, that acts similar to them both
         | 
         | worth noting that intercooler.js, which was the predecessor for
         | htmx, is 8 years old as well
        
       | joelbluminator wrote:
       | I like how many frameworks end up cloning what Rails is doing
       | (Stimulus / Turbolinks etc).
        
       | cosmotic wrote:
       | What makes it 'modern'?
        
       | joseferben wrote:
       | I wrote about my experience evaluating the same stack here:
       | https://www.joseferben.com/posts/hoarddit_a_website_to_disco...
        
       | miki_tyler wrote:
       | This is a very promising architecture! We are actually building a
       | template for Kit55 (http://stack55.com) that illustrates the use
       | of Alpine,js. I think we should look into HTMX as well. Do you
       | know if there is a comparison of Alpine.js vs HTMX somewhere?
        
         | czue wrote:
         | I'm not sure! As I say in the article, I kind of think of HTMX
         | as "alpine for AJAX"
        
         | recursivedoubts wrote:
         | From a sibling comment:
         | 
         |  _htmx is for syncing client side actions with the server
         | effectively within the hypermedia model
         | 
         | AlpineJS (and hyperscript) are better for purely front end
         | needs.
         | 
         | htmx and Alpine pair well together, as does htmx/jQuery,
         | htmx/VanillaJS or, if you are brave, htmx/hyperscript _
        
       | awinter-py wrote:
       | 'django saas startup kit' concept of the author is really smart
       | 
       | there's a hole in the market for people wanting to use frameworks
       | to make saas sites -- frameworks provide great primitives that
       | are subtly unusable for some modern web apps. Login but not saml,
       | admin but not multitenant, forms but not multiple forms on a page
       | 
       | feels like this scratches an increasingly common itch of 'the web
       | as a platform isn't shaped like what people use the web for'
        
       | jpe90 wrote:
       | Any opinions on how this (or a PETAL stack) compares to using
       | Clojure & Clojurescript?
        
       | Mizza wrote:
       | I've been moving from Django to Elixir/Phoenix/LiveView and
       | loving it so far. I hated the Angular/React era of the web and
       | mostly moved to doing backend development, but the Live App era
       | has reinvigorated my interest in web development as a whole. I'll
       | miss Python a lot and hope they can come up with something that
       | solves the concurrency issues, but Elixir is really pretty good
       | in its own right.
        
         | SoylentOrange wrote:
         | Can you explain what you mean by "Live App" era vs React era?
         | Can you point towards resources which might disambiguate the
         | two?
        
           | dgb23 wrote:
           | The term "era" in this context has to be interpreted as a
           | personal perspective to not be confusing. The mentioned
           | paradigm is not new nor does it replace/evolve from React and
           | similar.
        
           | Mizza wrote:
           | Sure! Basically, the idea is that rather than requests in
           | JavaScript going through an API, each user connection is
           | maintained by a lightweight process on the server (which
           | Elixir can scale easily), and then interactions with the page
           | are pushed as a diff via WebSockets and then magically merged
           | into the DOM. Interactive pages, no JavaScript required. I'm
           | still pretty new to it, but after learning the ropes it's
           | seeming very productive, and most importantly, fun.
           | 
           | https://dockyard.com/blog/2018/12/12/phoenix-liveview-
           | intera...
        
             | adamddev1 wrote:
             | So then this can never work offline like a single page
             | React PWA could then I guess? For me after seeing offline-
             | first PWAs it's hard to want to go back to building stuff
             | that's only available online, but I guess everyone's use-
             | case is different.
        
               | BoumTAC wrote:
               | what is your use case of offline ? I've never seen the
               | point. For example what the purpose of a social offline
               | app ? I can't refresh feed, I can't upload post or react
               | to any thing in my feed.
               | 
               | The only use case I know is for map where you can
               | download map so when you don't have 4G you will not be
               | lost but that's the only use case I know.
        
               | recursive wrote:
               | Working on stuff, not communicating. e.g. Google docs,
               | Photopea.
        
               | pjerem wrote:
               | Not saying offline-first apps have no interest, they
               | totally can have some.
               | 
               | But in more than ten years, offline mode have never been
               | a requirement on any of the projects I worked on.
               | 
               | What I'm saying is that offline mode is just a feature
               | like any other and it's one with a huge cost in
               | architecture complexity.
               | 
               | And, although it's just my own opinion, I think if you
               | want to be offline first, odds are that better stacks
               | than the web exists for those needs.
        
             | drbw wrote:
             | So pretty much the Blazor Server approach in the Dot Net
             | world then?
        
               | shijie wrote:
               | Yes, basically. Fun fact: Blazor and LiveView were
               | developed independently, around the same time as each
               | other! Just two similar implementations in disparate
               | communities.
        
               | pantulis wrote:
               | Guess that was due to browser-land innovations that made
               | this a possibility.
        
               | culturedsystems wrote:
               | It's also not unlike JSF in the Java world, which went
               | out of fashion 10 or so years ago, and for good reason:
               | relying on a framework to paper over the distinction
               | between client and server side turned out to be much more
               | complicated and fragile than a cleanly defined
               | separation. I haven't seen any authors or users of these
               | recently developed server-side-first frameworks discuss
               | this prior art, but I'd be interested to see if they've
               | come up with a way around what seemed like a fundamental
               | problem in the approach.
        
               | keewee7 wrote:
               | Blazor Server and Blazor WebAssembly needs to be marketed
               | separately. Most people have heard about Blazor
               | WebAssembly but are unaware that LiveView-style web
               | development is possible in the .Net world using Blazor
               | Server.
        
               | SketchySeaBeast wrote:
               | Yes, yes they do. I don't know why you'd name pretty much
               | the exact opposite techs the exact same thing.
        
               | jmnicolas wrote:
               | I don't use Blazor, however when I went to get basic info
               | about it every article I have read were very clear that
               | there's 2 ways to dev a Blazor app.
        
           | trymas wrote:
           | OP probably talking about Phoenix's "LiveView"
           | (https://www.phoenixframework.org/ check the video about it).
           | 
           | Phoenix LiveView is a framework where it keeps websocket open
           | with the client and renders DOM changes server side and
           | passes it to the client [0]. Thus with fully server side
           | development without any JS you can have almost full SPA
           | experience.
           | 
           | [0] Have no experience with it, and only read about it some
           | time ago, so don't judge me on the details, but the gist of
           | the "LiveView" idea should be like that.
        
             | beardedetim wrote:
             | But you still need JS to update the DOM and handle the
             | websocket stuff, right? Or is this all somehow done with JS
             | disabled?
        
               | dgb23 wrote:
               | Right. It uses JS but you don't write any. Or very
               | little. Or in a custom DSL/framework.
        
               | hunterb123 wrote:
               | Important distinction, as it wouldn't work when JS is
               | disabled in browsers.
               | 
               | I don't see the point of going back to full server side,
               | you have to scale more with more users.
               | 
               | The only benefit would be if it all worked without
               | running JS in browsers, but it doesn't.
        
               | BoumTAC wrote:
               | Don't you have to scale your api too ?
        
               | hunterb123 wrote:
               | Yes, but now you have to scale both the data layer logic
               | and view layer logic when doing server side rendering.
        
               | BoumTAC wrote:
               | So now it's two times the hassle, two times the money
               | spent
        
               | porker wrote:
               | 99% of the time no one runs into scaling issues and
               | worrying about it is premature optimisation. I have to
               | remind myself that all the time.
               | 
               | And no, same hassle, same money spent. Thought about from
               | the start server-side rendered pages are almost as
               | cacheable as API responses will be. If you can't cache
               | you're in for a world of expense at scale whichever way
               | you go.
        
               | beardedetim wrote:
               | I have (limited) experience scaling long-lived websocket
               | connections and it _sucked_. It is _way_ easier to scale
               | out little Node servers that are "stateless" than it is
               | to ensure that Client A is connected to Socket A.
               | 
               | I would much rather scale out my REST/Graph/RPC API
               | instead of having to scale out a WS API.
        
               | dqv wrote:
               | > as it wouldn't work when JS is disabled in browsers.
               | 
               | You can make it work when JS is disabled as well, you
               | fall back to rendering regular HTML. It does require a
               | little extra work, but it's not insurmountable (e.g.
               | using @conn instead of @socket).
               | 
               | >you have to scale more with more users
               | 
               | I might opt for additional optimizations once it gets
               | bigger, but I'm not too worried about scaling Erlang
               | processes.
        
               | beardedetim wrote:
               | Yup, this is my thinking as well. If I go back to fully
               | server side, it's because I can somehow instruct the
               | browser to update without JS involved.
        
               | [deleted]
        
               | sodapopcan wrote:
               | It's done with JS but that's all written for you. But as
               | a bonus, LiveView apps do work without JS (they just
               | aren't updated over web sockets anymore).
        
               | bcrosby95 wrote:
               | I assume you have to specifically design your site to
               | work with both the request/response model and the
               | LiveView model in order for this to actually work, as
               | opposed to LiveView being able to plug that hole
               | automatically for you.
        
               | sodapopcan wrote:
               | To be a little more concrete, here's an example:
               | <%= live_patch "about", to: Routes.about_path(@socket,
               | :index) %>
               | 
               | which creates:                 <a href="/about" data-phx-
               | link="patch" data-phx-link-state="push">about</a>
               | 
               | The data attributes are read by the LiveView HTML and are
               | otherwise ignored by a JSless broswer.
               | 
               | Edited to fix glaring code sample error.
        
               | sodapopcan wrote:
               | Nope, all you need to do is make sure that everything has
               | a route (which is very much encouraged in LiveView) and
               | it works.
        
               | dqv wrote:
               | You can design singularly for LiveView and it handles
               | everything. But if you want both request/response and
               | LiveView (e.g. to mix the two or fallback to r/r when no
               | js) you have to be more explicit in your design. It's
               | mostly trivial though. I have authentication pages that
               | use the old controllers but pages that use only LiveView
               | without any hassle.
        
         | emodendroket wrote:
         | I haven't done frontend work for a few years, but Angular was
         | really a revelation to me when it first came out. For all the
         | headaches, it made it practical to do stuff that was really
         | cool.
        
         | [deleted]
        
         | simonw wrote:
         | There's a thriving ecosystem these days around the ASGI
         | standard for building concurrent web applications in Python -
         | it came out of the Django project originally but Starlette and
         | FastAPI are the most widely used implementations of it.
        
           | Starlevel001 wrote:
           | ASGI is a bad solution to the concurrency issues as the
           | ecosystem is heavily centralised around asyncio (which is
           | ``java.lang.Thread`` for async/await, with all the pitfalls
           | included).
        
         | [deleted]
        
         | koyote wrote:
         | Having recently looked into Blazor Server (similar to LiveView
         | but in C#), one of the cons Microsoft listed was the
         | scalability (compared to a typical SPA) as each client now
         | needs an active websocket connection to the server, which will
         | require more server resources.
         | 
         | Do you have any experience in that? I'd love to know where
         | server resource requirements sit between SPA, this and a
         | typical SSR site like Django.
        
       | amenod wrote:
       | I agree that the way modern JS (need to?) download half the
       | Internet for a semi-useful app is annoying, wasteful and
       | dangerous.
       | 
       | However, I still remember the hell that was updating the state
       | and keeping the rendering in sync with it when using jQuery.
       | Native JS of course doesn't improve on that, and (judging by the
       | description - no experience with it) Alpine.js doesn't either.
       | For me, the paradigm of rendering from the internal state is what
       | makes React (and Vue,...) useful. Too bad that npm ecosystem
       | sucks and that everyone is inventing new shiny useless new things
       | all the time... But React makes non-trivial single-page apps
       | possible.
       | 
       | Of course, if you need server-side rendering (for example because
       | of SEO) then the equation changes, and maybe using Alpine.js
       | makes sense.
        
         | acdha wrote:
         | > However, I still remember the hell that was updating the
         | state and keeping the rendering in sync with it when using
         | jQuery. Native JS of course doesn't improve on that
         | 
         | I think this varied a lot depending on how teams approached it
         | and that a lot of the appeal to something like React, Vue, etc.
         | was simply that there was one way to do it.
         | 
         | The approach I've been quite happy with is to use JavaScript
         | classes (IE11 is less than 1% of global web usage) for internal
         | state, where you follow standard practice for having ownership
         | and updates between different parts of your app, and the HTML5
         | data APIs for the public elements which are managed by
         | different codebases. Web Components has something like 95-97%
         | availability these days but this can be as simple as using
         | element.dataset.whatever as needed. React is definitely good
         | for huge apps but a significant fraction of the web sites I use
         | are solidly in the level of functionality which in 2021 doesn't
         | need functionality outside of what a modern browser provides.
        
         | stepbeek wrote:
         | That internal state is a burden on small teams though - you're
         | efectively implementing the persistence layer twice. I'm
         | totally onboard for SPAs as an option when breaking down an
         | organization, or for solving a particular kind of problem.
         | 
         | But they're just not worth the effort for a form-oriented
         | website with a small-medium team behind it. Almost everything
         | about a web-app is harder with an SPA.
        
         | grayrest wrote:
         | Keeping all state server side is a completely reasonable
         | approach. The 37Signals guys have been advocating for it since
         | 2006 or so and as long as you have a low latency connection to
         | the server then it usually works great.
         | 
         | What doesn't work well (and what tended to happen with jQuery
         | apps) is having state both on the client and on the server and
         | having to coordinate between the two. My personal preference is
         | for client side state with a lighter setup than React (i.e.
         | Svelte). I like the predictable latency and I feel you don't
         | run into a complexity barrier (e.g. multi-step forms) as the
         | app grows.
        
         | deergomoo wrote:
         | > Alpine.js doesn't either
         | 
         | While it won't fit the needs of a complex app with dozens of
         | components, it does drive the UI from the state. In fact, it
         | uses Vue's reactivity engine.
        
         | smolder wrote:
         | I was very good at making reliable apps and managing states
         | manually in the jquery days. Having a scaffolding helps overall
         | and in many ways, but now in the dense jungle that is the JS
         | "ecosystem", there is sometimes a productivity loss searching
         | for "the right way to do X in framework Y" or troubleshooting
         | underlying tools instead of just writing the code to do the
         | thing. Easier, maybe, but not at all satisfying.
        
           | scaryclam wrote:
           | I think the trick is, that state needs to be carefully
           | considered at an overall systems level, not just client vs
           | server. That's quite hard, so many (most?) devs don't do it.
           | Certainly, I've seen state managed well using jquery, and
           | even vanilla JS in the ES5 era, so frameworks don't make it
           | possible, it's always been so.
           | 
           | So the question is, do frameworks make it easier? I don't
           | think they really do. I think they make it easier to
           | manipulate state, but not designing your system will still
           | mean state being mismanaged.
        
       | gavinray wrote:
       | Can someone genuinely explain to the the desire/interest to use
       | HTMX/Hotwire/LiveView etc?
       | 
       | I was writing web apps when rendering templated HTML views on
       | your server was standard, and you had controller endpoints that
       | returned HTML content, or things like Rails "Unobtrusive
       | Javascript" where you had code like:                 $('#user-
       | list').html("<%= j render('index', users: @users) %>")
       | 
       | As an automatic callback to some action.
       | 
       | Whether or not you love or hate this model of development is
       | irrelevant, because if at some point you need to render on a
       | client other than a browser -- you have to start from the
       | beginning and write an API now.
       | 
       | IE, so that your Android/iOS app in Java/Swift or whatnot, can
       | ask your backend for data and render it using the tools available
       | on that platform.
       | 
       | When we turned apps into pure API's and just exchanged data with
       | them, it opened up the ability to be platform-agnostic.
       | 
       | I guess I don't understand why someone would choose to build an
       | app that sends HTML over the wire instead of JSON/XML/whatever,
       | that any client can render. All it means is that you have to
       | write this functionality later when you want it, in addition to
       | now having this HTML stuff.
        
         | roywiggins wrote:
         | If you already have an app with no AJAX going on, HTMX is
         | _hugely_ helpful in progressively bringing it in. You just
         | provide endpoints for the forms or other pieces of pages that
         | need updating, and wire them up to the page with the right HTMX
         | tags.
         | 
         | Even starting from scratch, it can be very productive to keep
         | all your HTML in one place- eg Django templates- and use HTMX
         | and a sprinkling of JS to provide client-side interaction. You
         | can jump straight into laying your app out without building the
         | whole thing up as platform-agnostic APIs first. When you need
         | API endpoints you can start adding them based on the context
         | objects you're providing your Django templates, since all the
         | information is in there anyway. There's _real_ benefits to
         | putting all your presentation and _most_ of the logic on the
         | server.
         | 
         | And keep in mind that many web apps will _never ever_ need to
         | also be a native app.
        
         | acdha wrote:
         | First, many sites do not need a mobile app -- people who sell
         | apps like to present that as a requirement but there large
         | categories where it doesn't make sense and most users won't
         | install it because it takes space on their device and they
         | [correctly] fear ads, notification spam, and possible invasions
         | of their privacy. I've seen figures for this where pretty well-
         | known organizations spent millions on the app and then saw
         | install rates under 10% with most users opening it only once or
         | twice.
         | 
         | Second, this is something of a false dichotomy: if you have a
         | website, you need to have HTML somewhere. One approach is to
         | use an SPA but that increases the cost somewhat significantly
         | and absent a significant engineering effort will reduce
         | performance and reliability because you are moving
         | functionality out of a high-performance data center where you
         | control everything onto the users' devices where you have to
         | work with whatever browser and extensions/ad blockers they have
         | installed.
         | 
         | An alternative approach is to render HTML on your servers --
         | quite possibly using the same JSON API as the source -- and
         | then progressively enhance it with the functionality which
         | makes sense to do on the edge. This gives you a hefty
         | performance win for the initial page-load times, helps with
         | things like search engines, and ensures that your users get at
         | least the basic experience when something goes wrong with
         | client side JavaScript (network errors, browser compatibility
         | issues, ad blockers, etc.) rather than nothing working at all.
        
           | tata71 wrote:
           | Can you name one, that the group would know, that wouldn't be
           | improved by a convergent phone or tablet offering?
        
             | acdha wrote:
             | When was the last time you used an application from a
             | gallery, archive, museum or library? How many people use
             | https://apps.apple.com/us/app/wikipedia/id324715238 instead
             | of visiting wikipedia.org? I'm not naming names but this
             | came up a number of times at meetings I was involved with
             | in the GLAM community where people mentioned having spent
             | considerable amounts of money on apps, even winning design
             | awards or getting featured in the Apple AppStore, and then
             | seeing that their daily active users never came within 4
             | orders of magnitude of their web traffic.
             | 
             | What they generally had in common is that they're content-
             | heavy (i.e. solidly in what the web was designed for),
             | might not require authentication, and most importantly
             | aren't something most of the users wanted to use all of the
             | time. If you are trying to get the hours for a tourist
             | destination or even a restaurant, look at public
             | information, etc. the time needed to login to the app
             | store, authenticate to approve the purchase, wait for a
             | large file to download, open the app and complete any
             | mandatory enrollment, wait for it to retrieve content, etc.
             | was often orders of magnitude slower than using the
             | website. Restaurants and bars are a great example of this:
             | if it's your hangout and they have something like
             | integrated ordering, maybe a trivia night or something like
             | that, the app can be useful. For most people, however, a
             | webpage with the contact info and a menu with
             | Apple/Google/Stripe buttons to pay is going to be better
             | than an app they use a couple of times a year.
             | 
             | The other key thing to understand is that this is a
             | question of priorities and budgets. It wasn't that there is
             | no possibility of doing anything useful for these
             | organizations in a mobile app but rather than the cost
             | wasn't worthwhile for the incremental benefit to the users,
             | especially when you considered the opportunity cost of not
             | spending that much money on something else, especially
             | since most of the cool things you could do in an app could
             | also be done on the web with very similar quality but with
             | the difference that you only had to build one version
             | rather than 2+ and the web version required much less
             | ongoing maintenance.
        
             | dec0dedab0de wrote:
             | Hn would be worse as an app, but more notably Twitter, and
             | reddit would be better as pure web pages if they didn't
             | purposely cripple them to funnel people into the app.
        
               | scns wrote:
               | Well, i usually read HN on my mobile with Materialistic.
               | It is one of the apps i use the most often.
        
               | hunterb123 wrote:
               | Same, it works offline, loads faster with bad mobile
               | connection, better gestures & UX overall.
        
           | systemvoltage wrote:
           | I am open to HTMX. Seems refreshing but I am a little
           | confused about how to structure the backend API returning
           | small bits of HTML? Wouldn't that be a colossal nightmare to
           | reason about?
           | 
           | I can think over time I'll have endpoints like this:
           | POST https://foo.com/bar-section/baz-button
           | 
           | No? Haven't quite thought about it deeply but I can imagine
           | logic mixed with UI bits in the backend.
        
             | recursivedoubts wrote:
             | Not really, as long as you keep your HTML-driven
             | interactions from becoming too fine grained.
             | 
             | For example, if you have a search page that provides
             | management of contacts + active search & click to load
             | functionality, it might look like this:                 GET
             | /contacts - get a list of contacts + search & click-to-load
             | functionality       POST /contacts - create new       GET
             | /contacts/:id - get the details for the contact       PATCH
             | /contacts/:id - update the contact       PUT
             | /contacts/:id/archived - archive the contact       DELETE
             | /contacts/:id - remove the contact
             | 
             | All pretty reasonable and all can reuse the same few
             | templates and sub-templates for rendering responses.
        
             | acdha wrote:
             | I think you can get pretty far by having good conventions
             | and not over-thinking it, but remember also that this is
             | all about being pragmatic instead of taking a one-size-
             | fits-all approach -- if you found yourself doing a _ton_ of
             | highly-granular requests, that might be a clue that you're
             | not in the sweet spot and an API client might be a better
             | fit.
        
             | deniz-a wrote:
             | > API returning [...] HTML
             | 
             | The endpoints that return endpoints are not API endpoints,
             | they are UI endpoints like `/index.html` or `/login` or
             | `/Results.aspx?id=3984272`. Now you can have `/login/email`
             | or `/login/google` and switch between them like
             | <https://htmx.org/examples/tabs-hateoas/>.
             | 
             | As for the machine-consumed API, you have quite a few
             | options. e.g.: The server that serves these resources may
             | serve JSON to the same URLs through content negotiation, or
             | the API may be separate, or you can have a generic API that
             | is consumed by mobile app, desktop app and HTML-producing
             | server (as opposed to JS app delivered by static file
             | server or framework SSR).
             | 
             | The UI runs on the server, using REST to change client
             | state over a stateless protocol similarly to how a React
             | app may use Redux.
        
             | jspash wrote:
             | Have a look at how Phoenix(Elixir) does it with LiveView.
             | You simply write everything as a server rendered view and
             | the framework pulls things apart and sends just what
             | changed over a web socket. Its mind blowing how fast it is
             | (can be. Latency is real)
             | 
             | I have no doubt that this style of front-end management is
             | going to be a game changer in the next few years. Of course
             | full-on SPA frameworks will still have their place. But if
             | you aren't writing the next Google Maps clone, maybe you
             | don't need all that. It's made me love web dev again after
             | hating the complexity explosion of recent years.
             | 
             | https://m.youtube.com/watch?v=8xJzHq8ru0M
        
           | 0des wrote:
           | > First, many sites do not need a mobile app -- people who
           | sell apps like to present that as a requirement
           | 
           | Yes, Testify! Also, I'd like to mention, so many of these
           | upsold apps end up being a wrapper around the normal web
           | view. I've seen this being advertised/proposed as a plus, as
           | well "No need for your customers to learn a new interface, we
           | specifically engineer your app experience to be _just_ like
           | the web experience ". It's interesting to see heads nodding
           | in reply to this.
        
             | acdha wrote:
             | Oh, yes -- definitely saw those. My favorite were the ones
             | in the pre-WKWebView era where the app was basically the
             | website, except slower because it didn't have the
             | JavaScript JIT enabled.
        
         | Mikeb85 wrote:
         | Honestly because sometimes it's all you need.
         | 
         | Take Rails Hotwire for example. It's easy to write, easy to add
         | JS when you need it, easy to make mobile apps since they've
         | already done the work. It's live on Basecamp and Hey.com apps,
         | it works very nicely. Hey is easily the snappiest email client
         | I've ever used.
        
         | javajosh wrote:
         | This is a specific example of a class of problems I refer to as
         | "Where the indirection go?" In this case, the indirection is in
         | the form of a function that takes structured data and produces
         | html. That function can execute in the server, or on the
         | client. Which we can term moving a function "closer" or
         | "further" from the client. This is easier to imagine with
         | isomorphic javascript code, but it applies to anything (with an
         | extra translation step as you cross the network boundary).
         | 
         | What you've discovered is a general property of systems that
         | you want to keep your entropy low for as long as possible, and
         | defer the final boost in entropy until the last possible
         | minute. This keeps your options open. It also means publishing
         | low entropy APIs and boosting in the client. In your case,
         | you've correctly noted that it allows you to support different
         | clients more easily.
         | 
         | There are 3 reasons to pay the price to boost entropy on the
         | server: to intentionally make it harder to consume your API, to
         | protect a proprietary boosting function, and because you didn't
         | realize it was bad design.
        
         | kirse wrote:
         | Lots of reasons:
         | 
         | 1) No need for 3.7GB of node_modules to crank out a simple site
         | 
         | 2) Single solution, easier to bring on junior developers and
         | reason about application logic
         | 
         | 3) Caching much easier, too many people think they need real-
         | time push when NRT-polling + caching is far easier and more
         | performant
         | 
         | Broadly speaking it's often a case of YAGNI. The JS ecosystem
         | really does still suck for its complexity, I remember that
         | every time I ramp up a new developer onto a React project. It's
         | smoothed out with tooling but the litany of JSON configuration
         | files and the mess created by hot-reload + proxying +
         | microservices etc etc. Often just YAGNI.
         | 
         | People today don't remember the VB6 IDE days where you could
         | slap a button on a Form, write a line of code for a MessageBox,
         | and smash that play button with zero effort. JS development is
         | often about working your way through a tangled spider-web of
         | helper utilities and config files and JS modules at which point
         | when it finally works you're afraid to rev anything.
        
           | recursivedoubts wrote:
           | bang on, especially that last part
           | 
           | a bit focus of htmx, alpinejs (and htmx's sister project,
           | https://hyperscript.org) is putting the logic _on the
           | element_ , so you can see exactly what a button, etc. does
           | just by looking at it, and without trawling through ten files
           | of indirection
           | 
           | i am trying to popularize the term Locality of Behavior to
           | describe this design goal:
           | 
           | https://htmx.org/essays/locality-of-behaviour/
        
             | lhorie wrote:
             | I'm curious about your thoughts on that locality of
             | behavior idea vs aspects of precision and composability.
             | For example, the argument goes that the behavior of `hx-
             | get` is obvious upon inspection, but the terseness is
             | achieved by omitting the event type (i.e. it's
             | assumed/implied that hx-get runs on click). The
             | quintessential widget where that breaks down is the table
             | w/ checkboxes for batch operations over an arbitrary subset
             | of rows. That's where less DSL-ish frameworks' abstraction
             | via state management tend to shine, since they allow the
             | developer to more precisely specify how disparate
             | checkboxes relate to a bigger picture that may also involve
             | table sorting (both client and server varieties) or nested
             | modal structures or other forms of complexity.
        
         | dagw wrote:
         | _you have to start from the beginning and write an API now._
         | 
         | Is it really that much more work? Much of the time the big
         | difference is just be replacing                  return
         | render(my_template, my_data)
         | 
         | with                  return to_json(my_data)
        
           | acdha wrote:
           | A few years back, I implemented this as a Django CBV which
           | worked quite well:
           | 
           | https://github.com/LibraryOfCongress/concordia/blob/main/con.
           | ..
           | 
           | That handles a few things like pagination for list views,
           | calling get_absolute_url() on objects in the template context
           | which have that method defined, and running all URLs through
           | request.build_absolute_uri().
        
         | recursivedoubts wrote:
         | Because of the simplicity, flexibility and power of the
         | hypermedia programming model.
         | 
         | - simplicity: e.g. something like active search can be
         | implemented with a few attributes:
         | https://htmx.org/examples/active-search/
         | 
         | - flexibility: e.g. because of the uniform interface,
         | versioning is much less of an issue
         | 
         | - power: e.g. deep linking is trivial
         | 
         | Additionally, there is increasing awareness[1] that Application
         | APIs and Data APIs have different needs and "shapes", and, once
         | you have split them up, reconsidering using hypermedia for your
         | application API[2] is a reasonable thing to do
         | 
         | [1] - https://max.engineer/server-informed-ui
         | 
         | [2] -https://htmx.org/essays/splitting-your-apis/
        
         | lhorie wrote:
         | Worth pointing out that HTML is more ubiquitous than you're
         | making it out to be: just plop a WebView in your native app,
         | and you're done. I know, for example, that the Uber app does
         | webviews in some places; you probably wouldn't even be able to
         | figure out where just from looking at it as a user.
         | 
         | Another case in point: is your dev team going to support PSP
         | devices[0]?
         | 
         | [0] https://shkspr.mobi/blog/2021/01/the-unreasonable-
         | effectiven...
        
         | [deleted]
        
         | sodapopcan wrote:
         | > because if at some point you need to render on a client other
         | than a browser -- you have to start from the beginning and
         | write an API now.
         | 
         | The answer lies in the "if" there. The speed and lack of
         | complexity developing server-side with no API is unparalleled
         | to doing client -> api -> backend. Not to mention, you aren't
         | tying yourself into several different JS technologies (Which
         | GraphQL or REST lib? Which view framework? What testing
         | frameworks? And what's the whole backend stack? etc. etc.) I
         | can only speak for LiveView but the whole top-down experience
         | is in Elixir with sprinkles of vanilla JS (the community is big
         | into Tailwind and AlpineJS as well, but not exclusively).
         | 
         | I have real world experience of dev'ing API-first only to have
         | the company nix any plans to open up the API. Adding new
         | features is always a slog as we have to think about if the
         | business logic needs to be on the client, the server, or
         | both... not to mentioning have to update about 18 different
         | places the name of a new field you're adding.
         | 
         | The company I work for actual has a LiveView widget that is
         | embedded on their client's apps. I can't speak very well to it
         | since I only just started working there and don't actually
         | start until next week, haha.
         | 
         | But ya, I'll also echo the whole idea that a lot of companies
         | don't need mobile apps. I'm certainly one of those people who
         | uses the browser on my phone whenever I can.
        
         | joelbluminator wrote:
         | > Whether or not you love or hate this model of development is
         | irrelevant, because if at some point you need to render on a
         | client other than a browser -- you have to start from the
         | beginning and write an API now.
         | 
         | That's not true generally since many mobile apps are simply
         | wrappers around a WebView. Rails Turbolinks basically has
         | mobile shims that allows you to deploy to all platforms. Sure,
         | if you can't use a Web View on your mobile app (idk, for
         | performance reasons) that's something else. But that's not the
         | rule.
        
         | interactivecode wrote:
         | because you still want server rendered html? because you focus
         | on building websites?
         | 
         | Being platform specific makes it easier to have a higher
         | quality and integration on that specific platform.
        
           | gavinray wrote:
           | I build exclusively web apps and I still use the backend as
           | an API.
           | 
           | You fetch data from the API and render it with JavaScript.
           | 
           | React, Vue, Svelte, Angular, Alpine, pick whatever.
           | 
           | Not sending HTML over server endpoints, or using templated
           | views like ERB/EJS/EEX/etc doesn't mean you inherently have a
           | worse quality app.
           | 
           | If you do this in something like Next.js with
           | "getServerSideProps()", it's functionally equivalent.
           | 
           | React even went so far as to make "Server Components":
           | 
           | https://reactjs.org/blog/2020/12/21/data-fetching-with-
           | react...
        
             | senko wrote:
             | You build web _apps_. The parent talks about web _sites_.
             | 
             | Not everything on the web is a full featured interactive
             | application, this is exactly what they're talking about.
        
             | sodapopcan wrote:
             | I feel like I gotta call out the LiveView is a bit in a
             | class of its own. HEEx is rendered on the server, but the
             | diff sent over the wire is the absolute minimal diff it can
             | be with a map of where it in the DOM. Often this is just
             | text. LiveView also gives you a running process on the
             | server (a virtual machine process, not a linux process)
             | that holds the user's state (like if they're logged in, for
             | example) and makes things like "who's online?" and other
             | concurrent features almost trivial.
        
             | roywiggins wrote:
             | If you render everything with JavaScript then HTMX is not
             | really going to be useful at all. It's useful for
             | developing apps that simply don't need the sort of complex
             | client-side interaction that those frameworks enable. The
             | article points this out- if you want to write a SPA in
             | React, HTMX is not going to help at all. But if you want a
             | mostly-server-rendered page with some AJAXy interactivity,
             | HTMX is _much much easier_ than trying to shoehorn in
             | _some_ client-side rendering just for the AJAXy bits.
             | 
             | The main thing is is that there is still a substantial
             | demand for tools that let you mostly avoid writing lots of
             | JavaScript, whether on the server or the client.
        
               | gavinray wrote:
               | This is a super valid answer, thanks.
               | 
               | Psychological bubble from the sorts of apps I build I
               | suppose, I hadn't considered:                 > It's
               | useful for developing apps that simply don't need the
               | sort of complex client-side interaction that those
               | frameworks enable.
        
             | [deleted]
        
         | hedgehog wrote:
         | I've used Intercooler.js (the predecessor to HTMX) a bit on top
         | of Django and small Go apps (no framework). If you don't need a
         | lot of complex state and interactivity on the front end it can
         | work well. This approach avoids the complexity of having two
         | codebases, you can get the performance/usability benefits of
         | partial page updates while keeping 99% of the codebase in one
         | language.
        
         | czue wrote:
         | The need for a native mobile app (or any kind of platform-
         | agnostic behavior) probably negates much of the value of these
         | stacks.
         | 
         | That said, many projects don't have or need mobile apps, and
         | many more can probably get away with a web-first mobile app.
         | 
         | For those apps this stack can vastly simplify and streamline
         | development
        
           | gavinray wrote:
           | > That said, many projects don't have or need mobile apps,
           | and many more can probably get away with a web-first mobile
           | app.
           | 
           | To me this is like building a house that can never be
           | expanded, instead of starting with an open-ended design.
           | > For those apps this stack can vastly simplify and
           | streamline development
           | 
           | I guess this is an opinion/subjective?
           | 
           | I am very open-minded and experimental. I love trying new
           | things.
           | 
           | I've tried these technologies (HTMX, it's precursor
           | Intercooler.js, Turbolinks + Hotwire, LiveView, etc) and for
           | me they are less productive than the ways I know how to build
           | API-first, JavaScript web apps.
           | 
           | Have nothing against them, just genuinely having a hard time
           | seeing the appeal.
        
             | nauticacom wrote:
             | I've tried these technologies ... and for me they are less
             | productive than the ways I know how to build API-first,
             | JavaScript web apps
             | 
             | I think I feel the same way you do, except the other way
             | around. I genuinely can't understand how you build apps
             | productively with a separate client/server model.
             | 
             | How do you do form validations? How about authentication
             | and authorization? What about a consistent domain model? Is
             | there one copy of it on the server and one on the client?
             | Or does your client just treat everything as dumb data and
             | make network requests for every question of business logic?
             | What about data consistency throughout the interface--when
             | you update e.g. Document(id=45) with new data, how does
             | that update get propagated to every other place in the app?
             | Does that involve a client-side identity-map? Or are you
             | manually trying to send updated data to other places with
             | callbacks/whatever? etc. for ever and ever.
             | 
             | Every time I try to build an app where the frontend and
             | backend are split into a separate client and API, it ends
             | up adding _so_ many more considerations and _so_ much more
             | complexity than the traditional model. Mostly because now
             | everything that just required a database query or method
             | call before now _also_ requires a network request, but also
             | because data consistency in a long-running app is _so_ hard
             | to get right.
        
               | porker wrote:
               | > How do you do...
               | 
               | Those are all questions I have, as a 2-decade
               | "traditional web app" developer who is now doing frontend
               | work & hybrid mobile apps. I know the backend sucks for
               | some of them too, so this isn't a set of questions to
               | bash with.
               | 
               | They are the questions I'd spend money on a book or
               | learning materials to answer. They are philosophical
               | questions that seem overlooked.
               | 
               | I think the answer is JS/TS on server and client-side for
               | a lot of them, so models/classes/structs are shared; form
               | validation rules are shared (something let's face it that
               | "traditional" web apps suck massively at).
               | 
               | The one Q I feel qualified to answer is: > What about
               | data consistency throughout the interface--when you
               | update e.g. Document(id=45) with new data, how does that
               | update get propagated to every other place in the app?
               | Does that involve a client-side identity-map? Or are you
               | manually trying to send updated data to other places with
               | callbacks/whatever? etc. for ever and ever.
               | 
               | Assuming you're not talking realtime (because that's a
               | problem for both) then this is why the concept of data
               | stores (Redux, Vuex, Mobx to name a few) are so popular.
               | Because when the data is changed, and you're using a
               | reactive frontend framework, it updates all components
               | that use that data. It is, frankly, magical and
               | wonderful. But as you say, data consistency can be a
               | problem...
        
               | nawgz wrote:
               | Your questions are all... contrived?
               | 
               | > How do you do form validations?
               | 
               | How do YOU do form validations? Is it entirely on the
               | backend so it requires a round-trip before the user gets
               | feedback, and additionally requires you to wire both the
               | HTML endpoint for user feedback AND for rendering some
               | results?
               | 
               | For myself, I have a reusable Form component I can plug
               | in arbitrary tests. You can run the tests when the user
               | changes an input or on submit, with some
               | options/conditions for when you clear the feedback.
               | 
               | Then, of course, my API gives feedback as well; usually,
               | it's harder / more awkward to wire the API feedback to
               | highlight the offending Form fields, and I certainly
               | don't see how HTMX would accomplish this, so without some
               | machinery I already feel your side lacks QOL features
               | like "highlight error fields" and "autofocus first
               | offending entry".
               | 
               | > How about authentication and authorization
               | 
               | You are joking or what? There is no difference in how an
               | HTMX app would authenticate to its endpoints and how an
               | SPA would
               | 
               | Finally, you ask a bunch of questions that clearly aren't
               | any better in an API-endpoint-randomly-renders-HTML
               | paradigm...
               | 
               | > Is there one copy of it on the server and one on the
               | client
               | 
               | Obviously, but you load the client version from the
               | server at API request time... just like an HTMX powered
               | client... except an SPA keeps objects instead of a
               | rendered representation so you can do more in-depth
               | things without network trips...
               | 
               | > What about data consistency throughout the interface--
               | when you update e.g. Document(id=45) with new data, how
               | does that update get propagated to every other place in
               | the app?
               | 
               | Because you use singletons like a not-crazy person... how
               | does this happen in HTMX world where you have no data
               | representation on the front-end? Does your form have to
               | be manually wired to update every single present data
               | view that is holding that document? Seems like you're
               | worse off than me. I hold a stateful representation and
               | update the views when that representation changes,
               | automatically... Wow, literally no work required because
               | it's declarative
               | 
               | > Does that involve a client-side identity-map? Or are
               | you manually trying to send updated data to other places
               | with callbacks/whatever?
               | 
               | Laughable. the HTMX paradigm is clearly worse off here
               | 
               | > Every time I try to build an app where the frontend and
               | backend are split into a separate client and API, it ends
               | up adding so many more considerations and so much more
               | complexity than the traditional model
               | 
               | You clearly did not bother to understand how state &
               | views relate in an SPA then. Your complaints make no
               | sense either, this happens in HTMX world more than mine:
               | 
               | > now everything that just required a database query or
               | method call before now also requires a network request,
               | but also because data consistency in a long-running app
               | is so hard
               | 
               | I honestly can't tell if you're trolling me. Let me break
               | it down for you.
               | 
               | In client/server world, client asks APIs for the data.
               | Easy. Imagine a paradigm like GraphQL, the client
               | literally just loads the data. It's the same as it would
               | be on your server endpoint for HTMX, that's literally the
               | client in your world. I hold a global singleton
               | representation if my app is interconnected, or I load
               | different singleton representations for unrelated
               | subtrees if it's only partially interconnected.
               | 
               | Next, if "collaboration"/real-time features are
               | important, you make this data loading "aware" of when the
               | data changed server-side, and you refresh your data. Easy
               | as pie; you use the same function to reload. Lots of
               | options on how to update the data, but if you correctly
               | make your "load" function idempotent it is clear this is
               | trivial.
               | 
               | Finally, you write views that describe, declaratively,
               | how to render the data. Since application state
               | automatically re-renders these views, ideally not in
               | their entirety if you used a good state management,
               | you've already solved every single concern you listed
               | about "stale data" by how you wired your data loading.
               | 
               | So, great, in conclusion, HTMX endpoints are like a
               | scattered version of a client that makes all nice
               | "application" tricks virtually impossible, giving you no
               | gains in any fashion that relates to data consistency or
               | continuity, and requiring loads of manual wiring and
               | awkward data-HTML manipulation in places that have no
               | business doing it.
        
               | nauticacom wrote:
               | How do YOU do form validations?
               | 
               | I use some server-side library to do it (take your pick
               | for your language/framework of choice) which then sends
               | it back to the user, in most cases automatically wiring
               | up old field values and error messages. Checking string
               | lengths or whatever is equally easy in both cases, but
               | what's really difficult is the part you conveniently
               | hand-wave away:                 usually, it's harder /
               | more awkward to wire the API feedback to highlight the
               | offending Form fields
               | 
               | This is _the entire point_ of validations. When I render
               | everything on the server, I have my entire application
               | and its associated logic to play with; can this Person
               | access that Document? Has this Person already enabled
               | Notifications for new Revisions on this Document? etc.
               | Most server-side libraries make it equally easy to
               | surface validation errors for those questions as they do
               | questions like  "Is this Password no shorter than 10
               | characters." Every time I've tried to do this on the
               | client there's been no easy way or you have to wire it up
               | manually every time.                 There is no
               | difference in how an HTMX app would authenticate to its
               | endpoints and how an SPA would
               | 
               | I've found this not to be the case. Here are the
               | potential options I see:
               | 
               | - The client contains all the logic for who can view
               | what, and redirects or shows a message appropriately
               | using whatever mechanism is appropriate (e.g. Angular has
               | route guards, I'm sure other routers have similar
               | functionality). Because you want real data protection,
               | this logic is _also_ on the server, so now you have
               | duplicated logic and you have to hit the server multiple
               | times on every navigation, which is basically
               | impractical. - The server contains all the logic for who
               | can view what, and when the client asks the server for
               | some data, if it responds with 403 it can show a message
               | or redirect or whatever. This is okay, but now you have
               | so little information on what happened on the client side
               | that it 's a much worse experience. e.g. if I try to
               | access a document that I don't have access to on the
               | server-side, I can redirect_back and maybe show a pretty
               | message that says "hey you can't access that, maybe click
               | this link to ask for permission." If I just get a 403
               | from the server, all I can say is "uhh I don't know, you
               | can't do whatever you just tried to do."
               | 
               | This is much easier if all your logic resides on the
               | server. To check if a Person can access a Document, you
               | just call person.owns?(document) or whatever. If they
               | don't, you just redirect_to wherever, and since you
               | haven't actually rendered anything yet it's all in a
               | single HTTP request-response cycle.
               | Obviously, but you load the client version from the
               | server at API request time
               | 
               | I'm not sure you understand my problem here; it seems
               | like perhaps client-heavy people just aren't doing this
               | anymore? Ember, Backbone, et al got this part right, and
               | everything since then seems to have forgotten about the
               | "M" part of MVC.
               | 
               | What I mean is that on the server I have a Document
               | class, a Person class, etc. and the associated business
               | logic for dealing with it. Maybe a document has a bunch
               | of Revisions, and they're stored in an array or something
               | and I can get the newest revision by calling
               | document.latest_revision, or I can get properties of the
               | latest revision by just doing document.latest.title.
               | Maybe when I update a field on a Document I really want
               | to create a new Revision or something. Whatever, I'm just
               | making stuff up here, but you get the kind of business
               | logic I'm talking about.
               | 
               | How do I do _any_ of this on the client? Do I have a
               | separate Document class that maintains all the same
               | logic? Do I split the logic so some of it is on the
               | client and some is on the server? Do I put it all on the
               | client...oh but wait I can 't do that because the server
               | needs to do integrity checks or make database calls that
               | the client simply can't do.
               | 
               | In an ideal world, what I want is essentially like my ORM
               | on the server-side: a cache of every instance of every
               | model that I've loaded from the server, normalized with
               | references to one another and an easy way to retrieve an
               | object with its relationships either from memory or from
               | the database (network/API). It's then easy to update
               | Document(id=45) in one place and have it propagate to the
               | rest of the app, and if it's referenced by any related
               | objects to have the update propagate to them, too. This
               | is a _hell_ of a lot of work to create, and basically
               | none of the modern frameworks provide anything resembling
               | this.
               | 
               | ---
               | 
               | Your final few paragraphs are essentially all the rosy
               | writing out there about client-heavy approaches: look how
               | wonderful it is! Just fetch your data and we'll rerender
               | it! I understand all that. And maybe it's evidence that
               | we're just living in such different worlds that there's
               | difficulty explaining requirements to one another.
               | 
               | If I was creating Desmos or something, where basically
               | every ounce of logic exists on the client, and the
               | client's job is just to do a bunch of stuff with client-
               | generated data and display it, then yeah I'd probably
               | reach for a client-centric approach. But I'm not. Most of
               | the time I'm creating GitHub or Wikipedia or Fastmail or
               | something, where there could be some nice benefits of
               | having a fat-client that talks to an API, but the massive
               | complexity increase just isn't worth it.
        
             | andybak wrote:
             | > To me this is like building a house that can never be
             | expanded,
             | 
             | Or alternatively it's a good application of YAGNI.
             | 
             | There's always a difficult balance between that as a
             | principle and "do work upfront as it will take you longer
             | to do later down the line"
             | 
             | Everyone makes this decision based on client budget, time
             | constraints and a host of other factors. My clients tend to
             | prefer to save money in the short term. That's not uncommon
             | and it's a rational position to take for many.
        
         | andybak wrote:
         | > because if at some point you need to render on a client other
         | than a browser
         | 
         | Been doing this for decades and this has cropped up so few
         | times I can't actually think of any.
         | 
         | Your clients might not be my clients. Your projects differ from
         | mine. Don't generalise from your own experience. There's a lot
         | more websites than there are apps.
        
         | ethnt wrote:
         | Depending on your architecture, an API or rendering HTML is an
         | implementation detail, rather than the meat of the application.
         | Have your business logic elsewhere and have the API or
         | controller endpoints call out to those and just do the business
         | of rendering JSON or HTML in the controllers.
         | 
         | (I think this is inversion of control, someone can correct me
         | if I'm wrong)
        
         | dnautics wrote:
         | can't speak for the others, because they are still stateless,
         | but LiveView is stateful and this is the point, you're not
         | constantly rocketing perfectly good content into the trash can;
         | it's essentially a "content-aware cache layer":
         | 
         | https://www.youtube.com/watch?v=XhNv1ikZNLs&list=PLqj39LCvnO...
        
         | simion314 wrote:
         | >you have to start from the beginning and write an API now.
         | 
         | You could refactor your code to share mostly everything . I
         | have no idea how this templates system work though so maybe you
         | need a different one.
         | 
         | so the API returns an array of users object as a json the html
         | side of things would have a render function that has as input
         | the same array of user objects. What you will probably lose
         | versus complex frameworks is magic stuff like 2 way data
         | bindings but from my experience those always caused issue, I
         | prefered the old react way of doing things, it was more
         | "functional style" and less magic under the hood and I
         | could(and used) JS and not a special template language with
         | special keywords to render stuff.
         | 
         | Amway my point is yu can reuse the API code for the html render
         | stuff too.
        
       | bingohbangoh wrote:
       | I'm a big fan of these setups but has anybody ever successfully
       | used a minimal-JS setup for anything useful?
       | 
       | I mean, there's apps like Pinboard but React & Redux do handle a
       | lot of complexity and most modern apps demand that complexity.
        
         | deniz-a wrote:
         | People have done plenty of useful things with htmx, just like
         | people did (and some continue to do) useful things with links &
         | forms.
         | 
         | Here's the example that's most convenient for me to pull up:
         | https://www.youtube.com/watch?v=zHoAwVcSLdE (via
         | https://www.commspace.co.za/)
         | 
         | > most modern apps demand that complexity.
         | 
         | Citation needed.
        
         | nnoitra wrote:
         | Whatever you can do with React you can do with pure JS.
        
         | infamia wrote:
         | Basecamp and Hey.com for starters.
        
       | streamofdigits wrote:
       | would it possible to have a browser _ship_ with htmx so that it
       | is possible to have truly  "javascript optional"? (in principle
       | this applies to any full js framework but I suppose it is natural
       | in the htmx context)
       | 
       | are there any unsurmountable issues around security and the
       | sandbox etc (not terribly familiar with browser internals)
        
         | deniz-a wrote:
         | Most of what htmx does is a direct extension of the browser's
         | capabilities. Some issues I can think of are
         | 
         | - maintaining the "accessible by default" nature of HTML
         | 
         | - swapping. htmx takes html from the server and uses one of
         | innerHTML, outerHTML and insertAdjacentHTML to put it into the
         | document, but it also does a whole lot more to avoid unexpected
         | behavior. This would all need to be specified and implemented
         | natively
        
       | pjs_ wrote:
       | HTMX really kicks ass, I simply love it.
        
       | chrisfinazzo wrote:
       | Smells like Turbo (and related frameworks) to me, which isn't a
       | bad thing. From my brief use of CRA, I can see why many people
       | are attracted to it, but the fact that a bunch of JS has to
       | download before anything happens is never far from my mind.
       | 
       | In the meantime, I'll keep waiting until we get native HTML
       | imports/includes - hopefully before the heat death of the
       | Universe.
        
       | Savageman wrote:
       | It reminds me a bit of [MooTools
       | Behavior](https://mootools.net/blog/2011/12/20/mootools-behavior)
       | (from 2011!) where interactivity was created by adding tags to
       | HTML, similar to the article!
        
       | synergy20 wrote:
       | If I use alpine.js why do I need htmx still? I would use either
       | of them but not both. Using both seems making a supposed-to-be-
       | simple approach immediately back to complicated-again-now-you-
       | need-two-components.
       | 
       | alpine increases client side interactivity, it can also do ajax
       | to talk with server, why do I still need htmx then?
       | 
       | On the other hand if I use htmx I will probably use its
       | hyperscript for interactivity on the client side, to be
       | 'consistent'.
       | 
       | Note both projects are trying to make frontend simpler, mixing
       | them seems not to help that goal to me.
        
         | nop_slide wrote:
         | I don't think Alpine has any similar AJAX directives as HTMX.
        
         | deniz-a wrote:
         | The pattern is that you use htmx for anything it can do, then
         | use Alpine for things that shouldn't/can't require a server
         | round-trip (toggling sidebar, animations etc).
         | 
         | You can reimplement htmx functionality with Alpine, but htmx is
         | a lot better than `@click="fetch('/partial').then(res =>
         | res.text()).then(frag => $el.innerHTML = frag)"` all over the
         | place (with a slight variation in that one component that you
         | miss because of the noise).
         | 
         | Don't use _hyperscript just to be "'`consistent`'", use it
         | because you want to. Being agnostic and playing well with other
         | tools is a big thing for htmx. _hyperscript is lots of fun and
         | lets you write very readable code, but you also need to stomach
         | a 26mb bundle just to toggle some classes :/
         | 
         | (if anyone reading this can help us make it smaller, LMK)
        
           | recursivedoubts wrote:
           | _> 26mb_
           | 
           | ackshully, 21.2 _kB_ :
           | 
           | https://bundlephobia.com/package/hyperscript.org@0.9.0
           | 
           | Which compares pretty well w/ alpine, which comes in at
           | 21.7kB with its dependency:
           | 
           | https://bundlephobia.com/package/alpinejs@3.5.2 - 17kB
           | https://bundlephobia.com/package/@vue/reactivity@3.2.22 -
           | 4.7kB
           | 
           | :)
        
         | recursivedoubts wrote:
         | htmx is for syncing client side actions with the server
         | effectively within the hypermedia model
         | 
         | AlpineJS (and hyperscript) are better for purely front end
         | needs.
         | 
         | htmx and Alpine pair well together, as does htmx/jQuery,
         | htmx/VanillaJS or, if you are brave, htmx/hyperscript
        
       | nawgz wrote:
       | I take so much issue with HTMX being branded as "JavaScript
       | optional". It's a project built for people who hate JS by people
       | who hate JS, and as the resulting developer workflows aren't JS-
       | based have managed to convince themselves they're not using JS.
       | 
       | It's totally false. Your HTMX app does not work for JS-disabled
       | people any more than someone's React/Angular/Vue first-render-on-
       | server app.
        
         | VWWHFSfQ wrote:
         | I think you misunderstand what HTMX is
        
           | nawgz wrote:
           | Explain it closely to me then. What is HTMX doing that
           | enables someone to write HTML attributes that make arbitrary
           | actions that update the DOM possible?
        
             | post-it wrote:
             | My understanding of HTMX is that the main draw is not
             | having to _write_ JS as a dev, not not having to _run_ JS
             | as a user.
        
               | hunterb123 wrote:
               | Optional JS is a term already for web pages that degrade
               | gracefully when JS is turned off.
               | 
               | It's a shady marketing technique to hijack that term when
               | it doesn't work that way.
        
               | VWWHFSfQ wrote:
               | it does work that way though
        
             | VWWHFSfQ wrote:
             | when there's no javascript those attributes do nothing and
             | your webpage acts like normal. ie, link clicks do a full
             | page load. so your website works with or without
             | javascript.
        
       | colbyhub wrote:
       | Another one to consider is https://www.django-unicorn.com if you
       | want that LiveView feeling for Django.
       | 
       | For my latest project[1], I've opted for https://unpoly.com
       | instead of Alipine+htmx as Unpoly allows me to write 100% server-
       | side code and sprinkle some progressive enhancement where
       | desirable. As a result, I can offer a no-JS experience (minus the
       | Stripe Checkout) for those who may want/need it. Additionally, it
       | forces me to focus solely on the server-side, and I write more
       | idiomatic Django code as a result.
       | 
       | [1]: https://heraldsms.com
        
         | porker wrote:
         | I've been looking at these libraries and Unpoly looks the most
         | promising for my needs. HTMX looks good as well but Unpoly's
         | infinite layers feature [1] rather grabbed my attention :)
         | 
         | Stimulus is the one I can't get myself to like. Separate JS
         | controllers is clever but the DSL and general nature - it just
         | doesn't click with me.
         | 
         | [1] https://unpoly.com/up.layer
        
         | benbristow wrote:
         | https://www.django-unicorn.com/examples/count-characters
         | 
         | Sending an AJAX request every time you enter characters just to
         | count them. Ewwww.
        
           | alpha_squared wrote:
           | I guess that's the extreme end of no-js. Wanting to use
           | compute, but philosophically sticking-to-your-guns on where
           | that compute happens.
        
             | benbristow wrote:
             | Well it's still using JS to send the AJAX request, so in-
             | fact something along the lines of 'on text change, set some
             | element text to text.length' is a lot less JavaScript code
             | than 'on text change, format and POST an AJAX request and
             | then set the element text to a value within the response'.
        
               | RussianCow wrote:
               | The difference being that the code to send an Ajax
               | request an update the DOM based on the response is
               | already coded and already used in other places, whereas
               | updating the text length client-side would have to be
               | custom code. Not that I'm arguing one way or another, but
               | the reason it's done that way is to reuse the same set of
               | primitives for everything.
        
       | sbussard wrote:
       | I always have the fear that something I write will be too
       | complicated for someone else. This has become particularly
       | irksome when integrating OIDC into a single page app. It's gut
       | wrenching to double check every random header for every domain it
       | needs to serve, to set up SSL for localhost, to include the right
       | headers on the fetch request, and maybe edit the /etc/hosts file
       | to make it work. That process is a joy killer. The tools
       | mentioned here can help stop that madness and bring joy back into
       | development. So thank you! Please evangelize these ideas to
       | browser standards committees and whoever will listen.
        
       | polyrand wrote:
       | After reading some HTMX criticism, there's one point people seem
       | to miss. Making HTML your application interface does *not*
       | prevent you from having a JSON (or something else) API. If
       | anything, it probably forces you to split your functions better.
       | e.g:                 def get_user_data(user_id: int) -> Dict
       | (JSON-looking data):           ...            def
       | render_user_view(user_id: int) -> HTML:           user_data =
       | get_user_data(user_id)
       | render_template("user_detail_view.html", context=user_data)
       | 
       | If you need the user data in a JSON API, nothing prevents you
       | from exposing `get_user_data` as a JSON endpoint. You can also
       | use WebViews in a mobile app.
       | 
       | People tend to overestimate the "interactivity" needs of their
       | apps and underestimate what they can achieve by just swapping
       | HTML. HTMX also lets you swap "Out of Band" [0]. This makes it
       | easy to model more complex interactions (like "reactions"), for
       | example, updating a counter somewhere else in the app when a form
       | is submitted. Reactive frameworks can also become a Rube Goldberg
       | machine if an app is not properly designed from the beginning.
       | Then you start fighting rendering loops, build dependencies,
       | components' side effects, etc.
       | 
       | Personally speaking, HTML-driven apps are not just about easy vs.
       | hard development, it's also about your users [1]. Maybe a big
       | React app runs fine on 8 CPU cores and 32 GB of RAM, but very
       | often, your users just want to read some content, maybe submit a
       | few forms, and leave. They may not want to download 2 MB of JS so
       | that the page can render boxes with text, even more if your
       | browser can already do that if you give it some HTML.
       | 
       | [0] https://htmx.org/attributes/hx-swap-oob/ [1]
       | https://shkspr.mobi/blog/2021/01/the-unreasonable-effectiven...
        
         | abstract_put wrote:
         | Big +1 on all of this. I have terrible rural internet, and just
         | recently tried developing my first app with HTMX (wasn't aware
         | of Alpine.js), and _man_ is it fast. For city slickers with
         | their symmetrical gigabit connections it may be unnoticeable,
         | unfortunately. Not saying SPAs have to be bloated, it just
         | seems like most sites that turn into SPAs are bloated.
         | 
         | All that said, trying to push everything server-side if you've
         | been working in a heavy client takes some getting used to. In
         | my real life job I've seen feature flags shipped as an API so
         | the client queries whether a feature flag is enabled - this is
         | something that always struck me as silly, the server serving
         | the front end already knows if the feature flag is enabled.
         | While that might be justifiable in some cases, it is definitely
         | not so much in the on-prem-only product I worked on.
        
       | nop_slide wrote:
       | Can anyone describe the use cases between HTMX/Alpine and Unpoly
       | JS? I see the 3 routinely mentioned, but I am unsure what
       | coverage Unpoly has vs HTMX/Alpine.
       | 
       | https://unpoly.com/
        
       | thih9 wrote:
       | Is anyone here using either HTMX or Alpine.js (or both) in
       | production? What are your thoughts, are you happy with how these
       | work in practice?
        
         | jonathan-adly wrote:
         | I am using HTMX in production in two applications - it's sped
         | development considerably.
         | 
         | I completely stopped using React
        
         | sgt wrote:
         | Am using AlpineJS on a new production Django app. Works fine.
        
         | werdnapk wrote:
         | I use Alpine.js in a handful of my production apps and have had
         | no real issues when Vue, etc is overkill, except that when
         | dealing with a lot of data, I found Alpine.js to be just way
         | too slow with rendering. Swapping out Alpine.js for Vue fixed
         | my problem. I likely was pushing Alpine.js beyond it's intent
         | of "small" snippets to enhance a page.
        
       | strogonoff wrote:
       | Downside of most HTMX examples (such as the form in TFA) seems to
       | be lack of graceful degradation with non-JS-enabled user agents.
       | 
       | But then, the rest of the page is server-generated (taking care
       | of SEO), and handling interactivity without JS may not be a
       | priority for most sites nowadays.
        
         | recursivedoubts wrote:
         | progressive enhancement is possible with htmx (e.g. the hx-
         | boost attribute is p/e friendly) but often requires thought by
         | the programmer
         | 
         | for example, the active search example can be made p/e'd by
         | wrapping the input with a form that submits to the same page:
         | 
         | https://htmx.org/examples/active-search/
         | 
         | but it requires work by the end developer
         | 
         | the idea here is to be pragmatic: obviously some people care
         | deeply about p/e and are unwilling to sacrifice it for more
         | advanced U/X, but others are willing to do so, so let's make it
         | possible for both camps to improve their sites with the tool
        
       | beebeepka wrote:
       | I think it's great people who passionately dislike JavaScript
       | have such powerful options.
       | 
       | Personally, I am not buying the whole "you can do anything this
       | way" because it seems to me the main driver, implied or plainly
       | stated, is always the "and no js!" part.
       | 
       | I get it, though. We are all capable of going to great lengths to
       | prove a point. Having more viable options is great.
        
         | joelbluminator wrote:
         | It's not necessarily about disliking JavaScript. I can see Node
         | people using this as well, why wouldn't they? Not everyone
         | wants or needs to double their app code by building both a
         | server app and a SPA. I might be exaggerating by "double" but
         | it's for sure a major increase of code. Github is doing fine
         | without a SPA last I heard.
        
       | 1270018080 wrote:
       | This honestly sounds like a miserable tech stack.
        
       | Wronnay wrote:
       | https://archive.md/9YAJm
        
       | ksec wrote:
       | Sorry if this is off topic, I remember reading a proposal of
       | including something similar to Alpine.js / HTMX within the HTML5
       | spec.
       | 
       | But I lost the page. And the proposal itself doesn't mention
       | Alpine.js or HTMX so no keyword bring it up in Google. I am
       | wondering if anyone have any idea.
        
         | technobabbler wrote:
         | Web components? https://developer.mozilla.org/en-
         | US/docs/Web/Web_Components
        
         | deniz-a wrote:
         | This might be it https://discourse.wicg.io/t/extending-html-as-
         | a-hypermedia/5...
        
       | resoluteteeth wrote:
       | One major downside to HTMX is that as soon as there is any state
       | you have to keep track of, you're teleported back to the late 90s
       | or early 2000s where you have to keep track of all your state in
       | hidden form fields, and you're extremely constrained in how you
       | update pages.
       | 
       | IMO, it's annoying enough that it's probably not worth it unless
       | you're doing something trivial. If you want to render html on the
       | server you can still do that, but in many cases it is easier to
       | just use custom javascript and maybe even receive the rendered
       | html as json to simply updating pages rather than use htmx.
        
         | nlitened wrote:
         | Yeah, those damned early 2000s when back/forward buttons worked
         | perfectly and we didn't lose the entire rich client state upon
         | page refresh or wireless internet hiccup. Thank god we have a
         | lot of JavaScript libraries and ambitious programmers to save
         | us from those trivial things :)
        
           | kiawe_fire wrote:
           | But those were actual problems back then, and they were
           | solved only through significant engineering work to hide
           | them, each of which had their own problems.
           | 
           | Frameworks like .Net WebForms were created to abstract and
           | hide a lot of this from developers, with things like long
           | encoded strings of "view state" that would be re-posted on
           | each request, by serializing things to the URL, or by saving
           | them to Cookie-backed sessions.
           | 
           | But each of these has issues, from privacy concerns using the
           | URL, to security concerns with the "view state", to
           | concurrency and integrity concerns with sessions.
           | 
           | IMO, the biggest reasons these didn't stand out as huge
           | problems in the early 2000's was because:
           | 
           | (a) we didn't use the web like we do today, and our
           | expectations were very different in how things would work if
           | we, for example, added an item to a shopping cart
           | 
           | (b) most heavily interactive / app-like things that more
           | closely work "the way we expect" today, were either still
           | done as desktop apps (like business software) or were
           | implemented as Java applets, Flash, or something else of the
           | sort
           | 
           | (c) in the rare cases that neither (a) nor (b) applied, it
           | was because some very good engineers put in a lot of work to
           | make it work that way.
        
         | jon1628492 wrote:
         | I'm new to htmx and alpine, but isn't alpine's global store
         | what you'd want in this case? https://alpinejs.dev/magics/store
        
       | austincheney wrote:
       | I'm not sure I understand the motivation to avoid JavaScript. I
       | completely understand not wanting 400mb of SPA/NPM nonsense, but
       | otherwise what problem does avoiding JS solve in a webpage?
       | 
       | * Is it because JavaScript is too hard to learn or too unpleasant
       | to write?
       | 
       | * Is it because training people to write JavaScript is too much
       | effort?
       | 
       | * Is it due to a lack of trust in your fellow developers?
       | 
       | * Is it due to challenges in planning or forming architecture?
       | 
       | * Something else?
        
       | jonatron wrote:
       | Not sure about the snippet:                   // when the DOM is
       | loaded         document.addEventListener('DOMContentLoaded', ()
       | => {           // find every element with the class "close"
       | (document.querySelectorAll('.close') || []).forEach((closeButton)
       | => {             const parent = closeButton.parentNode;
       | // and add a "click" event listener
       | closeButton.addEventListener('click', () => {               //
       | that removes the button's parent from the DOM
       | parent.parentNode.removeChild(parent);             });
       | });         });
       | 
       | It'd be clearer without useless comments and useless extra code:
       | document.addEventListener('DOMContentLoaded', () => {
       | document.querySelectorAll('.close').forEach((closeButton) => {
       | closeButton.addEventListener('click', (event) => {
       | event.target.parentNode.remove()                 })
       | });         });
        
       | robertoandred wrote:
       | Don't use a framework, use three!
       | 
       | This sounds like a lot of effort just to brag about how you
       | avoided whatever piece of tech we're considering to be evil this
       | month.
        
         | ozzythecat wrote:
         | I did web development work in the early 2000s (PHP, MySQL) and
         | briefly in 2013-2014. In the past few years, I explored a
         | recent version of Angular, React, and some other framework.
         | 
         | The tooling seemed really nice at first, but I was actually
         | shocked at the number of dependencies and just the overall
         | complexity with all the layers of abstractions.
         | 
         | Fundamentally, these are still websites. I honestly see this as
         | people getting bored, inventing new things to deal with their
         | boredom, and the rest of the industry follows.
         | 
         | Meanwhile, the services I was writing in Java like 10 years ago
         | haven't really changed. We agreed Spring sucked and moved on.
         | At a FANG where I work, we use Java and Kotlin. A lot of my
         | data crunching jobs are in Scala. We did start using Rust for
         | shared libraries deployed on mobile operating systems...
         | because the entire team preferred it over C++.
         | 
         | But I come back to web development and there's always a new
         | flavor of solving the same problem. /shrug
        
           | BoumTAC wrote:
           | I do not understand it too.
           | 
           | The cost due to the complexity is at least 10 times more.
           | 
           | It feels strange to me that nobody in the hierarchy consider
           | it.
           | 
           | I do understand that developer like to play with new
           | technology and don't care about the cost as long as they can
           | play with it and get paid but the hierarchy must have seen
           | the millions dollars lost. Why did they do not say something
           | about it ?
        
         | recursivedoubts wrote:
         | alpine has one dependency and htmx is dependency-free, and both
         | are very small[1][2]
         | 
         | so it is a very lightweight combination on top of plain-ol'
         | HTML
         | 
         | [1] - https://bundlephobia.com/package/alpinejs@3.5.2 [2] -
         | https://bundlephobia.com/package/htmx.org@1.6.1
        
         | ttymck wrote:
         | This is unfair. HTMX and Alpine could hardly be considered
         | frameworks.
         | 
         | React, by comparison, is absolutely massive. It's complicated.
         | It requires compilation, and often a complex build
         | configuration. You still need a backend server, so it won't
         | obviate Django.
         | 
         | Your comment speaks to a larger debate, but it's a rather
         | disappointing contribution.
        
       | jonathan-adly wrote:
       | For people who want to see more advanced examples/tutorials built
       | using Django and htmx- you can see a bunch here: https://htmx-
       | django.com/
       | 
       | Anything that can be done with React/Vue can be done with htmx in
       | a more "Django-way"- it's an amazing library that allows for
       | complete web applications without the complexity of the JS
       | ecosystem
        
         | robertoandred wrote:
         | All I see there is someone using <span>s as fake <a>s.
        
           | jonathan-adly wrote:
           | cool, right? You don't have to do this with htmx, but you can
           | if you want too and I did because I wanted too :)
           | 
           | Keep an open mind and continue reading on
        
             | robertoandred wrote:
             | Fake links break normal link behavior. Accessibility
             | issues, opening links in new tabs, etc.
        
       | reidjs wrote:
       | Can this stack easily handle 2-way data bindings on the frontend?
       | For example, when you update a text input, the title of the text
       | input changes?
        
         | mejutoco wrote:
         | Yes. You give ids to elements and the html indicates which id
         | to replace with which content. You can even replace ids in
         | other sections (might get complex quickly, but it works).
         | 
         | https://htmx.org/attributes/hx-swap-oob/
         | 
         | Source: I used this to implement my
         | https://fromzerotofullstack.com website.
        
         | czue wrote:
         | Alpine should be able to do this by itself.
        
         | recursivedoubts wrote:
         | purely front end use cases like this would be handled by alpine
         | 
         | syncing state with the back end would be handled by htmx
        
       | fareesh wrote:
       | A suggestion for folks writing articles like this - sell me the
       | advanced but typical example. I want to see an image input which
       | is then previewed and then uploaded asynchronously with a loading
       | bar and error states.
        
       ___________________________________________________________________
       (page generated 2021-11-23 23:00 UTC)