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