Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

This article misses the single most important reason to use SSR: single language applications are single build applications. Frontend builds are basically a requirement for any application with a UI. You're always going to have CSS, and some degree of user interaction for even the simplest website, which means JS/TS. One of the most important developments for frontend assets in the past decade is dependency management and builds, and any dev team who knows what's up is going to include a frontend build for their app. So, given that the frontend build is baked into _any_ application build, if you decide to do template rendering in any language other than JS/TS, you are adding another build to your project. That means you need to configure that build for all environments, configure CI, and support that build going forward. Save yourself the trouble and just render everything server-side in JS.

As for speed concerns, server rendering is almost never the bottleneck for any application. DOM rendering can be slow, but even JS renders several magnitudes faster than any network action. So your latency to the server alone is always going to be much, much slower than your render. Same with any network calls your app has to make, DB access, etc. In my many years of building SSR apps I have never had to optimize a render.



I say save yourself the trouble and just avoid all "modern" web development tooling. Avoid "frontend builds" at all costs (everything except for esbuild is insanely slow anyway). Most websites do not need npm for frontend (or backend). Most web applications are barely "applications" at all but rather mostly-static content with a few forms, tables, and/or menus.

I use vanilla html/css/js for frontend + golang for the backend. Modern JS (esp. modules) are very powerful. ESLint provides pretty good static checks for the frontend, and of course golang is statically typed so you get strong guarantees about your backend. Go builds extremely fast as a small self contained binary that can run on any OS and in a from scratch docker container. Go performance and tooling blows JS out of the water. And go has a powerful built-in templating engine for SSR which allows to to make your JS even leaner. Testing a change requires no more than refreshing the page. Debugging is super easy, barely an inconvenience since there are no build layers between anything encumbering developer velocity. Just add breakpoints directly to chrome devtools in the JS (or in VSCode for the golang) and step through.

Always start vanilla. Most of the time you won't need to be dependent on npm, you'll never break when some random maintainer becomes an activist, people will wonder why your site page loads are so snappy, and you'll live happily ever after.


Yeah, no.

Don’t get me wrong, I’m very unhappy with the state of today’s JS ecosystem but if you’re building a project of any complexity ditching absolutely everything that can help you along the way is not going to work out. Nor is it going to work out for the person taking over the code from you.

Every now and then I’ll be putting together a tiny landing page type thing and write it all in vanilla JS and it’s bliss. But as soon as I start dealing with non-trivial state you’d better believe I’m reaching for a framework.


Most people overuse frontend state. It seems like every new React programmer goes through a phase where they think that everything needs to be in state, especially things that never change.


Or for "state" that is already saved on, or known by, the server -- or will be sent to the server for persistence.


Been there, done that. I don't agree. Go's native html/template and even pongo2 or quicktemplate etc have a big problem when it comes to conditional fragments of some text.

It's messy and you end up writing helper functions for pretty much everything. Need a href aware navbar? Custom function and macro time. Bleh.

Performance is great, maintainability isn't.

I dislike graphql because it's too mich overhead. RESTful is not good enough, only good for admin UI CRUD.

I moved to json rpc calls. So I can have the best of both worlds.

However what I'd really like to have is a proper SSR component framework that is interactive or rather reactive.


Just use Rails


With Rails you're back in the low performance camp sadly, might as well go full JS.

I want my cake and eat it too.

For Go, unless I missed some new development, there's Kyoto and jfyne/live . And that's it for Go.

Kyoto IMHO is more of a poc. And live is not very appealing, you're back in complicated camp with it.


These days it’s hard to justify Rails over Phoenix for fresh projects.


Fine then, Phoenix :) But yeah Go is not a good ecosystem for comprehensive web development


If you're using JS modules and ESLint, you are using a frontend build. You can certainly go back to the days of jquery and vanilla CSS with none of the advantages of modern dependency management, transpilation and module loading, but if you try to do that at even a small company you are not going to last long. These tools exist for a reason, and most people who don't see the point of them were not around for the bad times before the existed.


> If you're using JS modules and ESLint, you are using a frontend build

Browsers natively support JS modules with no frontend builds needed (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guid...).

You just need to specify `type="module"` in your `<script>` tag


I mean, you could do that, but as someone who has been doing this for a very long time, I would not recommend it. If your application is very simple and has very few dependencies it might work, though I think you'll have a lot of trouble managing your dependencies across multiple environments. You wouldn't distribute a C application without a Makefile, and you shouldn't distribute or deploy a frontend application without the equivalent dependency management and build orchestration. These tools exist not just to help one developer create and app that works, but to help teams manage code contribution and dependency management across environments.


> You wouldn't distribute a C application without a Makefile

And yet, SQLite does just that. They distribute as a single .c file. I wrote a moderately successful lcov replacement in python that I distribute as a single .py file so people can directly run it without needing pip (if desired). There's a time and a place for needing build systems, but as a minimalist I default to vanilla + no build system and that serves me very well the vast majority of the time.

> and you shouldn't distribute or deploy a frontend application without the equivalent dependency management and build orchestration

Why not? That's the other thing. What are all these dependencies you are talking about that need "managing"? Most web apps I've written have needed 1 dependency (bootstrap CSS). Maybe PIXI or ThreeJS if making something graphical. Include it in the html, boom done, no npm needed.

Take a look at this guy's blog and tell me that he needs to abandon vanilla and start using a frontend build system: https://ciechanow.ski/gps/


> single language applications are single build applications

I don't know your background but most teams don't view "single language" as an advantage over other options. People choose a certain language because of internal infrastructure, libraries/ecosystem, performance, and whether it is the best suited for a project etc, rarely because "we use that language for backend so we should also use it for frontend" or vice versa


> I don't know your background but most teams don't view "single language" as an advantage over other options.

We view it as a massive advantage, assuming we are on the same page with "single language, plus HTML/CSS/JS"

Our language is C#. Our web "framework" consists of the string interpolation and verbatim operators. Most of our views take the form of:

  var finalHtmlResponse = @$"
    <html>
     {DiyPHPViewEngineRabbitHoleEntrance(httpRequestContext)}
    </html>";
I actually tried using the cshtml/razor engines because it seemed "more proper" but after 2 days of dependency hell I decided to go back to raw string interpolation. If you are able to build a functional website using static sources and have the barest capability to compose functions and strings, I do not see why this path would provoke any serious anxiety (other than it not being popular).

Imagine being able to directly invoke some utility or other backend method from your HTML view source pipeline. If you write it all in the same language, this becomes feasible. The moment principal rendering is outsourced to the client (or some other language), you are talking about a JSON API + distributed state circus and all the hell that must go along with it.


I mean, JS is a language, so this would not really qualify. I have to wonder how you expose the state of your C# app to the JS when that needs to happen. Perhaps... with JSON? In which case you are just doing JSON API + distributed state, except in a more complicated way with C# thrown in for good measure. You could simply render your DOM in JS/TS on the backend and save yourself a step. Hell if you are really that opposed to writing JSON APIs, you can just write a Node app that queries the database directly. I don't really recommend doing this since I think exposing data via APIs is good, but whatever floats your boat.

Either way, at some point your app is running JS/TS and CSS, and those two resources require some type of build process to manage beyond a certain degree of complexity. I lived through the hell of having to determine the load order of JS and CSS files by where the script and style tags occurred in the DOM. It was incredibly difficult to do simple things. Now we can do much more complicated things more easily, but language chauvinists object to doing complex things in what they view as "lightweight" languages. The thing is, the "correct" language to use is generally just the one that does the job best, and in this case JS/TS is specifically optimized for writing applications that interface with the DOM.


Not sure what you're really saying here. Teams often use languages because their existing codebases and the proficiencies of their existing members, but "we use that language for backend so we should use it for frontend" is totally a thing. You're somehow seeing multiple languages as an advantage when its actually a form of debt. Teams work in multiple languages because prior choices force them to, but if you can limit the number of languages and technologies in use it allows you to streamline and automate spinning up new services, make it easier to hire, and greatly simplifies deployment configuration. This is one of the major things that happen as you transition from an early stage to late stage as a startup. You hire professionals after a few years of not knowing what you're doing, and they cull all of the non-standard shit, lock in your architecture and languages, and then template our your apps, your configuration and your deployments.


> So, given that the frontend build is baked into _any_ application build, if you decide to do template rendering in any language other than JS/TS, you are adding another build to your project. That means you need to configure that build for all environments, configure CI, and support that build going forward. Save yourself the trouble and just render everything server-side in JS.

You had me until the last part which seems to contradict everything you said beforehand as you now have to test everything being rendered server-side. Why render it server-side if it's already in JS and capable of being rendered on the client? Optimize your bundles if you're chasing lighthouse scores.


You render server-side in JS/TS. You can use the same components, same tests, same code running on the server and client. That's the whole advantage.


"Frontend builds are basically a requirement for any application with a UI"

I disagree with this premise.

Dynamic languages don't have builds either.


Since JS people target multiple browser versions and vendors, building is basically a requirement.


Builds are absolutely not a requirement for targeting multiple browser versions and vendors.


It's the other way around. Having multiple targets increases the motivation to use build systems.


Why would that be the case?


JS has one of the most painful and ludicrous developer experiences in the industry (right next to Python, and C++).

Sane dependency management is NuGet, not NPM. Sane build tooling is dotnet build, not npm run build (is this multithreaded/parallel yet?). Sane CI is achieved via dotnet package; then chucked into whatever CI workflow.

It just works. You don’t need to mess with it. It adds negligible overhead.

The DOM is inefficient — entire page loads are quicker than rendering changes in-page (accounting for latency, and using chromium’s Blink renderer). The box model is inane. JS is a horrible, cobbled together language (like Python) initially designed by a naive. I would sooner write my own 2D renderer in WebGL than deal with HTML/CSS/JS/Rendering pipelines.

In my many years of being a web$hit, I have always had to fight the frontend ecosystem to stop being daft.


I appreciate how the tree of responses to this comment are of the form:

> I agree/disagree with the article's premise because of this thing I absolutely know is true.

> You are totally wrong.


1. You can share templates between front & back-end using any language. (im not talking about WASM)

2. CSS has NOTHING to do with js/ts.

3. Most single page js applications require SSR anyway, otherwise you have a blank screen or spinner until the browser has downloaded & intialized everything.

Personally, i dont care if it's SSR or SPA. But the js/ts community tends to use things like webpack in combination with ~20 packages which themselfs rely on ~20 packages, resulting in index.js files that are +2MB... That's bad programming.


Man if you think 2MB is big, you should check out the size of the build product from a compiled language. And if you have an issue with nested dependencies, you've should check out the build a Python or C application which similarly require you grab all the dependencies, and then the dependencies of the dependencies, before building. That's just what dependency management is about.

If you have a frontend app that requires loading a 2MB bundle in the browser, then whoever configured that application did not know what they are doing. There are lots of ways of optimizing JS bundle sizes, and SSR is actually one of the best. With SSR, only the code that executes on the frontend gets included in the client bundle. Webpack is one of many build orchestration frameworks you could use, though honestly at this point you rarely have to actually write custom configuration for frontend applications. A great deal of standardization has happened over the last 5 years, and generally you just use a template for your use case.

As someone who has worked all over the stack, from API development to data pipelines to infrastructure to client-facing application, I find the dismissive attitude of other parts of the stack incredibly bizarre. It's a tool, it exists for a reason, and if you don't see the reason it's probably because you don't understand the problem.


> So, given that the frontend build is baked into _any_ application build, if you decide to do template rendering in any language other than JS/TS, you are adding another build to your project.

I’m looking at you, JSX. >_>




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

Search: