I understand (kinda) why SPAs came about. My question is; what incentive do companies have to revert to the more sane and simple technologies of htmx, hotwire etc?
I'm a rails dev and I love the framework but there's a realist in me that sees something akin to the phrase "markets can stay irrational for longer than you can stay solvent"
candiddevmike 647 days ago [-]
What's sane about swapping type safe, offline capable frontend code for spaghetti htmx/hotwire code?
clivestaples 647 days ago [-]
In the case of Rails, I lose type safety but also get a huge boost of productivity in other with extremely well-documented features: database migrations, testing, mailers, queues/jobs, file storage, rich text, authentication helpers (especially v7), etc. Re: spaghetti: I'm not sure my Rails setup is less neat and tidy than the React, Redux, Saga, GraphQL Typescript codebase of my 9-5 TBH. Could be just me though.
EDIT: typo
jack_riminton 647 days ago [-]
I've yet to be given a single example of how Rails suffers without types, it's just not an issue
Hotwire is the polar opposite of spaghetti code
boredtofears 647 days ago [-]
Rails does better than the rest of the Ruby ecosystem without types because it has strong conventions, but if you’ve ever adopted a rails app that doesn’t follow these conventions (or follows different ones like in the 3.x days where they were less defined) refactoring things across an entire codebase can be a gargantuan task.
Following variable life cycles in Ruby in general is much harder than a typed language. There are tools like pry for this sort of thing, but that’s more work than just having types with good ide integration.
joshspankit 646 days ago [-]
As a sibling comment implies, it can be a huge issue if the existing codebase tosses out conventions.
It’s underrated since devs mostly do it without thinking about it, but in enough cases you need to double-check the type before running any operation that requires a certain type. Unchecked it will either crash entirely or cause bugs so esoteric that they are very difficult to debug.
I don’t think I’d categorize it as “how Rails suffers without types”, more like “stay away from the edges and you’ll be fine”, but it can still bite you hard if someone mis-steps.
jack_riminton 646 days ago [-]
But I genuinely can't think of an example that is ever likely to arise, can you give me one?
Anything I can think of will immediately throw an error or would be covered by the most basic of test suites
joshspankit 646 days ago [-]
> immediately throw an error
That’s exactly what we don’t want in production code. We want it to work without errors.
An example: assign a variable to the output of a library function, then pass the variable in to a different function. Super basic, super common.
One instance of that is calling the first function and expecting an array back but getting any one of ‘String’ (edge case that the library maintainer decided is a good idea) or ‘False’ (maintainer decided that’s what happens when something fails during the call).
If you call ‘.each’ within the second function without verifying that the variable is iterable first the function will throw. (I’ve even seen a couple rare cases where a custom class responds to ‘.each’ but is not properly iterable).
Most Ruby devs will “just” check before they call ‘.each’, or wrap the second call in a rescue block, but that’s exactly the sort of potential for misstep I’m talking about.
jack_riminton 646 days ago [-]
Interesting. I wonder if these came about from engineers just trying to be too clever. The thing I really love about rails is the focus on creating nice boring conventional code.
I think the current mania for types has arisen largely out of the js SPA crowd creating problems for themselves doing the opposite,
rchaud 647 days ago [-]
Spaghetti in, spaghetti out. HTMX isn't going to spit out anything that wasn't already in your component.
tomatofrank 646 days ago [-]
Show me five use cases of offline web apps and I'll show you a liar ;)
naasking 647 days ago [-]
Show the spaghetti?
j45 647 days ago [-]
When technology decisions are too often made on signalling trendiness and shiny object syndrome, all organizations will eventually evolve out of this.
Simple technologies leave innovation points to be spent in the problem and user instead of experimenting with new tech that is usually a rewrite of something else that’s already similar, except without the hardening and maturation
bnchrch 647 days ago [-]
Simple is a changing target.
In a one person team merging your server with your client and using HTMX can be simpler (depending on if the value is in your UX or in your logic/data).
However as the team gets larger then I find having a clear separation between your API(s) and your Client(s) is much more simple and maintainable. Also it can unblock product decisions like offline mode or PWA's.
Finally its worth stating that being in an SPA community like React can give you access to "economies of scale" in terms of the libraries available to save you time (Tables, animations, UI kits, Video players, etc.) allowing you to do more with less people.
brtkdotse 647 days ago [-]
> clear separation between your API(s) and your Client(s)
The problem is that the SPA way of thinking has infiltrated every nook and cranny in this industry. The ratio of APIs vs clients consuming those APIs come scarily close to 1, at least with the customers I work with.
Now you have to maintain two projects, two CI/CD pipelines, two hosting solutions, potentially two sets of languages and tooling…
Danjoe4 646 days ago [-]
Yes. You should probably start with a monolith. If you really scale then toss the htmx FE, expose an API, and slap a react project on top. Django lends itself to this growth pattern very well.
klysm 647 days ago [-]
They aren’t more sane in all cases. You’ve left out the massively critical context of what’s being built.
endlessvoid94 647 days ago [-]
I wish someone would write up a comparison of Turbo/Stimulus and HTMX/Alpine. The approaches seem extremely (spiritually) similar, yet seem to ignore each other.
ebiester 647 days ago [-]
I'd also add Elixir/Liveview to that as well.
skeptrune 647 days ago [-]
I've heard a ton about HTMX/Alpine, but nothing about Turbo/Stimulus yet. Will have to look into it.
rchaud 647 days ago [-]
This seems like more of an ad for building with HTMX than anything else. Everything they're describing is true of any server-side rendered app that doesnt need a build step. I use HTMX for my PHP app and it's great, I can drop a folder into a webserver and voila it's live!
andrewmutz 647 days ago [-]
Yeah the part of the website devoted to Astro says as much:
> If you know another classic Web Application server like Rails, Django, Laravel, or like building your own in Go or whatever, you can use anything you want.
azemetre 646 days ago [-]
The owner of the site should change the acronym to alpine, htmx, and anything.
Then stress the anything part.
klysm 647 days ago [-]
I don't understand why all the arguments around frontend stacks on the web are treated with such dogma - it's a tradeoff space! You can send JSON, HTML, or whatever, but it depends on _what you are building_. The decision about what tools to use is nuanced, and difficult, and most importantly vastly depends on the context of what you are trying to accomplish.
bee_rider 647 days ago [-]
Some of the tradeoffs are paid more by different parties. For example, sending out scripts instead of content was (presumably? I don’t do webdev) easier for the developers. But it has a cost to the customers (wasting battery, starting up this crazy ecosystem where the expectation is we’ll just download scripts from the internet and run them).
When only one side pays the price, I think it isn’t that surprising that it gets dogmatic. Because there isn’t any trade off, really, for me as a user, getting scripts is simply bad, and getting plain old documents is simply good. Where’s the nuance or tradeoff? I don’t care if setting up a static site generator takes more time or is harder or whatever, I only see the output, which is obviously better in one case.
In the case of web devs talking to web devs, I’m not sure, having not been in that room. But from an outsider point of view, it seems like some sites care about this sort of thing and others just don’t. Maybe which parties are included in the cost calculation is basically an axiom, not really something that can be logic-ed out, and so it tends toward dogmatism and statements of preference? (hopefully I’ve accurately represented the fact that this is 100% a comment from the user point of view, so heap of salt and all that).
miki123211 647 days ago [-]
> getting scripts is simply bad, and getting plain old documents is simply good
This isn't that simple IMO. On one hand, JS-heavy apps take longer to load on underpowered devices and slow connections, which should be treated as an accessibility concern. On the other, approaches like LiveView, HTMX or even plain old HTML struggle on high-latency or spotty connections. A well designed SPA can cache data locally and push changes whenever internet connectivity comes back, making it feel a lot snappier in these situations. SPA apps are harder to write because you have an extra API layer, but you need one anyway if you're also writing a mobile app, so they may even become slightly easier in that situation. Every solution has its tradeoffs.
klysm 647 days ago [-]
You’re getting at just one axis of a larger trade off space. Yes serving scripts move compute cost to the browser, but you can also gain a lot of latency wins (which are sometimes critical) by having more compute on the client.
joshuaissac 647 days ago [-]
> I don’t care if setting up a static site generator takes more time or is harder or whatever, I only see the output, which is obviously better in one case.
Don't these static site generators serve the scripts that you do not like? On a statically-generated site, the dynamism of the site is in the script and is evaluated in your browser. On a non-static site, the server does the evaluation, so your browser does not have to run as many scripts for the same level of dynamism.
foolswisdom 647 days ago [-]
Sounds like you're using the concept of statically served files vs dynamically generated, but that's a different conversation to whether content files are generated at all.
throwbadubadu 647 days ago [-]
Nope, you got it mixed around..
WD-42 647 days ago [-]
The key there is what you are building. The problem is that people who aren't aware or don't have appealing alternatives will still build a full SPA for something simple like a blog. This just makes the internet a worse place. It's frameworks like this that are trying to capture that audience, I think. AFAIK there is still nothing comparable to Rails/Django in the Javascript world.
gedy 647 days ago [-]
> The key there is what you are building. The problem is that people who aren't aware or don't have appealing alternatives will still build a full SPA for something simple like a blog.
In fairness, most of my experience in past 10 years is dealing with companies trying to fake SPA style apps in blog-style server side frameworks.
Maybe it's gotten better very recently, but Rails+jQuery mess is not better if folks really want a SPA-style app and interactions.
stephenhuey 647 days ago [-]
It has.
Among the 4 production B2B Rails apps I've been adding features to in the past year, the only one using jQuery was created 13 years ago. None of the others ever used jQuery, and using Hotwire Turbo to replicate SPA functionality is easy nowadays.
One of the Rails apps serves a Flutter mobile client on the front-end, and as much as I appreciate all the lifting Flutter does for me, the sheer amount of code required to support that is enormous and laborious in comparison to writing a few Turbo frame tags in the fullstack Rails app. If not for a few gotchas that the client app needed, that mobile app would have been done with Jumpstart Pro iOS & Android with Turbo Native (great code reuse potential).
Users of Rails apps leveraging Turbo frames or streams don't think those apps feel more shiny and cool and performant than legacy SPA frameworks such as React, and the modern Rails developers spend less time churning out code.
klysm 647 days ago [-]
I’ve seen it done poorly in both directions: blogs with SPAs and people trying to build SPAs with MVC frameworks.
lordgroff 647 days ago [-]
Yep. I have a Woocommerce site that's mostly modified by my own custom plugins.
Most of my own custom work plugs in to the old school PHP server side rendering and that works just fine. I also have what's in effect two separate SPAs in the backend. Doing these in htmx and Alpine or whatever would be an absolutely enormous headache and it would perform worse. There's no one size fits all.
endisneigh 647 days ago [-]
There really is no incentive. I remember intercoolerjs a long while ago.
People love arguing over nothing instead of picking a stack and shipping.
hnrodey 647 days ago [-]
>People love arguing over nothing instead of picking a stack and shipping.
The most valuable code is the code that runs in production.
blowski 647 days ago [-]
That’s an oft-quoted aphorism, but it’s not always true. Sometimes, the piece of crap you’ve just deployed becomes somebody else’s support and maintenance nightmare. With a bit more care, it could be avoided. Other times, the piece of crap was just what was needed, nothing more.
It’s important to think about the right solution, and it’s also important to know when and why you’re putting something into production. Golden mean and all that.
klysm 647 days ago [-]
That’s one way to deal with the trade off space - pick one and send it. Sometimes it even makes sense due to other constraints: the best technology for the task may not be the best technology to choose! If you can shoehorn something you have experience with then it might be worth it.
gmaster1440 647 days ago [-]
In a similar vein, I cannot recommend SvelteKit enough, which features some of the most consequential performance improvements[1] built right into the framework.
I haven't played with Astro much, it looks quite sane, but oriented more towards content-heavy sites vs webapps.
alabhyajindal 647 days ago [-]
I no longer have the patience to read through the praises of another frontend framework.
I started web development just 2 years ago using React and at the time I didn't know any of the traditional frameworks like Rails, Django or Laravel. I learned Rails recently and have been using it for my side projects since. I'm having a great experience!
When I see the headlines praising a frontend framework that's been around for < 5 years, I roll my eyes. I imagine it's been written by someone like me 2 years ago, who hasn't used traditional frameworks.
FireInsight 647 days ago [-]
I started webdev some years back from the other direction; I had read of the countless JS web frameworks and their countless dependencies, and I had read the arguments against using "uncessary" JS (talking about genuine bloat) on websites. So, I thought I'd just explore options like those based on Go; fast, compiles to a single binary, no need to touch JS. Then I wrote my first totally website with Hugo and and a custom theme for it, had fun doing it too. Tried to write a couple selfhosted web apps with Go frameworks too but never got that far.
Then I moved to doing all my projects with Astro/Svelte and webapps with SvelteKit. I was surprised at how good and fun it was. The templating languages less esoteric, more integrated. Reactivity was something I never even dreamed of with a hard line on JS. All the while, the websites got better. I could finish them more quickly and there was still no or a miniscule amount of JS shipped by default. I could also, when making a content-driven website with Astro, easily reach for Svelte for a small bit of interactivity / reactivity. I could've just as easily used Alpine or whatever else someone might recommend.
That's to say, I've found a comfortable DX in current-gen JS frameworks, while finding the server-side giants a bit too sturdy for my use. Reading about new frameworks is fun to me, because I can easily switch from Svelte to something else on my Astro sites, if I find something that fits my tastes even better.
alabhyajindal 646 days ago [-]
I prefer traditional server side frameworks precisely because they have a rigid pattern of doing something. And also because they have been around for a while.
I don't get excited about learning a new frontend framework because I'm fairly certain it won't allow me to do something new. It may be more convenient in terms of syntax or have fewer client side code being shipped, but it doesn't enable me to do something in terms of functionality I couldn't already do.
I would prefer pick one framework and get better at it, rather than learn the templating language of 5 frontend frameworks.
WD-42 647 days ago [-]
Interesting that you went from React to Rails, usually people go the other direction. It's neat seeing the good 'ol server side frameworks being "rediscovered".
hipadev23 647 days ago [-]
> usually people go the other direction
I'm not sure that's true. Time has went that direction, for sure, but I don't think historical backend web devs have migrated to react. Mostly front-end devs expanding their horizons and younger devs starting there.
WD-42 647 days ago [-]
> but I don't think historical backend web devs have migrated to react.
Really? Back in the day, myself and my peers weren't "backend web devs" we were just web devs. Stuff started shifting to the frontend and we all learned Backbone, Angular, React, etc because that's the way the industry went. I think a LOT of us migrated to React, maybe not completely, but who can call themselves a web developer these days without at least some experience with FE frameworks?
hipadev23 647 days ago [-]
Guess it depends on your role yeah. I'm familiar with React etc but I only use it when required, it's all so clumsy, constantly changing, and their best new ideas have existed in the ruby/python/php communities for decades.
I still really limit my JS to just improving the client-side UI/UX.
mind-blight 647 days ago [-]
I've been doing web development for about 20 years, and have the opposite reaction. I started web development with Flash (dark times), jQuery, and/or Django.
I love that people are pushing back on the SPA architecture everywhere (though SPAs are still the right choice for some apps). Some people are pushing back like you (returning to backend renderering), and others are pushing back like the implementer/poster by trying to extend the original intent of REST architecture (not JSON apis the term has come to mean).
I think the htmx architecture is brilliant, though it's not something I would use for the majority of my projects (it doesn't fit the use case).
I think what folks who have come to web dev recently don't understand the historical tradeoffs that led to SPAs or the current web dev ecosystem. It was terrible to build websites, but it was worse to build cross-platform applications using the existing tools and delivery systems. The browser solved a lot of that, and SPAs were an attempt to upgrade web architecture to support that need. People forget the positives because of how ubiquitous they've become and only look at the negatives.
I'm glad we're moving away from the SPA-only world, but every web framework that we use nowadays has been influenced by the advent of node+SPAs
the_gastropod 647 days ago [-]
It's refreshing to hear this take. Thank you!
I've worked with countless younger junior engineers who know React reasonably well, and largely think Rails is old "legacy" crap they don't want to deal with. And to be fair, using Rails as a dumb JSON api does disrupt much of the convenience of using Rails. But I never understood how people could so under-appreciate the tooling and structure that Rails provides.
rchaud 647 days ago [-]
> But I never understood how people could so under-appreciate the tooling and structure that Rails provides.
12 years ago Rails was just as hyped as React is now. In a few years junior devs will be pooh-poohing React the same way as they are doing to Rails.
endigma 647 days ago [-]
Alternatively, the S stack: SvelteKit. I don't understand why you would use a pairing of different tools in this space when Svelte/Kit solves all these problems with one framework. This could also be said for NextJS/Nuxt/etc but SvelteKit is particularly well integrated.
There's a glaring issue with HTMX and I'm not sure how it can be resolved gracefully. Other related libraries solved this issue already (Turbo and Turbolinks). However, HTMX only returns HTML fragments and doesn't track head changes.
It's not easy to explain.. but imagine if a user loads your webpage. Then the web page loads your assets are loaded (JS, CSS, etc).
Then imagine a new deployment happens that introduces new styles and/or HTML for a given resource.
The page that is loaded in the user's browser does not have the new styles and doesn't know they were updated. If the user interacts with the resource the page styles will break.
This was fixed in Turbo and Turbolinks by introducing "data-turbo-track="true"" to a resource like a CSS sheet. When the server responds with a fresh page the head can be compared and a full reload can happen if the asset was updated.
In HTMX, the page is just broken.
edit:
Currently, you would have to manually hack around this... like long polling for the current app version or returning it in every XHR request and adding a middleware to HTMX to do the check and pop up a "your page is out of date..." message.
recursivedoubts 646 days ago [-]
it's true that htmx is mainly focused on partial HTML replacement and we usually recommend that people load javascript and CSS up up front and/or adopt inline scripting solutions for locality of behavior[1], but htmx also has a head-support extension:
for htmx 2.0 i'm integrating this functionality into the core, it seems useful enough to be there. The extension is based on the head morphing algorithm of idiomorph:
I get it-- that will enable you to resolve the clash (or at least make it possible to detect and do something about it). However, it does feel messy/ugly when compared to how HTMX is generally portrayed (do some action, an HTML fragment in response). Now, you'll return an HTML fragment and/or an optional head element to merge? It feels a bit yucky, but I understand why it will be done.
A cleaner approach may be leveraging the HX-Trigger response header in some way? I feel like the app version could be specified and if it changes, HTMX would know and could trigger an event that could be specified by the user.
I don't really like either solution.. perhaps the head merging would be more correct, but damn it feels off =/
recursivedoubts 646 days ago [-]
there are typically three major types of requests w/ htmx:
- a full page request via an hx-boost, where head processing makes sense
- a full page request via an hx-get, etc. where hx-select is used to pick out a piece, where head processing probably doesn't make sense
- a partial of HTML, where head processing doesn't make sense
we will optimize head support for the first case, hx-boost based requests, and make the latter cases possible via configuration if the user wants.
htmx is much less opinionated than other frameworks on these things, i try to make it a hypermedia swiss army knife, which makes it a little ugly at times, but I don't like forcing people to do things a certain way for better or for worse
using HX-Trigger to do a full page refresh on an application version change is a common pattern, but is something you would build on top of htmx, not something htmx would provide out of the box. it is focused on generalizing hypermedia controls and patching a few gaps in HTML, and that's about it.
naasking 646 days ago [-]
Not sure I get it. Non-immutable resources should be bundled as a URL that's a hash of the contents. Since htmx replies include updates to head, if the content changes then the URL changes, and head updates would update the URLs.
Where's the issue? I can see you getting into a pickle if you don't bundle mutable resources, but that's why you should.
endisneigh 647 days ago [-]
JSON is superior imo, works with multiple clients, but if you insist on server side rendering why not use your servers built in method, e.g. Django templates?
A well made SPA can work offline and doesn’t have most of the typical disadvantages with respect to routing and redirects.
That being said, people should obviously use what they prefer. It’s interesting how these things have become a sort of holy war.
weinzierl 647 days ago [-]
I'm all for getting rid of JavaScript, but I don't really see what sending HTML over the wire instead of JSON gets us?
andsoitis 647 days ago [-]
> but I don't really see what sending HTML over the wire instead of JSON gets us?
HTML you can render as-is. JSON needs additional processing logic client-side.
weinzierl 647 days ago [-]
Sure, but with HTML all I can do is render it. With a well designed JSON API I can wrangle and mangle it and use the same data in many places or different apps even.
andsoitis 647 days ago [-]
Yep. In some cases it might be better to keep a local representation of the data and have different view and business logic all on the client to create a presentation & interaction experience for the user.
Other times, centralizing it on the server might be best.
Some apps lend themselves much more to doing a lot of interesting work on the client (Figma is an example, going so far as to implementing their own rendering engine, for instance).
hannofcart 647 days ago [-]
The way around this is to have a layered approach in the backend. A business logic layer which generates some data, presumably structured in whatever way is canonical for the language you use.
Then add a layer on top of that that 'renders' the same structure into multiple formats: JSON or HTML as needed.
Expose each of these view layers as a different endpoint in your service.
marcosdumay 647 days ago [-]
You can wrangle and mangle the original data much better than whatever JSON you decided to send. And you can make different apps with your database too.
the_gastropod 647 days ago [-]
Here's a pretty good essay by Max Chernyak on why using a generic JSON api to power your application's front end is a bad idea. https://max.engineer/server-informed-ui
tl;dr:
Your JSON api has to figure out:
- How to predict and enable all possible workflows
- How to avoid N+1 requests for awkward workflows
- How to test functionality, performance, and security of every possible request
- How to change the API without breaking the existing workflows
- How to prioritize API changes between internal and community requirements
- How to document everything so that all parties can get stuff done
And on then on the front-end, you have to figure out:
- How to collect all the data needed to render a page
- How to optimize requests to multiple endpoints
- How to avoid using API data fields in unintended ways
- How to weigh the benefit of new features against the cost of new API requests
He goes on to point out that the "re-use" value of an api endpoint is extremely low. You can re-use virtually all the code that produced that endpoint to produce a different one with a different structure for precisely what you need in this new use-case.
Thanks for reminding me of that page. I remember already having seen it, the memes at the bottom are hilarious, maybe I should read the essays too.
eddd-ddde 647 days ago [-]
For one thing, at one point or another you need to render HTML, why not render it once instead of rendering to json, then parsing the json to render again to html.
Also, sending json means you either need type information in two apps, OR you build without strict types in one of the ends. Either way it's more work or less resilience.
These are just two examples that focus on DX.
Zambyte 647 days ago [-]
> but I don't really see what sending HTML over the wire instead of JSON gets us?
REST, instead of what we decided to start calling REST
marcosdumay 647 days ago [-]
To be fair, we already have a name for the Web, we don't need REST too for the same thing.
Zambyte 647 days ago [-]
No definition of the Web and REST are the same.
WesolyKubeczek 647 days ago [-]
Another set of tradeoffs that we used to think JSON over the wire would mitigate. They, of course, brought their own tradeoffs.
Case in point for partial HTML updates: you update the backend in such a way that HTML it sends is no longer compatible with the frontends running in the browsers.
(You won’t believe how long can a page be open without a refresh.)
647 days ago [-]
cies 647 days ago [-]
The "JS problem" is two sided: (1) we need JS (well, not anymore, there's WASM now too), and (2) many devs do not like the DX of JS (me included).
This project, if anything, follows a JS-on-backend-and-frontend and thus is more of a promotion of JS-everywhere than a way to "get rid of it".
j45 647 days ago [-]
Simpler can be better than a more unnecessarily complex stack that could be added later anyways
647 days ago [-]
pard68 647 days ago [-]
The naive tldr:
Render the HTML server side instead of client side, then the client is only doing DOM updates.
j45 647 days ago [-]
Client side updates via livewire type tech, or even more crazy - we might be at the time where websockets can now be used for what they were meant for.
jensenbox 647 days ago [-]
I want the DHA stack - Django in place of Astro.
shove 647 days ago [-]
Round and round and round she goes…
flufluflufluffy 647 days ago [-]
ah yes, that time of year when people reinvent the LAMP stack again
Alifatisk 647 days ago [-]
I love that we all agreed on leaving this heavily bloated website / webapp architecture
riffic 647 days ago [-]
it's all Lindy and not going anywhere anytime soon
Sweet! So my J2EE and SOAP skills will become relevant again?
eek2121 647 days ago [-]
I like where the Rails team is going with Rails. No JS bloat at all, just simple and clean JS. No compilation step or anything.
lghh 647 days ago [-]
There are benefits to a compilation (transpilation?) step that are worthwhile. Most notably, types/typescript.
Everyone's bar for what is bloat is a bit different. Everyone's definition of simple and clean is different. Typescript, even with a compilation step, is simple and clean to me. Javascript without types is the opposite of simple. Javascript without types is the opposite of clean.
paranoidxprod 647 days ago [-]
I've been using JSDoc with tsserver and its been working great for development. Types from typescript are removed at compile time, so they just help with the dx around JS, but I've been noticing similar benefits just using JSDoc.
j45 647 days ago [-]
dynamically rewriting JavaScript into not JavaScript as it evolves into a full programming language is an overhead that has its pros and cons.
A build system for a simple hello world page is the example I can’t often wipe from my mind.
Reactivity in web apps has been great but around for 20 years already from its roots in Ajax.
Rendered at 10:25:59 GMT+0000 (Coordinated Universal Time) with Vercel.
I'm a rails dev and I love the framework but there's a realist in me that sees something akin to the phrase "markets can stay irrational for longer than you can stay solvent"
EDIT: typo
Hotwire is the polar opposite of spaghetti code
Following variable life cycles in Ruby in general is much harder than a typed language. There are tools like pry for this sort of thing, but that’s more work than just having types with good ide integration.
It’s underrated since devs mostly do it without thinking about it, but in enough cases you need to double-check the type before running any operation that requires a certain type. Unchecked it will either crash entirely or cause bugs so esoteric that they are very difficult to debug.
I don’t think I’d categorize it as “how Rails suffers without types”, more like “stay away from the edges and you’ll be fine”, but it can still bite you hard if someone mis-steps.
Anything I can think of will immediately throw an error or would be covered by the most basic of test suites
That’s exactly what we don’t want in production code. We want it to work without errors.
An example: assign a variable to the output of a library function, then pass the variable in to a different function. Super basic, super common.
One instance of that is calling the first function and expecting an array back but getting any one of ‘String’ (edge case that the library maintainer decided is a good idea) or ‘False’ (maintainer decided that’s what happens when something fails during the call).
If you call ‘.each’ within the second function without verifying that the variable is iterable first the function will throw. (I’ve even seen a couple rare cases where a custom class responds to ‘.each’ but is not properly iterable).
Most Ruby devs will “just” check before they call ‘.each’, or wrap the second call in a rescue block, but that’s exactly the sort of potential for misstep I’m talking about.
I think the current mania for types has arisen largely out of the js SPA crowd creating problems for themselves doing the opposite,
Simple technologies leave innovation points to be spent in the problem and user instead of experimenting with new tech that is usually a rewrite of something else that’s already similar, except without the hardening and maturation
In a one person team merging your server with your client and using HTMX can be simpler (depending on if the value is in your UX or in your logic/data).
However as the team gets larger then I find having a clear separation between your API(s) and your Client(s) is much more simple and maintainable. Also it can unblock product decisions like offline mode or PWA's.
Finally its worth stating that being in an SPA community like React can give you access to "economies of scale" in terms of the libraries available to save you time (Tables, animations, UI kits, Video players, etc.) allowing you to do more with less people.
The problem is that the SPA way of thinking has infiltrated every nook and cranny in this industry. The ratio of APIs vs clients consuming those APIs come scarily close to 1, at least with the customers I work with.
Now you have to maintain two projects, two CI/CD pipelines, two hosting solutions, potentially two sets of languages and tooling…
https://ahastack.dev/aha/2-astro/
> If you know another classic Web Application server like Rails, Django, Laravel, or like building your own in Go or whatever, you can use anything you want.
Then stress the anything part.
When only one side pays the price, I think it isn’t that surprising that it gets dogmatic. Because there isn’t any trade off, really, for me as a user, getting scripts is simply bad, and getting plain old documents is simply good. Where’s the nuance or tradeoff? I don’t care if setting up a static site generator takes more time or is harder or whatever, I only see the output, which is obviously better in one case.
In the case of web devs talking to web devs, I’m not sure, having not been in that room. But from an outsider point of view, it seems like some sites care about this sort of thing and others just don’t. Maybe which parties are included in the cost calculation is basically an axiom, not really something that can be logic-ed out, and so it tends toward dogmatism and statements of preference? (hopefully I’ve accurately represented the fact that this is 100% a comment from the user point of view, so heap of salt and all that).
This isn't that simple IMO. On one hand, JS-heavy apps take longer to load on underpowered devices and slow connections, which should be treated as an accessibility concern. On the other, approaches like LiveView, HTMX or even plain old HTML struggle on high-latency or spotty connections. A well designed SPA can cache data locally and push changes whenever internet connectivity comes back, making it feel a lot snappier in these situations. SPA apps are harder to write because you have an extra API layer, but you need one anyway if you're also writing a mobile app, so they may even become slightly easier in that situation. Every solution has its tradeoffs.
Don't these static site generators serve the scripts that you do not like? On a statically-generated site, the dynamism of the site is in the script and is evaluated in your browser. On a non-static site, the server does the evaluation, so your browser does not have to run as many scripts for the same level of dynamism.
In fairness, most of my experience in past 10 years is dealing with companies trying to fake SPA style apps in blog-style server side frameworks.
Maybe it's gotten better very recently, but Rails+jQuery mess is not better if folks really want a SPA-style app and interactions.
Among the 4 production B2B Rails apps I've been adding features to in the past year, the only one using jQuery was created 13 years ago. None of the others ever used jQuery, and using Hotwire Turbo to replicate SPA functionality is easy nowadays.
One of the Rails apps serves a Flutter mobile client on the front-end, and as much as I appreciate all the lifting Flutter does for me, the sheer amount of code required to support that is enormous and laborious in comparison to writing a few Turbo frame tags in the fullstack Rails app. If not for a few gotchas that the client app needed, that mobile app would have been done with Jumpstart Pro iOS & Android with Turbo Native (great code reuse potential).
Users of Rails apps leveraging Turbo frames or streams don't think those apps feel more shiny and cool and performant than legacy SPA frameworks such as React, and the modern Rails developers spend less time churning out code.
Most of my own custom work plugs in to the old school PHP server side rendering and that works just fine. I also have what's in effect two separate SPAs in the backend. Doing these in htmx and Alpine or whatever would be an absolutely enormous headache and it would perform worse. There's no one size fits all.
People love arguing over nothing instead of picking a stack and shipping.
The most valuable code is the code that runs in production.
It’s important to think about the right solution, and it’s also important to know when and why you’re putting something into production. Golden mean and all that.
[1] https://kit.svelte.dev/docs/performance
I haven't played with Astro much, it looks quite sane, but oriented more towards content-heavy sites vs webapps.
I started web development just 2 years ago using React and at the time I didn't know any of the traditional frameworks like Rails, Django or Laravel. I learned Rails recently and have been using it for my side projects since. I'm having a great experience!
When I see the headlines praising a frontend framework that's been around for < 5 years, I roll my eyes. I imagine it's been written by someone like me 2 years ago, who hasn't used traditional frameworks.
Then I moved to doing all my projects with Astro/Svelte and webapps with SvelteKit. I was surprised at how good and fun it was. The templating languages less esoteric, more integrated. Reactivity was something I never even dreamed of with a hard line on JS. All the while, the websites got better. I could finish them more quickly and there was still no or a miniscule amount of JS shipped by default. I could also, when making a content-driven website with Astro, easily reach for Svelte for a small bit of interactivity / reactivity. I could've just as easily used Alpine or whatever else someone might recommend.
That's to say, I've found a comfortable DX in current-gen JS frameworks, while finding the server-side giants a bit too sturdy for my use. Reading about new frameworks is fun to me, because I can easily switch from Svelte to something else on my Astro sites, if I find something that fits my tastes even better.
I don't get excited about learning a new frontend framework because I'm fairly certain it won't allow me to do something new. It may be more convenient in terms of syntax or have fewer client side code being shipped, but it doesn't enable me to do something in terms of functionality I couldn't already do.
I would prefer pick one framework and get better at it, rather than learn the templating language of 5 frontend frameworks.
I'm not sure that's true. Time has went that direction, for sure, but I don't think historical backend web devs have migrated to react. Mostly front-end devs expanding their horizons and younger devs starting there.
Really? Back in the day, myself and my peers weren't "backend web devs" we were just web devs. Stuff started shifting to the frontend and we all learned Backbone, Angular, React, etc because that's the way the industry went. I think a LOT of us migrated to React, maybe not completely, but who can call themselves a web developer these days without at least some experience with FE frameworks?
I still really limit my JS to just improving the client-side UI/UX.
I love that people are pushing back on the SPA architecture everywhere (though SPAs are still the right choice for some apps). Some people are pushing back like you (returning to backend renderering), and others are pushing back like the implementer/poster by trying to extend the original intent of REST architecture (not JSON apis the term has come to mean).
I think the htmx architecture is brilliant, though it's not something I would use for the majority of my projects (it doesn't fit the use case).
I think what folks who have come to web dev recently don't understand the historical tradeoffs that led to SPAs or the current web dev ecosystem. It was terrible to build websites, but it was worse to build cross-platform applications using the existing tools and delivery systems. The browser solved a lot of that, and SPAs were an attempt to upgrade web architecture to support that need. People forget the positives because of how ubiquitous they've become and only look at the negatives.
I'm glad we're moving away from the SPA-only world, but every web framework that we use nowadays has been influenced by the advent of node+SPAs
I've worked with countless younger junior engineers who know React reasonably well, and largely think Rails is old "legacy" crap they don't want to deal with. And to be fair, using Rails as a dumb JSON api does disrupt much of the convenience of using Rails. But I never understood how people could so under-appreciate the tooling and structure that Rails provides.
12 years ago Rails was just as hyped as React is now. In a few years junior devs will be pooh-poohing React the same way as they are doing to Rails.
It's not easy to explain.. but imagine if a user loads your webpage. Then the web page loads your assets are loaded (JS, CSS, etc).
Then imagine a new deployment happens that introduces new styles and/or HTML for a given resource.
The page that is loaded in the user's browser does not have the new styles and doesn't know they were updated. If the user interacts with the resource the page styles will break.
This was fixed in Turbo and Turbolinks by introducing "data-turbo-track="true"" to a resource like a CSS sheet. When the server responds with a fresh page the head can be compared and a full reload can happen if the asset was updated.
In HTMX, the page is just broken.
edit:
Currently, you would have to manually hack around this... like long polling for the current app version or returning it in every XHR request and adding a middleware to HTMX to do the check and pop up a "your page is out of date..." message.
https://htmx.org/extensions/head-support/
for htmx 2.0 i'm integrating this functionality into the core, it seems useful enough to be there. The extension is based on the head morphing algorithm of idiomorph:
https://github.com/bigskysoftware/idiomorph/
which 37Signals is going to integrate into Turbo for v8:
https://twitter.com/ben_pylo/status/1717975035669876790
[1] - https://htmx.org/essays/locality-of-behaviour/
A cleaner approach may be leveraging the HX-Trigger response header in some way? I feel like the app version could be specified and if it changes, HTMX would know and could trigger an event that could be specified by the user.
I don't really like either solution.. perhaps the head merging would be more correct, but damn it feels off =/
- a full page request via an hx-boost, where head processing makes sense
- a full page request via an hx-get, etc. where hx-select is used to pick out a piece, where head processing probably doesn't make sense
- a partial of HTML, where head processing doesn't make sense
we will optimize head support for the first case, hx-boost based requests, and make the latter cases possible via configuration if the user wants.
htmx is much less opinionated than other frameworks on these things, i try to make it a hypermedia swiss army knife, which makes it a little ugly at times, but I don't like forcing people to do things a certain way for better or for worse
using HX-Trigger to do a full page refresh on an application version change is a common pattern, but is something you would build on top of htmx, not something htmx would provide out of the box. it is focused on generalizing hypermedia controls and patching a few gaps in HTML, and that's about it.
Where's the issue? I can see you getting into a pickle if you don't bundle mutable resources, but that's why you should.
A well made SPA can work offline and doesn’t have most of the typical disadvantages with respect to routing and redirects.
That being said, people should obviously use what they prefer. It’s interesting how these things have become a sort of holy war.
HTML you can render as-is. JSON needs additional processing logic client-side.
Other times, centralizing it on the server might be best.
Some apps lend themselves much more to doing a lot of interesting work on the client (Figma is an example, going so far as to implementing their own rendering engine, for instance).
Then add a layer on top of that that 'renders' the same structure into multiple formats: JSON or HTML as needed.
Expose each of these view layers as a different endpoint in your service.
tl;dr:
Your JSON api has to figure out:
- How to predict and enable all possible workflows
- How to avoid N+1 requests for awkward workflows
- How to test functionality, performance, and security of every possible request
- How to change the API without breaking the existing workflows
- How to prioritize API changes between internal and community requirements
- How to document everything so that all parties can get stuff done
And on then on the front-end, you have to figure out:
- How to collect all the data needed to render a page
- How to optimize requests to multiple endpoints
- How to avoid using API data fields in unintended ways
- How to weigh the benefit of new features against the cost of new API requests
He goes on to point out that the "re-use" value of an api endpoint is extremely low. You can re-use virtually all the code that produced that endpoint to produce a different one with a different structure for precisely what you need in this new use-case.
Also, sending json means you either need type information in two apps, OR you build without strict types in one of the ends. Either way it's more work or less resilience.
These are just two examples that focus on DX.
REST, instead of what we decided to start calling REST
Case in point for partial HTML updates: you update the backend in such a way that HTML it sends is no longer compatible with the frontends running in the browsers.
(You won’t believe how long can a page be open without a refresh.)
This project, if anything, follows a JS-on-backend-and-frontend and thus is more of a promotion of JS-everywhere than a way to "get rid of it".
Render the HTML server side instead of client side, then the client is only doing DOM updates.
https://en.wikipedia.org/wiki/Lindy_effect
Everyone's bar for what is bloat is a bit different. Everyone's definition of simple and clean is different. Typescript, even with a compilation step, is simple and clean to me. Javascript without types is the opposite of simple. Javascript without types is the opposite of clean.
A build system for a simple hello world page is the example I can’t often wipe from my mind.
Reactivity in web apps has been great but around for 20 years already from its roots in Ajax.