[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)