Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Reimagining front-end web development with htmx and hyperscript (hashnode.dev)
212 points by mpweiher on July 1, 2022 | hide | past | favorite | 207 comments


Using html (and tailwindcss) have been the major productivity gain in web front-end development for us.

The speed on the UI is noticeable for our users (a lot of underpowered androids!) and the interactivity is equal than our prior vue version.

React/Vue is like Nosql: Good for certain niche scenarios but overkill for most use cases. Plain html/css is pretty performant and so easy to do than duplicate the state (+validations, structures, routes,...) between client/server.

So, if you are on the fence: Just try it. Is very likely it will be FAR simpler than you imagine!


I second tailwind as the way, and I'm using it along with web components. I think the important aspect of React/Vue was to inspire Web Components to exist. Now that I can leverage Web Components, I don't see a real need for React as the browser is very capable.

For me, I'm building https://www.adama-platform.com/ which is a reactive backend which then makes building reactive/interactive applications very simple.

With tailwind, I can just copy and paste HTML snippets and make it live with data. So much fun!


> Now that I can leverage Web Components, I don't see a real need for React as the browser is very capable.

Except for the long list of issues that WC proponents pretend doesn't exist: https://twitter.com/Rich_Harris/status/1198332398561353728


>Except for the long list of issues that WC proponents pretend doesn't exist: https://twitter.com/Rich_Harris/status/1198332398561353728

This is the sad reality for web components. You end up needing so many libraries to do basic things that a framework would handle, that your project just becomes a defacto custom framework.


Damn, now I have to pretend those don't exist. I have to investigate how it breaks a11y as that seems to the the core killer in my case.

How does that list square with https://shoelace.style/ ?


The linked tweet in the linked tweet gives one such example: https://twitter.com/sarahmei/status/1198069119897047041

I remember there being more, but I can't remember the links off the top of my head (and on mobile).


Alex Russell introduced Web Components in 2011. React was released in 2013.

Web Components originally used a view-model architecture, which I would guess was heavily inspired by the most popular JS framework leading up to 2011: Backbone.

React was a massive departure from Backbone, and sadly the Web Components spec was developed before React had matured and changed the landscape.


I think it was Angular.js the framework that made us jump from JQuery to the modern way to do things. Backbone was never that popular.

Angular.JS was created in 2009 and released in 2010.


Yup good call, Angular.js seems more likely than Backbone now that you mention it.


Thanks for the correction


> I think the important aspect of React/Vue was to inspire Web Components to exist

Web Components predate React as an idea, don't they? Admittedly it too hella long to get them properly standardised.


React as an idea predates React too ;-P


Sorry to say but you should brush up your UI on mobile firefox


I started as a front-end developer, so doing lots of Angular, React and Vue. But over the past few years I've transitioned back to plain HTML (or at least templating on the server side), and I find it so much more enjoyable and much faster to developer as well. I don't have to constantly switch between front-end/back-end, having to build APIs, just so that my single SPA can consume them.

Although I really miss the flexibility of of React/Vue components that can take different parameters, and have rendering logic inside them. jinja2/pug and the likes, just don't have that.


> Although I really miss the flexibility of of React/Vue components that can take different parameters, and have rendering logic inside them. jinja2/pug and the likes, just don't have that.

What is Jinja missing here when it has variables and logic in templates? You mean the rendering logic is less powerful so the template file alone can't encapsulate all the logic?


I do find the rendering logic less powerful, I know that in Jinja you have includes and macros, but I miss being able to extract specific logic to methods. I also like being able to use the language that I'm working in, to write extra logic in my templates, in React that would be JSX.

With Jinja it's this "weird" syntax that's completely different from Python and HTML. If that makes sense.


I really think components are an incredible innovation, and I'm constantly shocked that mainstream backend template systems don't have them. Some are beginning to, e.g Laravel's blade.


I feel the same. I tried playing around with server-side JSX in Deno and HTMX. JSX seems like a good solution for backend components, esp. since it's more suitable for reusable smart components with logic or data fetching and not just "dumb" templates.

https://github.com/dsego/ssr-playground/


What are the innovative parts of web components, which have no equivalent in lets say mainstream OOP, lumping state and behavior together?


Oh I didn't mean innovative in the broad software landscape. I may have spoken a bit too emphasically. I just meant to compare them to their direct competitors, e.g. Jinja style server side templating.

The best part of component-based templating to me is not when it resembles OOP, but when it's functional. Components as functions with all that entails (scope, most significantly) is a step up from the very procedural, preprocessor-style template engines.


Hm. I see it exactly the opposite way:

A template renders the same every time, given the same input. Rendering a template is like a function. It encourages people to put their logic elsewhere (separation of concerns) and first get the data they need, to only then render the template. Templates are merely views.

A web component in contrast has internal state, which it mutates, or at least can have internal stage and often does have such. Also it relies on global state, which is accesses. It seems to me like a step down from preprocessed templates, because state and behavior are lumped together again and because of internal mutating state. The view layer is no longer cleanly separated.

In practice the resulting DOM often is more convoluted and styles are defined in less obvious ways ultimately on the website. It makes writing user stylesheets and user scripts harder.

You can re-use web components, but realistically every projects adapts or writes their own component anyway and you can only re-use for the same framework or one based on the framework, for which the component was written. Re-use of components seems even less than it was for "my classes from the other project" in OOP, because not only does one have language specific classes, but framework-family specific components.

While not directly necessary for web components in general, I also find that syntax annoying, which mixes some kind of HTML look-alike with JS blocks inside of it. Kind of a reminder of PHP outputting HTML, which contains PHP blocks, which output JS, which modifies HTML. It is also annoying, because now I have to learn an HTML look-alike, which has new rules about what may be nested into what and those rules do not always make sense. I cannot nest as freely as in real HTML. What I write in a web component is not what ultimately gets output, but instead if will be translated at the end of the process. In a template I would simply write my HTML and compose them in such a way, that I have separate templates for semantically separate things, enabling re-use of templates. It is easy to do and the code is real HTML, no need for any indirection of translating a look-alike into ultimately HTML again.

Seems to me, that many lessons of the past have been forgotten.


This doesn't seem like a fair comparison, when I mentioned components, I wasn't referring to their state, or two-way bindings, I was purely referring to their templating methods. This also leads into my point about the syntax, they write just like regular HTML, just with a custom tag and custom data attributes. Since I'm already writing HTML, I really prefer this.

My point about JSX was also mainly related to that, since I'm already using TypeScript, I can just continue to use that in my rendering logic. Or at least, the logic reads like any programming language, not this psuedo-like syntax.

Jinja/pug/handlebars and the likes, have their own templating language, which is always different from the programming language you're already using. And I personally don't find HTML that difficult to write, that I need to compile into it.

So what I would like to see, is a templating language (such as Jinja/pug/handlebars), but that uses plain HTML, with the ability to use JSX and write custom components (that will just output plain HTML). I don't need any of the state mangement or two-way bindings.


In many Scheme dialects there is SXML, which looks just the same as normal Scheme code and actually also is normal Scheme code. You simply nest HTML tag names like so: `(div (p "here is my text" (span ,(calling-my-own-function-for-some-text)))) This builds up a tree structure, which ultimately gets fed into some function, which transforms it into an HTML string, which is send to the client. Before the transformation you can treat the tree just like any other tree, avoiding to have to parse anything. You can for example recursively search for something to pattern match on and transform in arbitrary ways.

The thing is, that it requires the developer to have some disciplin to divide view from the logic behind it. Simply make a folder called "templates" and put your Scheme files containing SXML stuff in there. For disciplined developers, this works well. In Scheme this works well, compared to for example PHP outputting HTML, because Scheme code in general has a tree structure already and as such an expression can be transformed into an HTML document. No need for any additional language like a templating language, but also not making the mistake to treat HTML as mere string, like PHP does.

JSX kind of treats its HTML-look-alike as a string as well, kind of. In the code you have a backstring wrapped string, which is processed later. There needs to be an additional parser for that, which performs the magic behind the scenes and checks the nesting of elements, allowing JS blocks inside that "template string". No such additional parsing is needed in SXML. Given the mere string before processing it into some internal tree, which is hidden away in the machinery processing JSX, I cannot simply transform the tree it represents, because it is merely a string. I would need to make use of JSX processing tooling, to get an actual tree and work with that. That might be possible.

The only advantage JSX has over SXML is not one, which stems from JSX itself, but from the fact, that JS runs in the browser and as such can run on the client side. If that were not the case, JSX would simply be worse in every way, forcing people to learn another language. Another language, because what one types in JSX template strings is not actual HTML, but something else, which has new rules about what elements exist, how elements can be structured, what attributes exist ("class" ...) and how elements can be nested, without receiving a type error. All that could be avoided, if we had something as elegant as SXML in JS. However, I am not sure, whether it is even possible to have something like SXML in JS. How would one go about quasi-quoting and unquoting? I don't know.

I would actually prefer to simply use JS objects to express the HTML document, so that I can work with them like with any tree. There could be magical attributes, which you can assign some closure to, so that it gets the dynamic behavior like in JSX. Not sure any framework has gone that way. It would be cleaner than inventing an HTML-look-alike and it would allow for more efficient processing, since it does not have to be parsed again, before outputting HTML.


How dare you call your users underpowered androids!

I’ll see myself out now


If I ever have a web application that I expect _could_ be revisited to add more functionality, next.js is the go to. It's performance on the user end is great, though I would be interested in how it does in the underpowered android scenario. Nevertheless it's hard for me to imagine feeling good about needing to add a feature on a plain Js+html project


This is what makes Svelte so fun and appealing for me. It’s just html with script and style tags… with optional superpowers if/when you need them. And automatically scoped styles, optimized bundles, SSR, and all the DX / UX boosts you could want!


So, your scenarios are mainstream and what React/Vue devs do is niche?


> React/Vue devs

devs probably not (ie: as NoSql, Kubernetes and stuff, some people pick overkill things, and by some I also mean me!), but React/Vue as libraries, certainly!

A SPA is a niche among the most mainstream web site. It makes sense when the interactivity is BIGLY on the cliente (like for example: A paint app).

But most things on web are not 90% client vs 10% server. Is the opposite.

Your todos, mail client, eCommerce site, blog, etc are better served with a server-side approach (note also how much important security is on this kind of apps!).

Your screen that display an interactive map, your game, paint app must certainly need a more client-first approach.

But as SPAs says: Is a "SINGLE" app. One.

Is your full app ONLY ONE? No? Then you are not in the niche, and if you actually have that SINGLE screen/app is likely a fraction of the whole thing.

---

Another possibility is that single thing consume so much that you say, screw it, lets do the rest similar even if is a poor-fit, but I think that is rarely if ever the best (for the users!). This is what drive adoption, React/Vue solve nicely some hard stuff and naively you think is great for the most basic one. But as show the fact that stuff like "back button" get broken without EXTRA workarounds is not the best fit for them...

P.D: Is my opinion -after try for years do the opposite!- that the majority of the web apps be server-driven and maybe add a little of react/vue/alpine for extra nice touch...


I decided to become a server developer as opposed to front end to avoid the js ecosystem meltdown... however I see server side tools like kubernetes have also become so ladened with exposing complexity we too find little time for actual creative development

watching a time lapse of a single biological cell develop for it's first few hours reminds me of the software tooling landscape... throbbing, twisting, shaking, bifurcating


What? Dont you like to learn 3/4 almost-useless DSLs, have to modify 3 config files for the smallest change and plumb more breaking things than Mario?


Mario doesn't do any plumbing.


It’s-a-me, the SRE!


It solves a lot of scaling problems though


> It solves a lot of scaling problems though

Problems that most devs wish that they had but don't.


Infrastructure as Code is powerful; Terraform + k8s (with nginx-ingress/cert-manager/external-dns) and you never need to worry about infrastructure again...


At $work we use(d) the following:

- Heroku

- AWS ECS Fargate

- AWS EC2 (AutoScalingGroups) + Docker

- AWS EKS (managed K8s) + Helm charts

Everything (except Heroku) is/was IaaC.

They are listed in the ascending order of how many problems they cause, and how much we have to worry about them ... I will never ever touch K8s if I can possibly avoid it.


At my last job, heroku was the cause of at least an outage a month. The redis add-on was particularly troublesome, as I recall.

That's not to say the rest aren't bad, of course, but I'd much rather have control in my hands than wondering if the next time it goes down again how many angry phone calls we'll get and if there is even anything we can do about it.

Give me a few bare servers any day, but you take what you can get I guess.


Yeah, until your team starts using PaaS services and your terraform modules are a mess that barely supports a third of the product's configuration, and that process is going to accelerate more and more over time.


So does a beefy server and a nicely parallelized backend service.


Problems that most of Kubernetes users don't have, and could have been solved with some unfashionable 2/3 servers and a load balancer.


Which 99% of users don’t have and never will


You don't have to use Kubernetes. Simple webservers and FTP and SSH still exist.


No need to go back 30 years.

If doing professional work, use heroku, App Engine or any similar PaaS solution.

If doing hobby/side projects, Dokku is a great self hosted heroku alternative. Easy to setup and use.

Kubernetes is a very low level tool. If you want to run it yourself you need s full team of infra experts to not fuck it up. So I think it could be a great tool for large companies with many teams and a lot of money.

As usual the problem is not taking into account context, and single developers or startups thinking they need to do what google does so they go full Go microservices spa Kubernetes crazy. Add some of the Agile bullshit on top of this and welcome to your average startup nowadays.


I'm doing both professional and hobby work with VPSs and SSH and there is no problem with that. Few less layers to take care of


What about backups? What about the vps going down? What about upgrading the server? What about security updates?

Professional work on VPS is either a lot more work, or not that professional. If it is not being a lot more work then you're not providing the same service, security and guarantees to your customers.

This is where PaaS shine. Easy and safe. And if you factor in your own time, then cheaper too.


All of those problems have nothing to do with using a vps.


Yes, they do. You get these "for free" with any PaaS. You have to do it yourself with vps or custom in house kubernetes.


Thing is, as a startup, there might be better solutions to your problem than Kubernetes, but investors specifically look to check the „use K8s“ checkbox on their rating sheet. It’s just as stupid as it sounds, and there’s nothing you can do if you need venture money.


To add to this, one could also learn Erlang or use kubernetes alternatives like Nomad, which, last I checked, has had less levels of abstraction than kubernetes.


All my stuff is fairly simple AWS via CDK, plenty of time for creative dev. But I do agree, k8s is not a requirement.


I’ve helped people use Kybernetes for quite a few things, but I can’t help but notice that there is even a policy agent that allows you to write rules in JavaScript now. There is a minimum level of complexity when you use Kubernetes, but there seems to be absolutely no upper bound.

https://www.jspolicy.com/


Its funny to me how all these people who learned js/react (bootcampers/"fullstackers"?) before html are now discovering html. as a web dinosaur like me (15 years) i've watched this whole cycle play out.

not that js/react are not useful, but rarely should be your starting point. much better to use them progressively when the trade off are worthwhile.


I don't think it's funny, it's sad, and i think it s fueled by overvalued tech sector that no longer seeks to innovate but is stuck rearranging the chairs. I can offer the major redesigns of pretty much any online service lately as an example of making an app at times worse than it was before, just for the sake of change.

As a (bad) side-effect, people have stopped creating amateur websites, because it's hard. HTML was easy and fun, and everyone wanted to create their own geocities monstrosity. I'm looking at modern web constructs like WebXR with disbelief: How is it an hypertext standard if it doesnt even involve html tags (it's just a rehash of openGL , but in JS??). Why dont we make it easy for people to make quirky stuff anymore?


You can create an amateur website in exactly the same way as 20 years ago. Is it that hard? It's hard perhaps to step back and just play with web tech if you're indoctrinated into the modern development hellscape, but I don't see any reason you can't be ftping html files into a www directory to your heart's content if you really want to.


I think one of the biggest issues now is for peopling learning is if you just search “get started with web development”, the very first result says “Pick up a Frontend Framework.”

Newbies are immediately plunged into the world of npm, react/vue, and AWS.

Gone are the days where the tutorials are “write a page in HTML and FTP it on to a server”


you can't because everything you might want to embed/add now asks you to either use npm or something of the sort. I can't even find ways to 'just' download JS in libraries lately. In my example, suppose you wanted to add a 3d panorama with a-frame (easiest way), here is the installation:https://aframe.io/docs/1.3.0/introduction/installation.html


I think that's just a poorly written doc that doesn't explain the tradeoffs for each approach.

If you don't want to deal with the tool chain, just go straight to the "Include JS build" section. That one line script tag is all you need.


I have chosen Hugo as my new static page generator.

Markdown and restructured text are both easier than HTML.

Very fast, easy to use, me gusta.


I just look at the installation instructions

https://gohugo.io/getting-started/quick-start/

easier than HTML, that a lot of people learned in school and with which people interact daily? no


I am one of those people who started reading a book on HTML when I was 10. I didn't understand a lot, but kept reading again and again and with 13 I understood enough context to create HTML websites.

For most projects I have been doing since it was either pure HTML, CSS wirh a few sprinkles of handwritten Vanilla JS, or Jinja2 templates with occasional PHP. When it got really complicated I used Flask or Django.

But to this day I never understood people who use js/react for pages that could have been handwritten with zero js in half a day (including a handwritten fluid CSS layout).


> But to this day I never understood people who use js/react for pages that could have been handwritten with zero js in half a day (including a handwritten fluid CSS layout).

I think people tend to improve their knowledge of some specific tool/language (JS in this case) and wanting it to apply to everything, not just what they initially learned it for and even if it might not be a great fit.

If all you know (because its what the schools/bootcamps teach) is generating HTML via DOM operations in JS, you might not even know better/simpler ways of doing it.

A bit like if someone just knew C and haven't really explored other languages/environments, then they might think that building a server serving HTML is a great thing to build in C, rather than using pre-built tools that serve static files or even using a safer language.


HTML is hard to compose (as in composing a page out of modular components), reuse (your toolbar everywhere has to recreate a bunch of components, like the nav section, logged in state, etc.).

Sure you can do that with server-side templates, but it's more readable (especially in a team) to use React components.

For me the main benefits of React didn't really shine until I had to maintain complex state and component trees among multiple devs. What is overkill for a simple blog is an absolute godsend for more complex apps.

Although frankly I still think Angular had a much better architecture, and I'm kinda sad React took over. But hey the frontend landscape gets a revolution every year or two (sigh) so who knows what the dominant paradigm will be by 2024.


I still don't get the love affair with CSS in JS. It defeats much of the purpose of CSS.

Also, my idea of a FE component is that of a class. A black box if you will. It the markup structure with the details as properties. Reusable because all properties are set from outide.

If you're hardcoding CSS within the "component" then it's not a component. And then having to effectively rebuild the entire app because a hardcoded bit of (Tailwind) CSS needed to he changed?? That's a step forward?

From a professional / career stand point I'm interested in React. But its model of thinking feels like 1999 in some ways.

I'm missing something? What am I missing?


The CSS in js components can be fully reusable between compatible frameworks, without any wiring of separate CSS files, and can also utilize theme configuration. Also just like how jsx is a form of html in js, having your style definitions in the same place makes it a lot easier to immediately grok what the component does and how it will look


Not if that CSS is styling (unique to the project). Once it's "hardwired" you have to rewire it to use it again, or worse...if the styling changes you have to rebuild. In the context of CSS's intention, that's an anti-pattern. Yes, people do it. But that doesn't change the anti-ness.

If you're editing the actual components then that's a step backwards in time. They should be like (OOP) classes. Completely agnostic. Completely "decoupled". They should be the structure (i.e. markup). But the styling should be abstracted out into "real" CSS, not inlined hardcoded CSS.

Put another way, for all intents and purposes CSS in JS is like using important!. Nuff said.


As a react dev, I don't like CSS in JS either. It brings back the old font tag approach of individually styling components.

As an alternative, you can just assign class names to components and use global CSS like the old days, if you prefer. Sass is pretty great, basically CSS with better selectors and variables.


Exactly. Something like Tailwind should be done in the Sass, not by assigning a gazillion helpers.

Have a component-type class in the component then use Sass to configure that with helper properties (read: functions and mixins, etc.)

But hardcoding? Inline? I did that in 1997.

Keyword in. I know TW is done with Sass


I'm building a simple page. Ok let's do simple html. Now I need popup for email capture, ok add a bit of hacky js. Now add a menu, could potentially be done with css only.

Now add responsive images. Good luck. You need to process then on server side, then handle them on client side etc...

Now add some customer area...

Add a few more features and it becomes complex.

Why would you want to now throw away all this and rewrite in react when you could just start with react.

In addition I can even migrate my old app to the new one and sometimes I can just copy paste certain components and css styles (thanks to css in Js) and it just works.

Honestly I don’t want to write responsive images manually. I just wrote a system once, now any app reuses the same thing. Same for other stuff. Plus I only need to know react and I can build anything.

You telling me now to learn htmlx syntax and use it sometimes, then use react other times just because… it’s simpler. The benefit is minimal, but now I need to know 2 worlds: react and htmlx.


Not meant as a criticism, but if this is the way you build websites, you are doing it wrong. If you are building a website in a way where you can not anticipate beforehand what will be needed a few steps later because you skip the one most essential step — the planning phase — you are gonna have a bad time.

Of course customers change their mind constantly, which is why you anticipate this in you choice of architecture to leave some wiggle room. The scenario you described tho: I never even remotely had a situation where it bit me in the arse that I wrote HTML with JS sprinkled in. For more complex stuff I have flask, django, websockets, htmx, custom REST-APIs I can built in any other language interacting with custom JS on that webpage (most of the software I write is server side). Or I could just take something like Grav CMS and write a custom Theme and some plugins for it. What is a good starting point depends on the kind of website.

There is so many ways to skin the cat it is not even funny. And if you don't know what cat it is beforehand it is your fault for not asking.


You are not going to be promoted if you quickly build something using simple tools. Complex and overengineered systems is where the golden opportunity is.


I just want to thank you and also chime in. I'm not even 40 years old and all this frontend crap from the last decade or so makes me feel old. I started learning this webdev stuff from an HTML book in the nineties. A time when 'frontend' meant HTML and CSS, and maybe some plain JS.

I'm not here to piss on JS frameworks, it's good that devs push the limits of what's possible, I guess. But there's something to say for simplicity and stuff that's so matured that you can really rely on it. Making sound decisions for your product, your stack and your architecture is a skill.


As someone who's a similar age, I wonder if that's a bit of rose colored nolstagia? Sure, these days the JS ecosystem is incredibly fragmented.

Back then it was CSS that was so rapidly evolving nobody could keep up. Remember the ACID tests? And that was even before flexboxes made things both simpler and more complicated.

Then there was the streaming wars, where RealPlayer and Flash and ActiveX and whoever else competed to be able to deliver <video>.

And what we solve now with CSS layouts and React components used to require frames and iframes and sprinkled JS drop downs that spoke to ColdFusion templates served from a single old Apache instance shared between a thousand users and constantly crashed, and https cost like a thousand dollars and couldn't be used internationally...

The web was never simple. We were just younger then and our neurons weren't so degraded yet. /sigh


These new technologies allow me to build websites about as fast now as I could build applications 25 years ago with FoxPro.

The HTML and CSS from the nineties require about five times more work just to get the same results.

This is progress.


> making sound decisions ... Is a skill

I agree! It sucks that most jobs don't care about paying for that skill though.


The author is a backend developer whose tech stack (as described in his profile) is:

  C#
  Python
  C++
  Django
  Git
  Jenkins
  Docker
  Kubernetes
Also sort of a web dinosaur here (remember when VRML was supposed to change the web forever?). Even today 90% of the web is static pages with JS sprinkled on top because much of the process of creating that was automated years ago. Contrary to popular belief people aren't actually that generous in their usage of SPAs because it's expensive.

Also while React has the highest market share, it's not the only framework out there.


What's really saddened me isn't so much the inevitable change in tech stacks, but the incredible centralization of websites. There isn't really meaningfully a "web" anymore. For most people the internet is just FAANG and that's it. Indie sites and good personal projects are totally gone, replaced by click bait and Medium SEO spam.

It's just a corporate hellhole now, with Facebook owning the frontend via React, Google and Apple owning the hardware, and Amazon owning the network.

I miss those one person passion project pages that you used to be able to find on Yahoo.


It feels weird to read this on HN, where a sizeable fraction of the links on the front page often go to websites built by internet randos.

If you're talking about web sites as art projects, there are communities like that although they are fairly small. Neocities is one of the more prominent ones.

The small web still exists, but you have to stray quite a way off the beaten path to find it.


I don't mean art projects per se, but websites about some personal project that isn't tech or engineering focused. Somebody's story, or esoteric research thing, or personal thoughts on a random topic, etc. These days that sort of stuff seems to be in reddit or Facebook or other curated communities, not really on the web as individual pages.

Like most content is now controlled by, what, 5 to 10 corporations?


I think this web is still there somewhere, it's just that in the meantime FAANG et consortes started expanding at an exponential rate, so on one hand there's a lot more web out there, on the other the fraction of it that looks like the old web fell drastically.


I think the “web” is still very strong, but it is now extremely commercial. If a person wants to create a website these days is mainly for business purposes. Pretty much all other uses had migrated to the FAANG (or MAANG, rather).


>as a web dinosaur like me (15 years)

2022 - 15 = 2007.... Which means you aren't even in the IE era. Hardly a dinosaur if you ask me :)


Something it took me some time to understand, and I feel very dumb for that, is that with these modern "SPA" tools such as Next, you can still do quite easily dumbed down non interactive websites that do traditional form posts. It works perfectly fine.

The other way around, using the dumber tools and trying to do highly interactive apps, is a lot harder.

That might be part of the reasoning most things are nowadays built with these spa like frameworks.

Not that I agree. Just trying to understand.


I don't know, sometimes doing very simple concepts in modern SPA is much harder than with traditional technologies.

Have you ever had to debug non-functional SSR in React or Next.js? I very much doubt SSR is simpler than plain HTML or PHP or AJAX.

After all, SSR is just rendering plain HTML. It doesn't have to be that complicated full of gotchas and quirks like it is in the React world.


But Nuxt/Next SSR is not "just rendering HTML". Funny how htmx threads always revolve around largely dishonest arguments.

"I very much doubt SSR is simpler than plain HTML or PHP or AJAX"

What does that even mean?


Correct - SSR the way Next does it is basically the same as HTML+AJAX but simpler to reason about as an implementer and, if you use Typescript, type-checked and far less likely to be buggy.


Yes, I agree. The "minimum complexity" is way higher this way, even for simple things.

But my fear is that when things get complex in the frontend, at some point there is a peak point at which these tools become easier and the more traditional ways more difficult. And it is not easy for me to day where that peak point is.


It's possible to agree with or refute you based on the definition of the definition of "highly interactive apps". But I can qualify it this way. If htmx (maybe with hypertext or alpine.js) is enough for your app then I would say it's much easier to do it with htmx than a js framework. The frameworks come with the kitchen sink and are not trivially easy to even keep running due to node updates, bundlers etc. They are also very complicated and as with every framework, you start to see the limitations as you start doing more complicated stuff or go out of the happy path. Another way I can qualify it is, I can write a semi interactive website with htmx at my current experience level with Javascript but I can't do that with most frameworks. Where you are probably right without qualification is when the programmer/team is already using said framework and has experience with it.


An issue with Next is that it still loads a complete React app after delivering it pre-rendered.

Astro might solve that with selective hydration.


the js ecosystem is built on romance. what this article describes is not even the tip of the iceberg for a large application.


The JavaScript ecosystem is insanely successful, even though the language, node_modules, and the entire process of building a SPA are disorganized and clearly poorly designed. What makes it successful though is those flaws exist because individual developers in aggregate have decided that they’re worth the trade off. All the JavaScript killers seem more precisely designed, but that’s only possible because they haven’t been shoe-horned into thousands of different use cases they weren’t meant to solve. Those edge cases add complexity and rough edges, but make for a more practical toolset in the long run.


For a large interactive single page application you probably still want to use React/Vue or similar.

But for a small, simpler app, maybe one you are working on alone, only having a “backend” is appealing.

I’ve been using Alpine on a project recently and removing the overhead of a frontend to manage has made progress faster.


great article showing how htmx and hyperscript can play together

i know they aren't going to be everyone's cup of tea, but htmx is a pretty pure take on "what if HTML had kept going as a hypermedium", generalizing the various limitations currently placed on HTML. htmx stays within the original, REST-ful model of the web, exchanging hypermedia with the server in a way that is extremely compatible w/ Roy Fielding's description of the web architecture.

hyperscript is an event & DOM oriented scripting language, based on HyperTalk, the old scripting language for HyperCard. definitely not everyone's cup of tea, but it fills a need for a general, event oriented language that is easily embedded directly in HTML. This complements htmx really well in many cases. hyperscript is definitely much more speculative, but it has some pretty interesting features, such as async-transparency: https://hyperscript.org/docs/#async

anyway, it's a different take on web dev, but I'm glad to see some folks running with it and I'm happy to answer questions


I miss hand-writing webpages in Notepad and then FTP'ing them to the public_html directory on the server to make them live. The amount of infrastructure, libraries, build tools, pseudo-languages, etc layered on top of each other some developers/orgs use to make a simple form today is crazy to me. It also feels super fragile: deploy a website today, come back to it in 5 years to make some changes, and half the tools and libraries you need will be gone.


In 5 years? I think you misspelled weeks here.

Last six months with my last employer I spent immersed in the full Next, React, Prisma ecosystem. I swear that 80% of developers' time was wasted on fighting compatibility issues. Actual work happened in the small crevices of time left between endless stream of build breakages or chasing random bugs caused by changes in transitive dependencies.

My God, never again.


I feel like es modules have killed javascript. They have enough momentum that everything supports them (or needs to support them). But they’re not good enough, or compatible enough to actually integrate well.

Recent example: bundler X insists on import statements including file extensions. But the typescript compiler refuses to let you import foo.js and won’t rewrite an import of foo.ts to foo.js when you build. There’s giant GitHub issues about this but nobody wants to fix it on their end. In short, everything is awful.

Writing javascript in the browser used to be just the same as nodejs, with the exception that you needed a bundler like browserify - which mostly just concatenated everything together. Now I dread setting up new projects. Will typescript work with svelte? Will this webassembly module work with rollupjs? Will it pull in my type definitions correctly? Will the url path system magically work or break? Urgh.

I feel like I’m no longer competent enough to get arbitrary tools working properly together. We need bespoke build systems now because it seems like they’re the only thing that works any more. And that means I can’t throw together a simple server side rendering system like I used to be able to do.

Bryan Cantrill once joked that javascript was the failed state of programming languages. That doesn’t feel like much of a joke any more.


The thing you described about tsc not liking file endings ... I wasted a whole free day on this and my whole motivation for a side project. How the f is tsc not able to output whatever module for.at I need in 202X??? And that means you need an extra tool to do the job. Good luck setting up shitty bundlers for another whole day, until you finally get a simple output directory with normal JS file, one per ts file and simply deliverable to the browser. It is such a PITA. It makes me question whether all the type safety of TS is actually worth the trouble. Once I start writing plain JS, I slowly but surely get the feeling of that project being lost, unless I use a proper programming lang and output to JS. Maybe one of these days I will learn Clojure or something. All just because the JS ecosystem of tools sucks so much. And this is what people put up with all day long. How have we strayed so nuch from the path?


I once set out a simple goal, instead of shipping a production Node package with all the js files and node_modules, just have it all in one js file that can be executed by Node. After trying several compilers and messing with their settings, I ultimately failed exactly because of the different ways to import/export modules. My own code was all esm with .mjs files, but many npm libraries aren't so basically you're stuck.



Tried that one too, failed me as well and I recall correctly due to a different reason. However I see there have been new releases, maybe it's time to try again.


You don’t need bundlers or build systems. ES modules work in all modern browsers without any build tooling, imports and all.

HTTP/2 mitigates the TCP overhead.

You can have an unbundled, unminified web app load quicker than the average bundled and minified React app.

Best of all, you can’t use NPM modules so your codebase can stay ultra-clean!


Sure, but I can’t run the same code in nodejs for server side rendering.

And wasn’t server push for HTTP/2 removed by web browsers? If the browser needs to do a round-trip to the server to fetch every individual javascript file (and it doesn’t even know which files it needs up front) then the result will be way slower than a bundler. I would expect performance to get worse, not better using this approach.


I don’t get the need to use js for SSR? Why not PHP/Go/Python/Ruby… ?


If you use react to create the DOM, you can do SSR in nodejs to re-use the same code.

Not clear to me that the added complexity is worth it personally.


Also this re-use tricks people into tightly coupling frontend view logic with backend logic, making a mess of everything.


No it doesn’t.

SSR is typically just a way to pre-render the client app into (critical) static assets that can be delivered to the browser quickly, so it can display at least some content before the client app loads, runs and ”hydrates” the server-generated HTML back into the exactly same interactive app (e.g. a React app) that was used to generate the SSR assets.


I know what SSR is ... been using it for a decade or so, before it became hip again in form of JS frameworks.

That does not change, that in practice people will write their web components all in one file and render a template, which contains <MyFancyNamedTag>{js logic here that should not be written here}</MyFancyNamedTag>. The mere ability to have arbitrary js logic in there and the fact, that rendering MyFancyNamedTag actually renders a component, which itself can contain arbitrary js logic, instead of outputting a real tag named MyFancyNamedTag, leads to people coupling everything tightly together. Traditional server side template rendering encourages people to make up their data beforehand and then render the template.

Maybe you don't do it that way. Maybe you are smarter than the average frontend/js-is all-I-know-because-I-heard-its-all-I-will-ever-need developer. Not saying you specifically make these mistakes it.

Edit: With regards to being able to contain arbitrary js code in braces in the call to render a component, this actually inches close to the mess many people make when using PHP. There is was: open php "tag", php logic, output HTML, treating it as a string, inside HTML open PHP again, output some JS, JS logic contains code for manipulating HTML ...


Well, the way I see it (and the canonical way React sees it), a render function f producing a view V from some data D is defined as

    V = f(D)
… which is an oversimplification, since UI commonly has local state, which definitely doesn’t need to be elevated all the way to the master data. Any interactive UI thus certainly uses several sources of truth.

Let’s add some to the previous. Let our previous data D now be D_master since it is our master business data (which we may not change in any way, shape, or form). Then, add state of app routing D_router, user auth state D_auth, and local widget state D_widget.

    V = f(D_master, D_router, D_auth, D_widget)
We might have all kinds of access checks regarding the three first ones, but here we are only interested in what this means for rendering a view.

To use all our data, let’s imagine a form where a dropdown select widget is placed inside a tabbed container. The user needs to have a particular user role in their auth data to see this widget. There are many similar widgets in this form, all with fine-grained controls.

- The options for the list come from D_master.

- The state of the tabbed container lives in the URL so that it isn’t lost on refresh, so it is accessed through D_router.

- The user role comes from D_auth.

- And finally, whether the dropdown is open or not is stored in the component’s local state, D_widget.

This is not a far-fetched example, such things are common in more complicated applications.

In any case, it does make intuitive sense to me to allow logic in the render function, as long as that logic operates directly on the render function parameters and not on some on-the-fly transformed intermediate.

Rules of refactoring also apply.

Without logic in the render function, the coupling between frontend and backend would get insane, as every component fetching data would require custom on-the-fly denormalisation for that data in the backend. In our example, we would be pre-generating data for the entire form for a particular user, probably even for unused features.

It would be like generating snippets of HTML in response to AJAX requests, but without the prerendering to HTML.


> Not clear to me that the added complexity is worth it personally.

It used to be pretty easy to set this up. Modern bundlers, jsx, es modules, typescript, webassembly and modern web frameworks which need their own compilers have all made this much more complex. I’m not sure the complexity is worth it any more.


So you rather write your app twice: once in react and once in go? And keep it in sync, including css and styles and dom… ? For real?


You should almost always use a bundler. ES modules work, yes, but using them naively subjects you to a waterfall (each module file may trigger the loading of others, though you could circumvent this with a sufficiently advanced server that recursively traversed modules in order to collect the whole set and send rel=preload links for each with the initial response), slow loading everywhere and exceedingly slow loading in higher latency, and the downloading and execution of much unnecessary code. For many completely realistic designs that would have been a hundred kilobytes in a one or two files, you’ll end up with it spread over several hundred files, reaching ten or twenty levels deep, so that it downloads and executes multiple megabytes of code, a lot of which is not even used, so that for someone on the other side of the world, what would with proper bundling have taken less than two seconds to load (including initial TLS handshake) will instead take ten or twenty seconds if everything goes smoothly. And I’m not exaggerating in the slightest here.

The situation would certainly be worse in HTTP/1 because of the lack of pipelining and the six connections limit, but HTTP/2 does not make not-bundling in any way reasonable.


The import statement returns a promise, so you can lazily load modules as required (i.e. don't load everything up front, only load on-demand as users are using your app).

You don't need to complicate things - just use vanilla JavaScript features as they were intended.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guid...


In practice, you are likely to have to contort your code very significantly to use dynamic imports pervasively. And pervasive usage such as you seem to be describing is emphatically not how dynamic imports were intended to be used, and wouldn’t speed things up much in general anyway (because you still can’t do anything until your dependencies have loaded), and stands a good chance of being slower.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe... expresses it well:

> Use dynamic import only when necessary. The static form is preferable for loading initial dependencies, and can benefit more readily from static analysis tools and tree shaking.

(Also, a quibble over your wording: dynamic imports aren’t a statement, but a call, though not a function call.)


You need to develop with this in mind from the start. I am not suggesting refactoring an existing application to use it for every single dependency as yes that would be a pain.

Instead import your initial generic dependencies up-front as usual, but then notionally break your application up by CUJ and load the CUJ-specific code dynamically as needed.

E.g. for a hypothetical email client you would import the initial "inbox view" code upfront (along with generic common dependencies), but you might not import the code needed for a rich text editor until the user clicks on the "write email" button, saving that network load and code execution for when - or indeed if - the user actually needs it.


Given the context (waterfall stuff), I was assuming you were describing pervasive dynamic imports, since the selective use of dynamic imports for code splitting is fairly standard practice. (And indeed, I know from working on it a few years back and doing most of the porting from a custom module system to ECMAScript modules, Fastmail’s webmail works in this way, though my recollection is that compose specifically is preloaded once the rest of the mail stuff is done, so that when you hit that compose button it’s almost certainly ready to go common fault of code splitting is deferring loading too long, so that you end up slowing users down.)

When I spoke of unused code, I was meaning things like a file containing a bunch of functions, of which you only use one, and so there are the other functions and perhaps deeper imports that weren’t actually necessary; a bundler would remove all the unused stuff. The “solution” in such a case would be to do something like splitting each function into its own file, but that’s worse than before because now your import chains are probably even longer, and even more files have to be loaded (and there is still some filewise overhead, even if HTTP/2 improves it drastically).

I’ll temper my expressed position slightly by saying that bundling is not so significantly advantageous if you have written all of the code (you’re not importing third-party libraries), and keep your file count fairly low and import depth very low. But at that point, perhaps you should have just dropped it all in one file.


Don’t use external dependencies (:D), don’t write code you don’t use, encapsulate imports in custom elements (this is a joke).

Without any runtime boilerplate like module bundling, corejs polyfills and the usual frontend/css-in-js frameworks, all code that gets downloaded is your code, so make it count. 640 kilobytes should be enough for everyone.


For runtime boilerplate: yeah, don’t use webpack, it does indeed add silly boilerplate (and structures things in a way that almost requires source map tooling to understand!); use Rollup instead, which pretty much writes just what you would have written if you had put everything in one file, with no overhead whatsoever. (If you happen not to be familiar with it, take a look at the examples in https://www.rollupjs.org/repl/.) Also ditch core-js as it’s almost certainly unnecessary if ES modules are your baseline.

But even if you’re not using external dependencies, I maintain: by not bundling, you’re slowing things down, and it’s generally the people on the other side of the world from your servers and the disadvantaged with less-powerful computers and more expensive data that will suffer for your whim.


From what I’ve seen, many built-and-bundled apps have run into security issues in dependencies and have been forced to switch to ESM versions which are highly incompatible with CJS-targeting builds and so require significant retooling just to fix trivial security issues.

It’s not npm’s fault for sure, but the ecosystem is fundamentally divergent on this issue and there doesn’t seem to be a universal solution.


I’m confused by your comment, because it doesn’t seem relevant and I don’t understand what you’re saying. My first impression is that you seem to be implying that the security issues in dependencies are in some way linked to the module format (ES/CommonJS), which is not the case. I can’t see why such issues would force a switch in either direction for anyone, given especially that ESM bundlers can generally slurp ECMAScript Modules and CommonJS alike (e.g. Rollup via @rollup/plugin-commonjs) with only rare compatibility issues after at most a little configuration, generally associated with very-badly-written code. Given how much of the npm ecosystem is still on CommonJS modules, there’d be much more outcry if you could’t intermingle the two in a bundler. So if what you had in mind was something like “version x was CommonJS and has a bug, version y is ESM and has fixed the bug”, well, you can probably update to y easily (at least as far as the CommonJS/ESM divide is concerned), and if you were forking or anything, if the bug is clearly identified then patching it onto x is easy too.


In practice, there are packages which have moved on to ESM and which no longer maintain their CJS version (at least as actively), making life difficult for maintainers of projects dependent on those CJS packages with published vulnerabilities.

A CJS-targeting build can’t slurp up ESM dependencies. Not without dubious hacks, at least.

See e.g. https://stackoverflow.com/questions/70545129/compile-a-packa...


> Recent example: bundler X insists on import statements including file extensions. But the typescript compiler refuses to let you import foo.js and won’t rewrite an import of foo.ts to foo.js when you build. There’s giant GitHub issues about this but nobody wants to fix it on their end. In short, everything is awful.

That's wrong. The latest TS version allows you to import .js files with extensions just fine! In fact, one of their recommendations is that you write the your JavaScript code as you would if they were intended for a browser (which doesn't automatically append any file extension, doesn't support importing directories by appending /index.js, only supports file-relative or absolute imports (outside of import maps) etc).


I wanted to import a typescript file from another typescript file.

If I made my import line be “import .. from ‘./foo.ts’” then typescript was happy, but the compiled output still specifies .ts rather than .js. So the import was broken (that file didn’t exist in tsc’s output directory).

My other option was to “import .. from ‘./foo’”. Then typescript worked but the bundler I was using refused to import the file at all - since it was missing an extension in the import statement. And apparently extensions are technically required by the spec.

The real solution would be for the typescript compiler to rewrite import statements. Like, import foo.ts should be rewritten to import foo.js. There’s a GitHub issue talking about this[1] that was closed because the typescript authors think this is someone else’s problem.

I ended up just giving up and trying a different bundler - which had equally different, but equally frustrating problems.

The ecosystem is a disaster.

[1] https://github.com/microsoft/TypeScript/issues/40878


“import .. from './foo.js'”

TypeScript doesn't rewrite (that part of) your code (it downcompiles ES features if necessary, but won't rewrite import specifiers). Write import specifiers as you would in regular JS code intended for the browser (ie. relative or absolute paths, including file extension, no directory imports, …).

> […] but the bundler I was using […]

Trying to write code that's understood by both bundlers AND produces working output when processed directly by TypeScript is a bit too much to ask at this time. Maybe we'll get there, eventually, but unless it's plain ES2022 code (intended directly for browsers, not targeting bundlers or TS or test runners etc) you have to write the code with a specific intent.


> “import .. from './foo.js'”

When I tried it, the typescript compiler errored at this - because no such file exists. VS Code also got really confused by this approach. Has the situation changed? If this is the recommended way to write typescript code, why doesn’t typescript’s documentation reflect that?

Typescript needs to pick a lane. A compiler that can’t produce working code is broken. And last I tried, typescript broke when I imported foo.js, and every other option didn’t produce spec-compliant javascript (since the extension is officially required in the import statement).

My take is that if typescript can rename my file from .ts to .js, or change import to require(), it should be able to rename my import statements too. But if you want to die on that hill and recommend people import the resulting .js file, then recommend that everywhere so tool authors can fix their tools! Don’t play it both ways then blame users when we can’t make our code work.

> Trying to write code that's understood by both bundlers AND produces working output when processed directly by TypeScript is a bit too much to ask at this time.

What rot. Being able to turn my source code into working software is exactly what I expect from a compiler. If typescript can’t deliver, what use is it?

Edit: I just tried it and "import .. from './foo.js'" seems to work correctly now in both the typescript compiler and vs code. Good! I'll raise tickets in other tools when I run into problems.


You see, it's not that ESM killed JavaScript, all the hacky build tools did. ESM was in the pipeline for an eternity and everyone took their sweet time to support it.

You can use ESM without issue in browsers, Node and using proper ESM bundlers like Rollup, as long as you don't expect `import 'a/b'` to arbitrarily load `./node_modules/a/b.js` or `./node_modules/a/b/index.js`

npm also keeps actively harming the community by not validating packages in any ways whatsoever, so everyone keeps pushing broken crap into the ecosystem.


Maybe the right way to think about it is that ESM is python3 for the javascript world. If javascript had ESM from the start, it would be fine. And maybe once every package in npm is rewritten for ESM, it'll be fine. But in the meantime, we have essentially 2 mutually (sort of) incompatible programming languages which share a name and a package repository.

> You see, it's not that ESM killed JavaScript, all the hacky build tools did.

The problem is that ESM added a massive extra amount of complexity to all those hacky build tools, because suddenly we have 2 different kinds of javascript code and people expect their code to be mutually compatible. That is really complex.

- Typescript's canonical way to import things (import foo from './blah') is incompatible with ESM imports (because imports must have file extensions).

- Nodejs has a plethora of options to configure packages to support combinations of ESM and CJS[1]. Half of those options are deprecated. Lots of tools read package.json - but don't parse all those different options consistently with nodejs's implementation.

- Eg: wasm-pack only knows how to compile code "for the web" or "for nodejs". (You want a package that works everywhere? Adorable.) The web version creates an ESM module, but doesn't specify "type": "module" in package.json - so even though it could work with nodejs, it doesn't.

- Lots of packages in npm are broken in either CJS or ESM mode. And there's no way to tell without trying them.

Essentially, we went from having a simple, extensible system (commonjs + bundlers) to a very complex system. The number of people who understand all that complexity has dropped by orders of magnitude. Now I feel less capable of creating working code than I was a few years ago.

Its an unmitigated disaster for the ecosystem. Maybe in a few years, everything will be using ESM. But until then, I want off this ship.

[1] https://nodejs.org/dist/latest-v18.x/docs/api/packages.html#...


We’re saying the same thing:

> Lots of packages in npm are broken in either CJS or ESM mode. And there's no way to tell without trying them.

I blame npm for allowing that to happen. I get that it’s technically a third party, but they never even checked that the file mentioned in `main` was included, even without a “postinstall” step.

They, together with node, could have built a tool that validates main/type/exports on publish, but no. There’s literally no way to validate ESM until you run them or use a full linter. The whole point of ESM was that it’s statically analyzable.


Next is the worst name for a JavaScript framework. It might as well be called "yet another JS framework." It's things like this that make me ponder self deletion. So much pointless work we create for ourselves.


It’s layers on top of layers on top of layers, etc.

I’m looking for a framework that compiles to web assembly to generate next.js to spit out react components that generate JavaScript that prints html.


In the era of Yarn, Bower, etc I was joking that we need package managers for package managers.


I just learned about Volta today...


Let me introduce you to asdf.

No, that is not a typo.

https://github.com/asdf-vm/asdf


I experienced this with multiple npm packages where I can no idea how to fix it. My most recent was with https://docusaurus.io/, and I did not have fun. This is how I'm getting myself back to basics: https://www.adama-platform.com/2022/06/26/making-html-the-be...

Here, I believe in taking HTML and then finding the absolute minimal extensions. My most work is to embed a mustache like primitives into HTML. For example <div rx:iterate="posts"><div><lookup path="title"> - <lookup path="body"></div><div> will iterate over an array and render the title and body appropriately.

I then take it a step further by making the binding reactive such that updates flow in real-time.

I am having a great deal of fun with this approach as I continue to explore this approach.


You should check out the OP. This is exactly what htmx does.


The name alone already makes me feel dread. htmx - as if HTML needed an x for extended ... also has a feeling of docx and its ilk. Why do people feel the need to change HTML instead of changing the logic, that outputs HTML? HTML is just the damn view layer! This smells of mixing logic into the view layer again.


htmx is very, very close conceptually to a standard HTML <form> tag. (By the way, the fact that there is a <form> tag immediately tells us that HTML is not just 'the damn view layer'.). htmx just goes slightly beyond it to give <form>-like capabilities to every element, and doesn't need a full page reload. It doesn't even necessarily change or extend HTML–you can just use a `data-` prefix on the attributes that it adds–which makes it completely standards-compliant HTML. It's a very natural fit.


This is so relevant. The current “bundle of bundles” approach has very low longevity potential.

I swear this whole design pattern in the article looks just like cold fusion did in 2000.


What’s stopping you from using these tools today? I still use vim for editing and rsync for deployment whenever I can.

Unless you mean for clients.


For Lua, just to be safe, I fork all my dependencies and when I work on a project I add those forked dependencies as git submodules. Just to feel a bit more secure any dependencies never disappear.

Not sure if this is good practice.


Its good to have dependencies archived for continued access to them, but there are efficiency issues with doing that. Using git submodules (or vendoring or similar) means that you and everyone who uses the project is stuck on the exact commit you have chosen for each submodule until they go and modify the git tree to use a different commit for each submodule. This makes it higher friction to update a submodule. You can't just go `git pull` or `apt upgrade` to update the submodule, you actually have to go modify every project that uses the submodule, update and redeploy each one, instead of just updating and redploying the submodule itself.


That sounds amazingly slow, in a good way.


Well, I only use git submodules in private projects. From what I read most devs hate it :)

In the past I did came into contact with git submodules through freelancing for another company, and I agree it was quite a hassle it times using it in a team setting.


Even in private projects, its an additional hurdle that can block things like security updates for example.


With node some people commit the heresy of comitting the whole node_modules folder.


I would do that, but node puts compiled bits in there, so nothing works if you switch machines.

It's not like linux distros figured out this stuff was an issue decades ago...


I think that's called vendoring and it's part of the 12 factor app.


Good luck with that approach in the JS world, where a package can have, without exaggeration, a thousand and more dependencies. Hopefully in the Lua world things are saner.


I’ve found most Lua game related libraries don’t have any dependencies, so it’s indeed a saner world :)


What about transitive dependencies?


I've found most Lua libraries don't have any other dependencies.

Perhaps this is the reason I've found this approach work well with Lua. I've never tried it with other languages that I use, like Swift, Objective-C, C#.

I did work in a company in the past that used Nexus [0] for their dependencies across various platforms. Perhaps Nexus has some tooling build in to deal with transitive dependencies, not sure.

---

[0]: https://www.sonatype.com/products/nexus-repository


It's forking all the way down. I run my code on a fork of Linux, just in case.


Theres a few nice lightweight CSS/JS frameworks like mdl.io and bootstrap that are still relevant, react apps get lost in a mess of callback caches and useEffect, unclear side effects seem to happen on rendering in most large react apps.

I developed some games like https://github.com/lee101/wordsmashing in a fairly simplistic jquery style i developed where i purposefully avoid using features of JS like "this", it trips most developers up when you pass functions around and the reference to "this" gets lost.

Agree with lots of the comments here about complexity of both JS (new es module compatibility issues etc) and JS frameworks that are limiting what people can actually build these days from cognitive overload and bugs.

a tonne of technologies (like polymer.io/web components) died in a sea of complexity and much technology we use is going to go the same way unfortunately.

Another gripe i think unpopular but true is that we as coders prefer complex things like static site generators like Jekyll/ghost etc, normal people can use a CMS and get stuff done without having to resolve packaging conflicts and SSL issues, we have to resist the urge to pretend coding/setting up complex software is easy because its not... also Kubernetes...


I built a website for my girlfriend's business using almost exactly this approach. Handwritten HTML, deploy to CloudFlare pages on git push, Stripe payment pages for ecommerce. It's great, more people should try it.


as someone who's been making websites for 20 years now, i think it's actually easier than ever. and pretty simple. the tools are insanely good.


I kind of still do this, just Sublime/SFTP instead of Notepad/FTP.

Still haven't seen anything from "the new JS" that makes me want to switch.


Angular -> React -> Vue -> Svelte -> Solid -> Marko -> Hotwire

Please stop.

The reason why React is so powerful is because of the maturity of React Native.

If you're a startup deciding your FE framework and you have mobile to consider, then chances are that React is best fit.

Unless you have capital to blow on a separate native team, lest it even be more separated to kotlin / swift, then sure you can possibly afford all these niche FE frameworks.

Lets not even talk about hiring pools.

React is good enough, and it's a shame that many of you think the answer is a new framework with better philosophy.

Trust me, I love reactivity > virtual dom, but React is good enough.

It doesn't need to be the best, it just needs to do its job.

The only thing I'll ever consider switching to is when WASM comes out with a framework - till then I'm betting on React.


React is not good enough. It sucks for both time and space complexity. It's slow, it's bloat. I don't want to tie myself with the word "engineering" for doing software development these days. It's shameful compared to other engineering fields.


While I agree that Front End "engineering" isn't as complex as other fields, calling it "shameful" is a bit much.

There is a huge requirement out of web apps today that SPAs are more and more required than your simple html + css blog posts.

Posts like these is where I feel the age of HN, that are becoming bitter about fields that were once very simple, ending up complex to suit the needs of the times.

Everywhere I look around, people on HN feel like we're still in the age of blog posts and form submissions, when in reality, there are people trying to port applications like Photoshop towards the web.

If Photoshop was available on the web, wouldn't you think that the Front End required an honest amount of "engineering"

And it doesn't even have to be a front-end heavy application like photoshop - it could just be a simple chat application that needs to be on the forefront of the site while you can still browse.

You can use whatever framework you'd like to solve your "bloat" issue, but the problem is, especially for startups, you're not going to get anywhere near the hiring pool, nor or you going to have an ease of choice for your native platform.

This is what makes React so strong right now.

I wished you had addressed this, instead of just deriding the entire front end community.


You are conflating the root comment of this and the OP's point. It's not about SPA. It's about network effect / marketing / cult / lack-principle insanity of frondend or web market that's heavily into React specially.


While I agree that React (for the web) isn't the best SPA out there (I would use Solid or Svelte), It's the most practical simply because of the hiring pool and because of React Native.

Sometimes you have to be practical and give up certain areas for the sake of the whole.

I don't even think React is even that bad as you claim it to be, judging from your past posts.

React Native is one of the best things to ever happen to native development, removing the atrocity that is the separation of development of apple and android - one of the most productivity inhibiting factors to a startup out there.

This is why react is so strong.


I don't think this is called practicality. React is neither even good in practice nor in theory. "Hiring pool" reason is not backing practicality at all. React Native fall into the same "Hiring pool" argument which is not practicality.


I take absolutely nothing noteworthy of your comment at all other than that you have a bias that you need to put in check.


Adding React is a big decision.

You’re adding a lot of complexity to your project which may be unnecessary if you’re app is a simple website with a few interactive elements.


Choosing any front end choice is a big decision.

But you're not going to get anywhere near the hiring pool nor are you going to have an ease of choice in native platforms.

React is easily the best decision a startup could make right now.

> If your app is a simple website with a few interactive elements.

lol


You're missing the point here. It's not "another framework". It's more like "no framework" at all. Please read: https://edofic.com/posts/2022-01-28-low-js/


No you're missing the point.

What's easily the better decision for a startup that has to deal with mobile and native platforms?

I seriously don't know what you people are building that you think low/no js is viable.

Collab tools like Trello Asana need high js

Chat applications need high js

Drafting applications like FanDuel, DraftKings, Sleeper need high js

Music apps like Spotify or Soundcloud need high js

Financial apps like Coinbase or Robinhood need high js

Seriously, what are you people building that you think low/no js is okay.


What is the lesson of this article? Instead of using React or Vue, you should use htmx and hyperscript to have less stuff under node_modules?


I'm not really understanding what hyperscript brings. It's neither back end nor JavaScript, and only AppleScript users will be comfortable in it. It seems like just another library that needs to stay current with the DOM and might become brittle.


It’s basically another framework that lets you add interactivity to server side generated HTML views, ala Stimulus, Knockout, etc.

A lot of devs like approaches like this because they can do more with their server-side language and frameworks that they’re used to/more familiar with, since trying to do everything server-side doesn’t give you the interactivity UX, product, etc wants.

(I personally prefer client side HTML view rendering like React, and only talking to the backend via API calls, but I understand the use case for this sometimes)


htmx is a little different in that its focus is on extending HTML as a hypermedium, exchanging html (rather than some other data format) with the server, and staying within the original web network architecture articulated by Roy Fielding:

https://htmx.org/essays/spa-alternative/

https://htmx.org/essays/hateoas/


I totally get htmx. Just not hyperscript.


My bad, yeah I don't see the value-add of that either.


the idea with hyperscript is to provide a general, event oriented language that can be embedded cleanly directly in HTML

normal on* attributes are fine, but they aren't general (e.g. htmx fires a bunch of events you might want to hook into, and you can't use normal on* attributes to cathc them)

hyperscript also has a lot of features that are DOM oriented (e.g. query literals like <div.foo/>)

certainly not everyone's cup of tea, but it dovetails nicely with htmx and fills a need for a general, event oriented scripting language to complement it


You can have no node_modules


The first comment on that page is that this approach produces inaccessible UIs, not sure if that would be the absolute case or not, as it didn't look like the article was taking accessibility into consideration.

All that said I don't think this gives any real benefit over JS, sure, fix node_modules bloat, but I guess I'm a little bit skeptical if there wouldn't end up being hyperscript bloat if it became the biggest programming language in the world powering what for many is their defacto platform and thus everything needed to be solved in it.


it's a good fit(alpine also fits well here) for 'legacy' server-side-rendering framework like django. rails and php already have their own similar approaches.

SPA still has its own place though: a backend provides the data, and a frontend renders it. the separation of two concerns still has lots of benefits not just for traditional website, but also for browser-based GUI(e.g. Electron apps).


Why is server-side rendering considered "legacy" nowadays?


Agreed, Alpine and the like work great when building your app in Laravel.


I feel complex UI development becomes a ease with SPA ecosystem than server side.


I think people in comment should not try to compare HTMX to SPA directly, but have a broader view of the whole pros/cons of the tech stack.

For example, let's say you need to write an admin dashboard with many pages, no fancy stuff. Odds are you'll be very productive with a good old Django/Rails, having no API to write and a single simpler project to maintain.

Once that monolithic framework choice is made, before HTMX, as soon as you needed interactivity, you had to mess with jQuery and the code was quickly awful. The only solution was to plug a SPA framework and develop an API (this is not trivial!). HTMX (and other tools like Alpine.js) solve that problem well.

So, the question is not "is HTMX better than SPA frameworks", but rather: "Knowing that I can now build decent front-end with Django/Rails, does a more complex stack with Next worth it?"

HTMX-like tools make SPA frameworks a little less indispensable in some use cases. That's it.


"A backend web and desktop application developer" whose "preferred frameworks are Django for Python and WPF for C#" has, unsurprisingly, a naive impression of what's needed out of a UI framework.


Alternatively; a backend developer writes about their exploration of a relatively new/emerging frontend approach which provides an interesting read on one of many alternative options for frontend from pure HTML to canvas for everything.

I write React in my day job and I think it's the bees knees, but I am interested to learn about alternative approaches and projects aiming to create new/revive old paradigms.


What the htmx anti js crowd refuses to accept is the existence of applications that do not fit their world view.

Serving html is trivial but do we really need every back-end juggling this stuff just to make these guys happy? What do they do when they have to support a number of clients. Oops...


> back-end juggling this stuff just to make these guys happy?

I don't see this design pattern as forcing a particular back-end framework?

It's merely shifting the frontend<-->backend contract from JSON to HTML.

Some backend engineers arguably would prefer HTML. Especially if their backends weren't Node. Backends were originally C servers that sent a string of HTML back. I think backend engineers are fully capable of "juggling" with this new/old paradigm.


The problem with using HTML in this way is that it couples the view with your data. What happens when non-browser clients (e.g. mobile, other servers) need to easily consume the same API?

I know some projects plan to only ever use browser clients, so this may seem irrelevant for them. But I'd rather not try to predict how a business will want to use it's data in the future, and would prefer to design a backend that can be adapted to many scenarios without being bound to a particular client.


> But I'd rather not try to predict how a business will want to use it's data in the future

Sure, then the backend can expose a gRPC / protobuf interface instead. Mobile apps can readily deserialize this and it will be more performant, both in network bandwidth and data parsing, too, especially with first-party to first-party SDKs. It's strongly typed and serves as a better data contract language than both HTML and JSON. JSON is loosey goosey because of JavaScript.

Then the frontend server now plays the role of aggregating data from gRPC backends and converting it to HTML.

The gravitation to JSON is a case of web developer familiarity.


This ain't such thing as a world view, it's only about tradeoffs.

When you build something that is highly transactional, say booking train tickets, and you don't have the resources, like dozen of 200k-400k a year devs, you are better of with a really short path between the where the state is stored and what is displayed to the user.

What we are seeing currently is something like that : DB(ms sql, ...) <-> [ microservices(java spring ?) ] <-> FrontEnd (react ?) With few integration tests and load testing, legacy authentication with oauth or oidc on top, and a really poor user experience (see https://www.sncf-connect.com/). The user experience is in fact poorer that it use to be with php, and even lousier than it use to be with https://en.wikipedia.org/wiki/Minitel

The "antijs crowd" is saying : When it's relevant, let's make more simple systems, but let's still offer solution for some interactivity in the frontend. That's it, it's not a "world view".


as I have said many times: the hypermedia approach isn't right for everything, htmx just makes it possible to address a much larger UX space using that model than plain HTML does:

https://www.reddit.com/r/htmx/comments/ufsqcj/vue_angular_re...

> So, consider something like google sheets, with a large number of dependent cells that need to be recomputed and synced on every cell entry. Probably not a good idea to jam an HTTP request after every cell edit, and a place where a more elaborate SPA framework is called for. On the other hand, maybe htmx is useful for the settings page for that application. And for something like Gmail, htmx would be perfect.


I think it kind of goes both ways. People knee-deep in the React ecosystem are dismissive of problems that don't require a full application implemented in a heavy, opinionated framework.


The article uses as its first example one of my most-hated fashions as a user of a website--the modal dialog entry form in html. Makes it hard for me to stay interested. Honestly, this is one thing I like about the multi-page app flow over single-page apps.


One of the things that I found lacking, was doing like general computing-esque business intelligence tasks in htmx. For example, how would you set src on image tag upon a click. Ended up having to use jquery.


You should be able to do this with hyperscript.

    <img src="my_cat.jpg" alt="My cat" _="on click set @src to 'my_other_cat.jpg'">


I am not sure what the benefit of hyperscript would be here? Why not just use JavaScript + htmx?


Why not just use JavaScript + HTML?

  <img src="my_cat.jpg" alt="My cat" onclick="this.src = 'my_other_cat.jpg'">


Any more full example? Interested.


Vanilla JS v. jQuery v. hyperscript full examples here: https://hyperscript.org/comparison/


you'd use hyperscript for something client side like that:

on click set @src to "https://whatever.com/cat.gif"

the htmx approach would be to replace the image tag entirely


That syntax just smells like a leaky abstraction and is jarring. Also probably lacks typing and poor intellisense support. Not sure why I’d pick that over conventional offerings.


I prefer Stimulus vs htmx + hyperscript for two reasons:

1. You can easily reimplement all htmx and hyperscript functionality and fine-tune to your liking

2. You are not limited by htmx and hyperscript


> In recent years, a few mavericks and renegades have started to turn away from the world of JS frameworks and the inevitable bloated node_modules folders

Some projects claim they are "zero dependencies" but a few sentences into the readme and you see an `npm install` and now you notice there is `package.json` after all . They meant zero runtime dependencies, which is still praiseworthy, but not zero `devDependencies`.

For my greenfield web app, I attempted to have zero dev dependencies on Node. I wrote some vanilla HTML, JS, CSS, and now needed to reduce network transfer. Requirements:

- minify

- inlining CSS file into HTML

- compress with Brotli

- print out final byte size

- nice to have: run a dev server that serves static Brotli

We know the story with WebPack. I looked to Parcel instead because it's the "zero-config" tool. It was promising because it inlined my `@import css` into my HTML, and logged out the filesize. The watch and reload feature wasn't working as promised, but that was nice to have anyways. For Brotli compression, which is mainstream at this point, I quickly needed to add a `.parcelrc` config. Their code sample didn't work because it turns out that in the real world you need to make your .parcelrc extend/inherit "@parcel/config-default". Parcel stopped logging at the compressed file sizes and not the final Brotli file sizes. Finally, Parcel's dev server is useless to me because you can't set encoding headers for "Brotli" files so the browser just attempts to download it. I didn't have a .gitignore file, and adding this one Node dependency on Parcel added 3,000 new files. To be fair, that's miniscule for a Node project.

I asked myself if I can achieve the same results with CLI tools that are not Node. I first looked to the Golang ecosystem. I stumbled upon https://github.com/tdewolff/minify. It just does minification. It's comparable in output size to other Node minifiers, but faster and just works. The lexer code is very readable, even for me who is not a compiler or systems expert. It's one command to install the CLI, and one command to Minify. You can do `npm install global -g` to get CLIs, but Node supply chains tend to be much deeper.

This bespoke one-liner does the CSS inlining for me:

  RUN sed -i "s/@import \"style.css\"/$(cat style.css)/g" index.html`
For Brotli compression, I went with the official first party CLI ( also Go based ) instead of using a third-party wrapper like you'd have to do with JavaScript.

One thing I was missing in NPM scripts as a self-documenting way of describing what commands to build, run, test. I've seen cases where people are beholden to a `package.json`, sometimes when their project doesn't even involve JavaScript. When you have a hammer, everything looks like a nail. It turns out Makefiles are a better way of doing this, especially if you don't already have a active relationship with Node

  .PHONY: help

  help: ## This help.
   @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)

  # DOCKER TASKS
  build: ## Build the container
    podman build -t ${APP_NAME} .

  run: ## Run container on port configured in `config.env`
   podman run -it --rm -d --env-file=./config.env - 
 p=$(HOST_PORT):80 --name="$(APP_NAME)" 

It's even better than self-documentation, because the documentation is self-documenting:

  $ make help 
  help                           This help.
  build                          Build the container
  run                            Run container on port 
  configured in `config.env`


I don't find this anything better than just using Next.js or any similar framework. Custom solutions for bundling end up being custom reinvented square wheels in my experience.


He can replace minify and sed with Hugo and now everything is well maintained instead of custom.

He even uses make instead of any of the reinvented square wheels used in JS!


I thought you were being sarcastic and snarky at first, but Hugo is exactly what I was looking in the event I need to scale up.


The point here is vendoring and dependency management.

Makefile and sed are decades old, stable, available on every Linux distro including the Alpine docker image clocking in at 30mb total. The entire image containing an Linux distro with all the needed CLI tools is 30mb.

  └─ ▶ podman build -t base . && podman images
  REPOSITORY               TAG            IMAGE ID      CREATED             SIZE
  localhost/base           latest         b593261330c1  1 minutes ago      30.5 MB
The only dependency here is the Go based minifier, and Go programs are self-contained executables.

Alpine contains an entire package manager. Compare with adding Node and one CLI for minification.

  └─ ▶ echo 'RUN apk add npm' >> Containerfile && echo 'RUN npm i -g terser'  >> Containerfile && podman build -t node . && podman images 
  REPOSITORY               TAG            IMAGE ID      CREATED            SIZE
  localhost/node           latest         a28f38037137  6 seconds ago      93.5 MB
  localhost/base           latest         b593261330c1  5 minutes ago      30.5 MB
Assuming dependency management was equal level of maintenance with Node, the spirit of Node ecosystem tends accept being whimsical with breaking changes. Terser or whatever Node-based processing library will introduce breaking changes to their config in relatively small timescales ( months, years, instead of decades ). That's not inherently a technical fault of the ecosystem as it is a cultural one. The popularity of JavaScript is its own undoing. Opting for tools in other web-friendly languages selects for a different type of developer.

That's just for minification. Want to inline CSS? That sed command is 66 characters long. That's about the same as Parcel's zero-config config boilerplate that is NoOp: https://parceljs.org/features/plugins/. Surely a WebPack config is more than 66 bytes. I proceeded to add Parcel to compare how much it increases the image size, unfortunately it failed because there is a Python dependency:

   └─ ▶ echo 'RUN npm i parcel' >> Containerfile && podman build -t parcel . 
  [2/2] STEP 18/18: RUN npm i parcel
  npm WARN deprecated stable@0.1.8: Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility
  npm ERR! code 1
  npm ERR! path /usr/share/nginx/html/node_modules/@parcel/watcher
  npm ERR! command failed
  npm ERR! command sh -c node-gyp-build
  npm ERR! gyp info it worked if it ends with ok
  npm ERR! gyp info using node-gyp@9.0.0
  npm ERR! gyp info using node@18.2.0 | linux | arm64
  npm ERR! gyp ERR! find Python
Fine, I added Python, Make, and other transitive dependencies to see how deep this rabbit hole goes:

  └─ ▶ podman images
  REPOSITORY               TAG            IMAGE ID      CREATED            SIZE
  localhost/python         latest         05582c8b2425  2 minutes ago      156 MB
Will Parcel installation work now? Nope, here's the new error trace: https://gitlab.com/-/snippets/2364041. It appears this is a dependency issue with Parcel, Maybe?, with this similar 6 week old thread: https://github.com/parcel-bundler/parcel/issues/8152, which reiterates the painpoint about Node.

Let's take a step back and forget the Parcel example for a second. How about NextJS? From that 30mb Alpine base image:

  ```Containerfile
  RUN apk add npm && npm i next react react-dom 

  └─ ▶ podman images
  REPOSITORY               TAG            IMAGE ID      CREATED             SIZE
  localhost/nextjs         latest         d177ee032ff0  9 seconds ago       266 MB
Kudos to NextJS for installing properly at least, but that single command added 266-30mb = 236MB to the image, and this is where the bloat creeps in. Thinking 200MB is a nothingburger is how we end up with gigabytes large images.


Yes, because optimising for docker image size sounds like the right thing to optimize for.


Again, you're missing the point about supply chain risk. The Docker Image size is a good proxy indicator of this.


He's just straw manning the argument.

And this is ignoring the time lost watching WebKit process the same thousands of one-liner dependencies over and over.

Instead of the almost instantaneous tools written in go.


I am keeping my fingers crossed and saying a few our fathers for www.redwoodjs.com JAMSTACK for the WIN.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: