People downvoted you, but I completely agree. It looks like this is NOT satire, but I hope you turn out to be right. Maybe someone has some sense of humor and enough time on their hands left to pull such stunt.
My bet is on someone forget to take it out of the template when the rest of the copy was added, and it will be gone in a few days with a realistic list item there.
I think it's mostly like a tongue in cheek acknowledgement of how everyone in big techs is fighting so hard for a promotion that they aggressively brand the heck out of every library, exploit, and "new tech" they scheme up, even if the thing they're mentioning is using weird language for a concept that isn't new.
Hydration is a technique where the content is rendered server side then client side JS attaches the necessary event handlers to make the UI interactive
Looks nice. A lot of ideas shared with remix but native to deno. Will def check it out when it’s production ready. Also, beautifully juicy hero animation.
From what I can tell, Ryan Dahl doesn't have anything to do with this (other than it using Deno). At the very least, he isn't a contributer to the Repo.
Deno is repeating a lot of the same things from node, but its in typescript now, and there's some rust involved, so that makes it good. Wait till you're this deep into your career and people are still hammering square pegs into the same well worn circle holes and you'll be the same way.
Gotcha. So you did respond to the wrong comment. Thanks for clarifying.
edit: 0des edited his previous comment to be much less hostile after I wrote this one (without indicating he did so), and then told me to "settle down sport" now that my comment seems a little aggressive. Really bad etiquette.
I don't fully understand the difference between this (and something like Remix, which seems similar) and other frameworks like Next.js (React) and Nuxt.js (Vue). Can someone explain a bit about the differences, and pros/cons to each?
Sure - this seems to be an implementation detail, though - eg, Remix and Next.js are both on Node.js but seem to have some difference that's not abstracted away, in terms of how you develop, how concerns are separated, etc.
I would say that deno vs node is the biggest difference, with node you need to setup and maintain 3rd party tools (bundlers, transpilers, etc) but with deno all that tooling is first party, so in theory is less things to install and worry about.
Deno has other advantages in paper, like official ts support, all the tooling was written in rust (so it's more performant that the default ones that the others use).
The only downside right now with deno is popularity and maturity of the ecosystem, it is just too new, so you will have hard time finding what you are looking for that works out of the box, while a lot of companies invested in node official packages.
The end result might be same but all of these frameworks/library/tools have some tricks up their sleeves that makes things easier for developers to implement certain functionality.
The major difference with Fresh is that it runs everything just-in-time when it is needed, hence doesn't require building no shipping anything by default to the client(but you can still ship some JS for client side interactivity).
The key here is no building (packing, bundling, transpiling). This don't just save time but actually removes the complexity as what you see is what you get. The only things that ships to users visiting your site is around 0-3kb (plus client side JS you decided to ship), not prebundled transpiled polyfilled prebuild 10mb JavaScript.
Since it is Server Side Rendering, the performance is based on design decision.
It’s in the same space as Astro. I can say with certainty without even looking at my Twitter feed that the Astro team will welcome more work in the space. Even if it’s not “better”, everyone leading FE web projects who isn’t a dilettante is learning from and inspired by each other’s work.
> The key here is no building (packing, bundling, transpiling).
How is that possible? In the documentation (https://fresh.deno.dev/docs/getting-started/create-a-route) I see .tsx files... so I imagine that at least one needs to compile TS to JS and then JSX to JS. Perhaps I got that wrong, though and browsers nowadays support TSX out of the box.
How does the counter demo work? I saw no network requests so it must be supporting a client side computational model. There must be TS to JS compilation of some sort.
Nit-pick: It does have a build step to generate the manifest file, at least currently. This is needed because Deno Deploy still lacks dynamic imports. So, their claims of no build step are as of now still aspirational.
(I am not affiliated with any of these technologies, but am a Next/Vercel customer. I am also not super familiar with anything except Next, but this is my attempt at an explanation.)
I think they all try to solve the same problem: how to get a modern interactive app to run on (and be performant) what is essentially a hacked-together ecosystem, HTML + Javascript, with decades of backward compatibility baggage. The essential problem is that browsers work on the ancient and really poorly designed DOM, but developing against the raw DOM sucks. It's fine if you have a simple webpage with headers and some text, but once you get into stateful UIs, it gets hard to maintain pretty quickly. So there's a mismatch between user experience (in HTML) and developer experience (terrible in HTML, better in other frameworks). So developers of complex apps end up abstracting it away with something like a JAMstack.
So you have things like React, which is essentially a UI library (vs a more fully-featured framework like Angular or even the older Rails stuff, or something like Laravel/Symfony for PHP or whatever the .NET equivalent is). React lets you compose apps not out of DOM primitives but components you define yourself, which in turn are reusable and composable.
But there's a lot of things that React don't handle out of the box: page routing, state persistence, static builds, image optimization, hot reloads, CDN caching and invalidation, etc. A lot of teams end up reinventing all those wheels, or else clobbering together 80 different open-source solutions and 10 vendors. It gets hard to maintain very quickly.
Enter Next.js, one of the earlier successful React-based frameworks. It turns a React app from a quirky UI library into something almost beautiful, because you can now make an entire app, not just a UI, using React and some easy to learn JS config objects.
For example, to make a blog with React, you'd first need a CMS (let's assume you have that part figured out) and an API (also figured out). You can write it as a single-page app, using fetch() or whatever to query the API every time. But then the client has to download that and then render the page. If the CMS is on a different host than your webpages are, it can take quite a while. That whole time your user is waiting, seeing a blank page. And if your CMS goes down, your website goes down, even if the content's been the same for days.
Anyway, you could try to statically bake all that into HTML, but then every time you add a new blog entry or update an existing one, you have to rebuild your project. And then if you want it to be fast, you have to invalidate all your CDN caches.
Next.js essentially takes care of all of that for you, in one easy to use and well documented package. Combined with Vercel (the company behind Next.js, who provides hosting) it also abstracts away all the complexities of the buildchain, CDNs, invalidations, etc.
As a duo, their most powerful feature is rehydration. You can code your app as though it were a single-page app, using React to compose components and pages, combined with file-system routing, to create a whole site. But then you push your changes and that's where the magic starts: Your Next.js server (like Vercel) picks it up, builds it with data fetched server-to-server from the CMS, bakes everything into flat HTML + CSS, and invalidates it across the CDN within seconds. At this point, any user who visits your site will be able to download the HTML + CSS, even with Javascript disabled -- the client does not ever speak to your backend directly. To them, your page is just a static HTML page, served straight from the CDN edge. This means the client doesn't need to load React to see your page. They can have JS disabled and it still shows up normally, it just won't be interactive.
Seconds later after the HTML has loaded, some "bootloader" JS then downloads all the other JS that enables interactivity and dynamic data fetches (comments, etc.)... all invisibly to t...
I've actually worked with things like Create React App, Vue CLI etc a lot but never any of the "meta frameworks". Based on what you are saying, it seems like the main difference it where things are evaluated? So, if I do my filtering on the client (with React) I need to make a request, get all the data, filter, render. For something like Remix or Fresh, you can do it on the server first [0]. Either way, the user has to wait, it's just a different kind of waiting:
1. Pure front-end solution (React) they wait on the front-end to handle it all.
2. Remix or Fresh, they are still waiting, it just happens on the server.
It seems like there isn't a significant difference either way - ultimately, you are still waiting, as a user. If the payload is huge, maybe the server model is faster - unless the server is getting smashed with requests, then it'll actually be slower?
For responding to user interactions (like filtering or searching) there isn't really a significant difference; like you said, it's just moving the "wait" elsewhere.
But many sites are more heavily read than interacted with: blogs, news, documentation, even to some extent HackerNews and comments. These are all "write rarely, read often" sites. In those cases, prerendering can be way faster both for the end-user (it's just HTML being downloaded from one single source) and also for the origin server (you build once, CDN caches it everywhere and takes over from there). Typically, the tradeoff is that it's also a PITA to manage these buildchains, especially once you get into obscure webpack or babel configs. Next.js handles it really elegantly.
Next.js has other benefits too, especially when coupled with Vercel. It is more than CRA + static builds, and even if you never end up using the rehydration system, the routing/image optimization/per-commit preview sandboxes may still be helpful, though not life-changing. For me the killer feature was being able to detach the data layer from the (write-rarely, read-often) frontend, such that the frontend could always just assume it would have access to the latest data from the API (because Next.js takes care of that).
That version is running on Drupal. Some of it was in a Drupal template, some of it was in-house PHP. To fetch data, we had to use a mix of Drupal built-ins and some raw SQL, mixed into some ugly templating language. Then through custom modules we had to add jQuery and React, sprinkled on top. Drupal had to "build" the page into HTML whenever we save, and then a separate buildchain would add back the Javascript on top of that and try to bundle it all. The developer experience was ugly and required needed at least four languages (Drupal, PHP, jQuery, React). Filtering is done serverside, so filtering by e.g. Type = 3D movie requires an API call and takes several seconds. If you turn off Javascript the whole page breaks and you can't access any of the links anymore. This version is pretty fast thanks to in-house optimizations and extensive caching by Pantheon (a specialist PHP host), otherwise it would be really, really slow. Our dev and staging machines were hell to use because every page took like 10-20 seconds to load.
That is 100% Next.js/React and only that, no more PHP or jQuery needed and no other frameworks. Data was moved to a headless CMS (DatoCMS in our case, which returned convenient GraphQL responses). It is slightly smaller over the network. All filtering is clientside and instant. If you go to a different exhibition page, it just has to load the JSON data for the new exhibition (text and image URLs + thumbnails), in like a 25kB JSON instead of the whole HTML page (headers and footers and all) all over again. The images are resized on the server for your viewport needs before they're sent to you (though TBH I am not a big fan of that feature because it's not preloading images right now). Even if you had JS disabled, the page would still load and the images and links would still work, you'd just lose the interactive filters.
So for users, the new version is hopefully a bit faster. The real improvement was in the developer experience, being able to code everything in React and not have to think about how it's going to get rendered into HTML or how we're going to balance our caching strategy (invalidations vs not overloading origin). And devs didn't need to use PHP at all anymore.
Given all the benefits you have listed, would the next big bottleneck to solve be the backend? I think it would be better to reduce/get rid of JS/Node and move on to server side Julia or C++.
For that simple page, the backend is a headless CMS that the vendor maintained. We just put content in and get GraphQL out and did not have to worry about how they hosted at all.
Sometimes it also depends on whether your local CDN edge has a hot copy. You could try a forced refresh and see if it's faster the second time? Up to you :)
The Drupal version is seeing production traffic, while the Next version only sees a few devs now and then.
I hate Drupal as much as the next guy, but I have to defend one thing about it: it doesn't have to be slow, and it doesn't have to have jQuery. Just get rid of all of the bloatware that comes out of the box, and then don't solve every problem with a plugin/module. I know, a 3rd party module for every little thing is exactly how Drupal development looks in most companies. Sorta like jQuery a decade or so ago.
Anyway, with a bit of discipline and some frontend tricks (preconnect, preload, async) you can create a Drupal page that's super fast. And it would actually serve less code to the end user than a page based on JS frameworks (as all things happen on the server).
Yeah but next gets you the same benefits without needing PHP or a DB (for the frontend). Drupal requires a LEMP stack, which is both hard to maintain and hard to scale/replicate.
You still need a place to store actual content/data, of course. But that could be any store or service that gives you an API endpoint to fetch from.
The HTML it returns is really big! 374kb before compression. I turned off Javascript to see how the page loaded without it, and it still downloaded the whole 374kb HTML (I guess that's to be expected).
I dug into the HTML and realised that the reason for the size is that Next.js includes a <script id="__NEXT_DATA__"> element that contains the entire data of the page's components as JSON for React to hydrate. This JSON takes up 60% of the whole HTML file! I suppose it's prioritising smooth rendering over reducing data use, but it doesn't seem very optimal, tbh. And it's really inefficient for browsers operating without JS, since every navigation click requires downloading a bloated HTML file.
I found Github issues, SO questions, and blogposts about this drawback, and it seems like this is a common practice for even the largest websites. This massive duplication seems to be a problem that newer frameworks are trying to solve. I wonder if non-dynamic sites like this aren't better off just being static HTML served from CDNs, since they aren't interactive.
Also, the main stylesheet is 1.12mb uncompressed! Bootstrap is part of it, but it seems like there's a lot of other CSS?
(Now I understand more about why my web browsing on mobile consumes so much data even on low-media sites, ouch.)
So I don't want to take away from your main point: That these frameworks add bloat (even more on top of React). It's an important consideration. Like you said, it's a drawback/trade-off. In our case, we decided it wasn't a dealbreaker and would still be worth it because:
1) That 374kB file is only like 50kB gzipped. We had bigger fish to fry/optimize, like that massive CSS. (Which is a holdover from the PHP days. Phase 2 of the project would eventually have refactored that and tree-shaken it, but it was out of scope for the prototype.) A lot of the bloat you see is because that's still a work in progress and they haven't had a chance to do any optimizations yet. A future version would probably get rid of much of that CSS and maybe even Bootstrap, then think about webfonts, oversized images, etc. There's a lot of work on that front.
2) Our target audience wasn't expected to have Javascript disabled, and with it enabled, Next's hybrid rendering model actually makes it really fast to navigate between pages after an initial page load. In an earlier test, we had the individual exhibition pages side-by-side, the Drupal version next to the Next one in iframes, plus back/forward buttons to navigate through each exhibition in sequence. Originally that was meant just as an easy way to catch visual differences, but we realized that the Next version was loading almost instantly (couldn't even see it load), whereas the Drupal version took 4-5 seconds per navigation. It turned out that Next was able to just download the tiny JSON (~20kB) for each exhibition and injected that into the React shadow DOM for updates; it didn't have to download anything else while navigating between navigations. That was an unexpected, and really powerful, feature that would normally only be available in SPAs.
Realistically, this means that if users had JS on, the initial page load might be a bit bloated, but subsequent navigations between pages should be MUCH faster.
3) The JSON shape was also an artifact of our CMS API (in GraphQL). If we wanted to, we could've optimized it before sending it over the wire.
4) Most importantly... I want to reiterate this... the main benefit of Next.js is NOT page performance, but developer experience. To the extent that there are any improvements at all to page load speed, that is a nice side effect. But even if there weren't, it would still be worth it for us. The big difference is in being able to quickly create new pages/templates, in a single language (JS), with a zero-stack configuration. Especially once we also decided to move the content to a hosted headless CMS. That meant no more LAMP stack to maintain, no more DBs to prune, no more fiddling with CDN caching, Drupal modules, Docker, CI/CD etc. Previously we were spending 80% of our dev time fighting our own stack and framework (Drupal is really really hard to work with, even compared to the messy Node/React ecosystem). Next got us out of the DevOps and infrastructure game completely so we could focus solely on the frontend, and Next + Vercel takes care of everything else. It's not just "serverless" but almost stack-less in a way (managed). All we had to do is write React, push a commit, and done. For a small team, that was HUGE... being able to push out a new template in a matter of hours instead of days/weeks, and being able to deploy to production in seconds (and roll back in seconds) too. In the Drupal world, there are companies like Pantheon and WPEngine and Acquia that try to do the same thing for the PHP landscape (and they do it well), but Next + Vercel is waaaaaay easier and faster. Other competitors in that scape (for JS) are Netlify, Gatsby, etc. These Jamstack hosts are gaining popularity because they are so much easier to work with than the traditional backend + pipeline + frontend model. But of course they have their own tradeoffs and aren't right for every use case -- for example, if we anticipated heavy user interacti...
>Seconds later after the HTML has loaded, some "bootloader" JS then downloads all the other JS that enables interactivity...
So until that happens the UI looks functional but isn't. The user is left to tap/click furiously on that button but nothing happens?
It sounds to me like this is only suitable for pages where interaction is an exceptional thing that users will only attempt to do after reading some content.
I throttled it down to Chrome's "slow 3G" setting and it still worked fine. The filters were active as soon as the page displayed, though the images took a lot longer to load after that.
There might be cases where the issue you describe occurs, but I haven't actually seen it in testing. If it's a concern, you could of course add throbbers or the such. But generally, in our limited tests, it hasn't been an issue.
But again, the benefit is mostly to the developer experience. It's a lot easier to write everything in React than to have to switch between PHP and Drupal (as in the admin UI) and JS. There are some benefits to the user experience if done well, but the same could be said of a statically cached Drupal output.
> That is the "rehydration", taking a React app that you wrote and the server buildchain "dehydrated" (baked into HTML + CSS), but then rehydrating it to add interactivity back. Yes, you could do all that manually, but Next.js makes it magically trivial... you never have to think about it, it just works. And it's lightning fast.
Actually I think the big trend in JS front-end development is realizing that you do have to think about it! React rehydration is often a very slow step (whether it's Next.js or anything else, I don't think it makes a difference), definitely not "lightning fast" on non-trivial apps with lots of data. Islands architecture goes a long way towards solving that but it's still a bit limited today.
What happens when the user interacts with the page while it's being rehydrated? Is that click eaten, does the user see some error, or does the page remember the click and run it when it has pulled in the relevant js?
“The page remembers the click” was the original intent [0], but the latest version of React includes a feature called selective hydration [1] which can hydrate a component synchronously in response to an event if possible (i.e. without replaying the event). Naturally React itself has to be loaded for any of that to work.
It doesn’t. This only works once React itself (i.e. the JavaScript code for the library) has loaded, which usually happens pretty quickly. The user-written React components might not finish loading until much later.
I am not sure how it works behind the scenes -- honestly, that's one of the drawbacks of Next, in that a lot of it just "black box magic" -- but it still seems to work fine when we throttle down to 3G. I am not sure how it decides which scripts to hydrate in what order... we were saving that optimization run for the end, but I changed jobs before that could occur (sadly).
There are some ways to work around that, if it actually turns out to be an issue (which it wasn't for us)... discussed it a bit more in my other response: https://news.ycombinator.com/item?id=31727249
at the top you mentioned "Rails". Rails handled the backend. You defined database schemas. It built forms to edge them. To a certain level you install got a working front end and backend.
The big standout feature that sets it apart for UX is partial hydration. DX like Next (or whatever similar), and UX like plain HTML plus some isolated interactivity, is becoming a focal point for a lot of the current crop of FE tools. Astro has been a big player in this area, Marko doing it for years, Qwik is another really compelling option. But the more the merrier where devs can dev how they want and users aren’t getting gigantic globs of JS they don’t need or want.
Why use '$' as the package namespace prefix/identifier instead of the already agreed upon convention of '@'? E.g. '@fresh/{package}' vs '$fresh/{package}'.
Seems like a departure from the norm for no reason unless there's some Deno particularity about it.
Because the '@' convention is for organizations, not the actual package, e.g. '@company/pkg'. In this case, '$fresh' is the actual package, and there is no organization name.
This just may be the Deno standard for their import mapping functionality since they also do full URLs for imports like Go (sans schema) normally.
Deno is also just not exactly like JS ecosystems, and that's exactly the point too. Opinionated defaults, out-of-the-box support for TypeScript, death to NPM.
That’s because it’s literally, not conventional templates. It is, from what I gather, Preact components, which can be rendered on the server and client isomorphically. The same component code runs on both sides. That’s not templates.
That is a weird term for two reasons. First, isomorphism is an invertible structure-preserving mapping between two structures. While the trivial case of that mapping being an identity is technically also isomorphism, it renders the relationship between the two structures (here code bases for different environments) into an identity as well. At that point the multiple code bases you're talking about are identical, not just isomorphic. It's like calling humans "vertebrates". While technically correct, if you're talking for example about the consequences of wars, do you talk about the loss of human lives, or the loss of vertebrate lives? I imagine it's not the latter.
And second of course, "portable code" had been the accepted term for this "pattern" (if you can even call it this way) for decades already. I'm not quite sure why one would feel the need to randomly rename things that have already had perfectly functional names.
The word portable is too general to be meaningful here. If I said my JS library was “portable” most would assume it meant that it ran across multiple OSes under Node.JS. If I said it was isomorphic, I need no further context, because it’s a well-understood bit of jargon in that context.
Personally, I don’t really think it’s useful to dissect the semantics of every bit of jargon; plenty of it is semantically imperfect, like the word “factoid” used to describe factual information or figurative uses of literally. It’s just a word being used to describe a somewhat specific concept in the context of a niche. You would still need to be initialized in what it means in context even if it were semantically correct. The helpful thing here is that a simple search like “isomorphic js” gets you up to speed almost immediately. OTOH, if I search for “portable” libraries on NPM, it’s all “cross platform” stuff. If this term didn't exist, that would make it hard to find libraries and frameworks satisfying this niche.
It’s neither here nor there, my chief annoyance with this general thread was people claiming that “this is just like PHP” or “this is just like Rails” and the problem is, it’s not really like that at all. It’s not like older attempts at “live” server code, nor is preact components really much like templating. The different approaches have their merits, and achieve similar end goals, but the developer experience is starkly different in ways that are maybe difficult to understand from simple examples, but absolutely definitive in real world apps. Don’t look at me, though. I write all of my backends in Go.
Vercel is doing a really good job with Next, but it's good to see some competition. Of course, that means there's now 65,535 + 1 more way of serving a web page using Javascript (sigh).
Rehydration is a really big deal. Sounds dorky but it dramatically speeds up load times and such by serving flat HTML and injecting JS afterward, like the old days, except you can write code like it's not the old days.
Have you seen Remix yet? It’s pretty compelling in terms of competition for Next.JS.
It makes different trade offs and isn’t strictly better by every metric, but overall I’m very happy with it for the two use cases I’ve tried it with. It’s a very low overhead framework once the simple conventions click.
I’d still like to check this out, then redwood and a couple others too. I’m not huge on these frameworks in general, but they tend to have some excellent ideas and smart people behind them, so plenty to learn by experimenting with them.
I've heard really good things about Remix, especially the nested routes. But I think Next is trying to copy that in Layouts? https://nextjs.org/blog/layouts-rfc
I use Next not just for the routing and composition and hydration, but for all the other quality-of-life improvements (image resizing, buildchain configs, hot reload), especially when it's paired with Vercel (per-push sandbox builds, stale-while-revalidate, seamless CDN, access to serverless, etc.)
I'm really excited to see how Remix and other Next competitors evolve, but for now, I think it's still the most "full" stack of the React frameworks? Is that correct?
That’s correct about Layouts, and I agree, if you want something with all the quality of life tooling ready to go, Next seems to be the way to go.
It isn’t too hard to get the same/similar tooling outside of the vercel ecosystem, but it does take know how and a bit of extra time. It isn’t obviously worth it unless vercel isn’t meeting your needs in my opinion/experience.
I mostly play around with other frameworks in order to learn, but for any client where a frontend framework made sense I’d almost certainly choose Next.
Edit: people also get bent out of shape about perfect hydration and shaving milliseconds here and there, but like you mention, Next offers such a comprehensive solution in a situation where routing and hydration are only a part of the big picture. Next gets you really far without any effort up front, which is crazy. I really like it!
For sure, Vercel was working on nested routes before Remix was a thing, as far as I know. A lot of people suggested it was lifted from Remix. It’s not a new idea at all and people have been asking for it for years.
Arguably there is nothing all that novel in either framework. We are constantly reiterating and rebuilding wheels, doing it a little better each time.
I’m glad to see the Remix take in things gaining steam though. It’s quite a bit less cognitive overhead than Next without any magical trade offs. Nothing ground breaking, but definitely better at things I care about.
Like most things, a blend of solutions would be ideal
Next is lovely to work with but it has a flaw. It loses client state between pages if you use getServerSideProps. For any app that needs to load some up to date data on every page if the user is hitting it for the first time, but doesn't need to load it if the client already has it, Next doesn't have a solution. You end up using a persist gateway pattern which is a massive amount of work that you shouldn't really need the client to do.
The problem is that that's pretty much every web app. Every time I've used Next I've end up abandoning SSR and building a plain clientside rendered app.
Also, next/image only works with a CDN, ie Vercel, it doesn't work with static site generation. It's been an open issue for years and I honestly now feel like Vercel doesn't fix the problem on purpose, to push more people to using their service rather than simply exporting to a static host which are plentiful.
You can set next/image to work with Cloudinary or Imgix or a custom provider. It gets the job done that way, but yeah, the experience isn't as smooth as with Vercel.
Same with incremental static regeneration and some other features... Next is obviously built not just by, but also for, Vercel. Vendor lock-in already is a small issue and may become a bigger one if they keep going down that route.
been saying it for awhile... Next.js is an ad for their services.
Take a look at their middleware. It's designed to be used solely with their serverless cloud BS. It uses a janky JS sandbox which means you can't use node APIs. It's just horrible for no good reason at all. I've never seen middleware so intentionally crippled anywhere before.
And the whole reason you need middleware is to maneuver around the flaws that the prior person mentioned with getServerSideProps.
Next.js probably seems great if you're writing greenfield code in a dead simple web app. Routing/URL handling on Next.js is just broken. This is all glaringly obvious if you've been around the SPA/SSR world for more than a day.
> Rehydration is a really big deal. Sounds dorky but it dramatically speeds up load times and such by serving flat HTML and injecting JS afterward, like the old days, except you can write code like it's not the old days.
Hydration is actually a compromise, and not a great one for UX. It’s in fact been said to be “pure overhead”, which I think is an overstatement but only slightly.
What you’re describing in the abstract is spot on though. Serializing server state to HTML and sprinkling in interactivity to pick up where it left off is exactly where we should be headed.
And yes it is like the old days, and yes all of HN will rapidly say so. The big difference now is the convergence of code written for both server and client, and compilers which help strip down and optimize what happens in the client.
Hydration in the current sense is re-running most of what the server already did, to recreate the runtime state it already had. That may be perceptively faster in terms of metrics like first paint, but it’s a huge barrier for time to interactive. All the more so when most content is static and has to load twice—fast first as HTML, then slower and redundantly as JS.
The best way to solve this is to not serve or hydrate anything at all unless you need to. The “islands” approach is a very good, but coarse, way to solve this: isolate components which are actually interactive, treat the rest as static. A more granular approach—termed resumability by Qwik and as I understand it the forthcoming version of Marko—works by treating the server-generated HTML as the initial state. The code executed from there is much more isolated than a full component.
I don't think anyone believes JS is a great language. It's just what we're stuck with.
How I wish something, anything better could've taken over. .NET was beautiful to work in. Maybe the native apps for iOS or Android are cleaner (I dunno, never tried).
But browsers are what the world use, and they only speak HTML and Javascript (sadly). So we're stuck unless something else manages to create a sea change in how the world uses the internet.
Right, but not all of it. The way Qwik serializes it is (this is from memory and probably overly simplistic, but conceptually approximate):
- Primitives already present from the server render are serialized directly into the HTML, and the compiled code reads those values from the DOM
- Everything else is split into fine grain chunks, assigned a special identifier (Qwik uses URLs) which is serialized to the HTML to fetch (which can be eager or on-demand) and activate interactivity as needed
My understanding is that currently Qwik serializes more than necessary—i.e. can be optimized further to eliminate non-interactive chunks from consideration—but that they’re focused on reducing JS cost first.
The way I read it, you might have lots of javascript to compute and render your e.g. counter control but you can keep that on the server side, only return the (much smaller) piece of HTML code and ONLY the JS needed to make the control interactive.
I don't know whether this means that it doesn't work as SPA any more since if you want to keep the best of both, you will end up creating more4 complexity, a new framework to learn and probably get marginal improvements at best.
that’s how it works, but you also need to attach event handlers and set up the state for the framework on the client-side (for subsequent interactions).
> The big difference now is the convergence of code written for both server and client, and compilers which help strip down and optimize what happens in the client.
I understand the spirit of your comment, but this was/is also true of Google Web Toolkit (GWT).
I’m going to have to take that on faith, their site doesn’t appear to ship the JS necessary to open the nav menu. But clicking through a few links confirmed what I recall: the major difference (apart from language) is the component/templating approach. Not that one is inherently better than the other (though I do personally prefer JSX), but bringing this concept to a dev environment which thus far mostly lacks it is a good thing for users. And with more flexibility in variety, there’s better odds users will get that experience.
> A more granular approach—termed resumability by Qwik and as I understand it the forthcoming version of Marko—works by treating the server-generated HTML as the initial state. The code executed from there is much more isolated than a full component.
Is that sort of what Phoenix LiveView does? Return a fully server-rendered page on initial load, then set up a "template" on the client side that can receive any values that change server-side over a websocket and patch them into the DOM?
This sounds conceptually similar, albeit maybe more similar to React Server Components? I’m really not familiar enough with Phoenix to get that specific though. Even in the JS ecosystem there’s a lot of nuance between seemingly similar approaches (hence why even commonly referenced concepts like hydration can be confused for what they actually do).
I think what Fresh is doing now is more similar to Server Components, shipping full components to the client. With LiveView, once it's set up on the client, the updates it sends over the wire are much smaller. https://fly.io/blog/how-we-got-to-liveview/ shows some examples of the idea.
> Hydration in the current sense is re-running most of what the server already did, to recreate the runtime state it already had.
It’s interesting that the problems with hydration is in some sense caused by the insistence on one-way data binding (deriving the view from the state). I imagine that with two-way data binding then you’d just need to attach event handlers and then the state would be derived from the view on the next interaction. Maybe.
It's really easy to make the states diverge this way. That's why the one-way binding is popular.
OTOH if there were a way to produce a two-way implementation from a one-way description, that could be great for performance. But this is already more CS than engineering.
I think you can have a two-way binding with a controlled update procedure, akin to one-way data-binding. I’ve read some people claim to do it by producing a kind of one-way directionality under-the-hood (?) from two-way bindings. The goal being that views can update state (and other views).
I think it was here I read it:
«‘2-way’ shouldn't be a problem if a component reports user events (perhaps transformed/mapped) to the domain model without changing it's own core state (disregarding throttling etc.) and only changes its core state in response to events from the domain model.« — peerreynders @ https://dev.to/peerreynders/comment/1objn
I’m not sure that gets you much. You still have to know which parts of the code are implicated in executing those event handlers, which very likely close over other state and call into other logic. To an extent you can get that with static analysis (as Qwik does, with one-way binding), but highly dynamic code is tricky no matter what.
Honestly it's unfair to compare a small e-commerce site made with Next to one of the biggest websites on the internet.
If Ebay was made with Next it would probably be much slower. React is the slowest at SSR of the modern frameworks. Amazon considered using it but it was too slow for them so they keep using Java + sprinkled JS.
I’m not sure why you’re asking me, but I just did a quick “how slow does eBay feel” on my really spotty mobile connection and it didn’t feel slow at all. Faster than HN, which is usually my fast baseline that responds even when I’m not coaxing my network settings.
This is neither ironic nor correct. But I will say I’ve described my mental model of Qwik as effectively that UX, but the compiler writes the jQuery for you.
> except you can write code like it's not the old days.
I imagine you mean that writing (frontend) code now a days is better than how it was in the old days. Well, at least from my perspective that's not the case. "Modern" frontend code requires:
- a package manager (npm)
- node (or deno or whatever)
- transpilers (or is it plugins?)
- TS
- 10K+ dependencies
And to be honest, what is all that good for? To being able to "hydrate" some server-side rendered template? Not good enough reason.
We've been able to replace a couple of client applications that previously used WPF with a React frontend (and a small native application that uses WebSockets to create a bridge between the browser and a particular piece of local hardware).
Updates are now easy-breezy (update the server and you don't have to touch clients at all).
There is a place for SPAs. I just don't think your typical grocery store website should use something like that.
What SHOULD grocery store websites use, then? I feel like they're some of the most complex websites around (if they do any ecommerce/online pickups at all)... between product reviews, indexing, filtering, sorting, checkouts, SMS/push notifications, geolocation, real-time inventory, etc. It's not the sort of site that says "easily built in plain HTML" to me.
If you think it's bad then why do you use it? Browsers still support just HTML. You can shove a just a script tag down in the page.
Eventually, you'll have enough devs working on this you'll start to run into issues with how you coordinate your work. Your site becomes large enough the code gets more complicated and needs organising to work on it without slowing you down. You'll start to reinvent the above tools to solve these problems.
Frontend/JS tooling isn't perfect, but don't pretend like other languages/systems (can) have a complex pipeline of build tooling.
Not necessarily, at least in the case of React and Vue.
Rather than using NPM, you can self-host react/vue (or preact if you need something even smaller), or serve it from Unpkg.
You don't need node/transpiler/bundlers if you're only targeting modern browsers. You can use modern syntax, async/await, ES6 import and a bunch of other features with static .js files.
JSX is a tough one, but there are solutions to that, packages domz and HTM are made to allow using React/Preact without NPM/transpilers.
Typescript is also a tough one. But it's also optional, although a good idea to have. I hope optional type annotations land in ES6 soon so typechecking can happen without anything resembling compiler phase.
-
> To being able to "hydrate" some server-side rendered template? Not good enough reason.
The "hydrating" parts is entirely optional in "modern frontend". It also needs some stuff on the server that is IMO significantly more complex than what I described above. But apart from some very specific cases, one don't necessarily need it.
Believe me, I hate the toolchain/buildchain as much as anyone. Especially TypeScript (see below). Luckily, Next.js also takes care of all that too! Out of the box it preconfigures all of it with sane defaults. `npm start` and you have a working server with transpilers all seamlessly configured, and when you change a line of code it just hot refreshes in the browser. On a `git push` to Vercel or a similar capably platform, the server transparently does all that and gives you a sandboxed preview environment for that specific build. It is magical.
But really, what I meant about "writing code not like the old days" isn't so much about the shitty toolchain (which Next helps with, but I agree it's shitty). Rather, it's the ability to write code like:
Basically, the ability to compose pages & apps out of components (which different developers can work on), and the ability to manage state in a central controller via Redux or useContext to avoid race conditions and the such. That sort of stuff is REALLY hard to do with plain HTML and JS, especially where there are multiple developers involved. React isn't a magical cure-all, it just makes it easy to componentize large apps into smaller areas of concern.
The shitty buildchain isn't a feature, it's an unfortunate side effect of browsers being limited to JS. Essentially it's a "compile" step that became necessary as the vanilla-JS developer experience wasn't able to keep pace with the complexity of desired business apps (and as devs of various skill levels flooded the market). So the developer tools kept growing, but they still had to be compiled/built into JS for the browsers. Next.js makes it relatively painless, compared to how it was just 3-4 years ago. But I agree, I hate that this is a step at all.
Ugh, as for TypeScript... I get that it's a necessary evil, but I spend more time fighting it than actual bugs... coming from PHP, it was already common practice to manually typecheck and coerce everything when needed, anyway. TypeScript often felt redundant and overly sensitive, especially when it came to async nullables, causing false alarms that React could just've silently handled with {isLoaded ? <Component/> : <Spinner/>}
But TypeScript is optional anyway. It's a superset/addon on top of JS, so you never have to use it if you don't want to. If it's scaffolded for you in someone else's project, usually it's just a matter of a either using a .JS extension instead of .TS, or adding a ts-nocheck or similar to that file. Other devs may hate you for that though, when your object or props ends up breaking theirs... so it's definitely a conversation worth having first :)
I started with https://alpinejs.dev/ linked via CDN, and OpenJSCAD, also linked via CDN - I wrote basic html, marked it up with alpine `x-model` and `x-data` tags, and sprinkled a little vanilla js on top. Everything worked well and I got 80% of the way through the project.
In the final 20% I ended up adding a bundler (parcel), so I could bring in an scss framework and override its variables. While it added a fair bit of complexity to the project (dev dependencies, parcel config files) I gained lighter files via parcel's tree-shaking and minification, auto-recompilation/reload during development, and re-usable html partials via `posthtml-include`. I'm also set up to swap to typescript quickly, if the project gets more complex and I start to get annoyed with the lack of compile-time type checking.
So, it's 2022, and you can write a web app without any of the things you mentioned (transpilers, package managers, typescript). Yes, adding even one of them nets you a 100+ dependency node_modules directory - but the reason we keep adding them to our projects is the things it gives us are NICE, and the cost (complexity) is mostly worth it.
You made a web site that displays a document. Not a web app. Web apps, like native apps, have a lot more UI state that needs certain patterns and tech to manage them properly. Many devs can discern the difference and use the correct tools. Some do reach for the wrong tool but it's not the tools fault.
Opinion only: I found their front page difficult to skim. It took me several scrolls-to-end-and-back to even realize they were trying to explain concepts on that page, not just showing screenshots. Normally I just page-down quickly to get to the features list or comparison table, but doing so here bypasses most of the explanatory animations. I kept wondering, "where's the section that tells you what this does and how it compares to other frameworks". Then I kept looking for a Features page on their top or bottom nav, but didn't find one.
Maybe it's just years of bad habits trained by seeing too many bad marketing sites, where the typical signal to noise ratio is really bad. I guess even when I see a good sales pitch, I don't recognize it as such anymore and try to skip through it... sigh. Sorry, Remix.
I think Astro is more likely the successor to Next.js and probably not remix. I think Next will steal the best parts of Remix but Astro was built with simpler foundations and has integrations for deno with Netlify edge functions among others and unlike Remix is not tied to React but you can choose your framework.
Remix is working on a Vue and Preact adapter, so won't be tied to React for long. I see the community is looking at a SolidJS adapter too. I'd say it'll be just fine
Other than helping creating websites, this has almost nothing to do with SvelteKit. SvelteKit:
- Requires configuration and build
- Doesn't support partial hydration
- Ship JS to the client by default
- Can also be used as static site generator or SPA framework (no server side code)
Early PHP and Ruby frameworks don't provide anything to help you write client side interactive code, so you are on your own there, and you have to bring your own tools to do this.
I'm really sad that this sort of attitude is common in Hacker News. I am not a huge fan of JS, but what I hate about this is not that it's critical of JS, but that it's clearly just a knee-jerk cynical reaction. This framework in question is not doing what PHP/Ruby frameworks were doing. Whether what it's doing is a good idea or not is neither here nor there, it's just simply that you aren't understanding what it is that it's doing, and yet still criticizing it as if you do.
We don't need this circus every time a new JS thing is released.
The fact that you think it’s materially different is amusing. The only “magic” here is injecting JS shims to handle bidirectional syncs for certain components (“islands” in their parlance). That is also something we’ve had for a very long time, though admittedly
it was kludgy as hell two decades ago (ajax polling, SSE, long-polling, comet, etc).
There’s companies that bet on deno/deno-like runtimes. It’s a move to having more options/control on sandboxing/embedding JS on server runtimes.
Think of how Lua is used. Heavy lifting in a compiled language with Lua on top to cover app specific logic.
Node is in a sense that, but with a stronger emphasis on being a general purpose runtime for JS.
Deno (and similar), gives you more options for embedding and restricting the JS side.
I think it’s worth keeping an eye on, because I think the JS world is soon in an refinement/optimization phase. It’s settling and stabilizing towards a set of core ideas and Deno might be part of that.
This feels exactly the same as Astro SSR (which I’ve been using recently and is great by the way). I guess this validates their direction. Happy to see more frameworks like this.
Even if you wanna be cynical, this is a really boring and overplayed take in my opinion. Most frameworks are indeed kind of bloated for running useless hello world demos. Most C compilers give you some kilobytes of code that isn’t necessary for hello world either, even worse for other respected and modern languages like Rust and Go. It can be forgiven if you consider that most of these things are not tuned for optimal hello world.
This comment is the overplayed take that because a lot are heavy frameworks, that this should be acceptable. As soon as something is classified as a framework, it seems ok to be >200kb.
If you take Tailwind CSS for example, when correctly using their CLI tool, it only includes the size of the css classes actually used, keeping it to a minimum, when compared to people just doing a standard import of the entire library. I like this mentality because it's offering the ability to be very lightweight, or as large as the 'framework' it offers. NextJS offers this as part of their build process, but not sure how big their assets are with it for a simple usecase.
The word framework doesn't really actually mean anything. People have a feel for it, but there is no concrete "this is a framework, not a library." However, I think that for most people, the criteria isn't actually related to how large the software is, but rather the feeling of using it. When you use a non-framework library, it feels like using a wrench or a drill; it's a tool. When you use a framework, it feels like you're writing code inside it, not using it. Frameworks can be small. The term "microframework" exists for this exact reason.
Semantics aside, the existence of things with different philosophies doesn't immediately invalidate everything that doesn't give you the same tradeoffs. For one thing, Tailwind deals with declarative CSS output, not imperative modular code. I'm not saying that makes it stupid or anything, but it's very apples and oranges. There are very few JS libraries or frameworks that can offer starting-from-zero KiB JS; maybe Svelte comes close? Ironically, if we're talking about client side bundles, it seems as though Fresh actually does start with 0 KiB, as it does not default to shipping JS code to the client at all.
This doesn't feel like a rational discussion at all. It feels like it's just necessary to come up with a cynical take because there's a new JavaScript thing. In a few weeks there could be some Rust FRP webassembly UI thing that has a 1.2 MiB hello world and hardly anyone will care.
Is this satire? I honestly can't tell, but it made me laugh.
If not, why in the world would a hello-world demo need optimization? By definition it's supposed to be the simplest thing you can build to showcase the features of what you're using. If the simplest project has the properties GP mentions, then it's not a good demo.
The difference is that it doesn't take 600ms for a Rust binary to render "Hello world!" to stdout. In the context of CLI apps, binary size is irrelevant to the functionality of the demo. In the context of web apps, bundle size and speed _does_ matter, so 108KiB and 600ms are very relevant data points.
Besides, I'm pretty sure that in this framework's case the final bundle can also be trivially stripped, but would that also reduce the render time? It's difficult to tell, and maybe those things should be mentioned in the demo. (Sidenote: I haven't confirmed whether what 0des posted is true or not; I'm just going by the fact that you're defending it.)
I know this comparison isn’t exact, but I didn’t attempt to engage with the supposed latency measure. That kind of measurements are really variable and hard to pin down. You’d need percentiles to make even an uneducated judgement, not a single random sample.
Still… a 100KiB bundle is not that bad of a starting point. It objectively isn’t, if you measure it up to other popular frameworks.
If you want to render random text and a button you shouldn't be using such frameworks at all. For a full-fledged web application a hundred kilobytes overhead isn't as crazy as you are making it seem.
I'm in Australia, and I see 18ms (with cache disabled) for the main page, then another 14 to 30ms for the js bundles (looks like some are done side by side).
The image of the dinosaur drinking takes 386ms, and the favicon is 132ms.
So for text and a button to increment/decrement specifically, it seems quite quick.
no hooks yet though, which limits compatibility and arguably developer experience. Preact has better compatibility - if that's something you're looking for anyway. I suspect that was part of the motivation as well. Also, Preact is 3KB full, inferno is 7.2 KB, if I recall correctly, may have also been a motivation here.
I both love it and hate it. Most of the features are similar to sveltekit/next.js. I get that the biggest benefit is the deno deploy integration for ssr on the edge. But I would have highly preferred a new flavor of sveltekit where deno deploy is a build adapter (like cloudflare workers currently are) and the script part of svelte could be set as "ts-deno". No need to reinvent the wheel yet again and split the ecosystem more.
It uses Preact, just in time bundling, and a number of other concepts that would probably be a pain to integrate seamlessly into those. Seems like a justifiable from scratch prototype.
> "To include this in a page component, one can just use the component normally. Fresh will take care of automatically mounting the island component on the client with the correct props:"
How does a developer know what rendering is going to take place client-side vs server-side, and is there any way to control this?
If I understood correctly, it all renders server side and then adds the interactivity where it's necessary, and in a react app is kinda easy to spot which components are interactive or not, the biggest difference here, vs a traditional react framework, is that fresh is more similar to astro[0] than next.js/remix, so it ships less js.
What I read from other comments is that fresh does code splitting, so for example if the interactivity is out of your viewport and you scroll down to that element, it will then load the js required to make it interactive, while I find that idea cool, what worries my is that it could take a few ms to load the js and then other few ms to boot that component and render it interactive. But I don't have experience with any of the frameworks (besides next.js where I build a small demo project to try it out).
He describes it as a post-Unix web framework (i.e. built on serverless primitives like cloudflare workers/deno deploy) with the goal of <10s deployment (which he says requires JIT compilation on first-request)
He really is the JS server-side sect leader. Plain wrong about so many things you lost count while he talks. Glad that the JS community, not that I am fan, left this dude behind.
What makes you believe the community left him behind? And he's only wrong from your perspective, especially as you say you aren't working in this domain.
> Well, NodeJS is the default for service-side JS. Node > Deno.
Are you aware that Deno is very new? I wouldn't say that Ryan Dahl got left behind because everyone hasn't switched to Node yet. There is a large amount of interest in Deno, exemplified by how frequently Deno projects make it to the front page of HN.
> React is the main driver for JS not some server-side BS.
Haha. Just because you hate JS doesn't change reality.
> The classic scripting arg. JS is a poor choice for scripting and hence, not used for it that much anymore.
This statement doesn't make sense. It never was very popular as a Bash replacement, if that's what you're meaning. And otherwise, it is the only option for browser interactivity. So it doesn't make sense what you're saying.
I am aware about what Deno is. But it is yet simply not the major leap forward that will get rid of NodeJS with that large ecosystem.
React was the first framework that requires the coder to really understand and utilize the modern features of JS.
Scripting something simple or spinning up a simple endpoint have always been arguments for NodeJS. R always talks about this. Terrible ground for decision making.
> Routes are defined as files in the routes directory. [...] If the file name is contact.js and is placed inside of the routes/about/ folder, the route will handle requests to /about/contact.
I can't say I'm particularly keen on being told what directory to put files in, or or being told that I must only code exactly one endpoint in each file. Why aren't I allowed to code multiple endpoints (e.g. for related functionality) in the same file?
Also, in what directory do I put my files if the url is of the form /user/{username}/page/{pagename} ?
In the case of Nuxt (which by default uses basically the same paradigm) I could circumvent this by using the package @nuxtjs/router.
I have no idea why this is the default behaviour, it sure feels something like a lot of people put a lot of work into and by then they didn't realise their fancy new feature doesn't make things better.
I think it’s a part of their convention over configuration philosophy. Say what you will about it, there are obviously drawbacks.
But I’ve noticed that it makes it easier to quickly understand new codebases in my organization. Everyone are using Next.js and all the apps have about the same file layout.
And it makes the routes easily greppable in VSCode/Ag/Telescope/CrtlP which I think is the thing motivating it.
I think it’s neat that having extremely fast project dir fuzzy finders has influenced framework design. Like how Django’s design is heavily influenced by how importlib works and would be completely different if Python modules worked differently.
What is a good argument against it? It makes understanding the layout of the website easily and saves you from having to come up with your own <custom> conventions around it.
I generally prefer keeping all the configuration in as few languages as possible and preferably in a single language. Adding filesystem-based config where a config option object in the main language of javascript would suffice goes against that.
Also, given a filesystem config, now I'm forced to have many very small files around for each route where each file is most likely just a call to another service handler. I'd prefer to mash most into bigger files that handle related but distinct routes.
Less important, but comes up, it's nice to be able to match routes based on code and not just string equality ... e.g. everyone seems to like having routes for usernames start with '@'
> fresh also does not have a build step. The code you write is also directly the code that is run on the server, and the code that is executed on the client. Any necessary transpilation of TypeScript or JSX to plain JavaScript is done on the fly, just when it is needed
I find this very interesting. I get that adding a build step can be a pain during development / deployment, but running your TS build once per deploy seems _much_ more efficient than doing it repeatedly, as needed. Or does it get cached , so it's built at-most-once? I haven't really dug in.
I explored using client-side service workers for build-less deployment workflows a while back, but the blocker was the initial visit when the service worker hasn't been installed yet. Ended up using es-module-shim's fetch hook (https://github.com/guybedford/es-module-shims#fetch-hook) instead, which worked quite well.
The repo itself is quite out of date at this point, but my current project, Reflame, is essentially the spiritual successor: https://reflame.app/
Reflame has the same ideals of achieving the developer experience I've always wanted for building client rendered React apps:
- instant production deployments (usually <200ms)
- instant preview environments that match production in pretty much every imaginable way (including the URL so we don't have to worry about special whitelisting for CORS and whatnot), that can also be flipped into development mode for fast-refresh (for the seamless feedback loop we're used to in local dev) and dev-mode dependencies (for better error messaging, etc)
- close-to-instant browser tests (1-3 seconds) that enable image snapshot comparisons that run with maximum parallelism, and only rerun when their dependency graphs change, and auto flake detection/recovery
It’s running on Deno, which builds TS on the fly with SWC (and does a bunch of other stuff with Rust-V8 interop). Generally speaking it’s close enough to zero overhead that Deno tends to perform better for TS source files than Node for JS source. I’m sure there’s plenty of caching involved, but even without SWC (like ESBuild) is a barely noticeable drop in the bucket.
- The dev experience is closer to the early days of PHP.
- TypeScript, Preact out of the box. No need to configure build tools / deploys much faster. It's a pain in the ass to make these working at the same time and targeting both browser and server nowadays.
- You can have interactivity without bolt-on client-side scripts that are different from other parts.
- The code could be running on the edges.
- I'm not sure what does the island based client hydration means, but sounds like Remix
Many other frameworks could do some of them but not all (Ruby needs JavaScript/Turbolink, Next.js need to build then refresh, etc)
Frameworks like Next or Nuxt often render each page server-side, shipping HTML to the client, but then also send enough javascript and json data to the client to "hydrate" the page back into fully interactive components. The whole site, then, really acts as one large javascript app once fully loaded.
The islands approach is different: pages are server rendered, but you can easily define islands of interactivity (like, say, an auto-complete search bar) where just enough javascript is sent to make those components interactive—and only when it's needed. You can control at what point exactly each component is made interactive: as the page loads, when the component becomes visible, when the user first interacts, etc. It's a great way to balance performance and rich interactivity. If the user never scrolls down to your photo carousel at the bottom of the page, the javascript is never requested.
If this sounds like what we used to do with say PHP & JQuery, you're not wrong. The difference here is we have the same javascript-based template logic and component model both clientside and serverside.
nope. deno runs "fresh" web server that spits out html. you would need a vps for that, until some hosting providers don't include deno/fresh as supported(unlikely in near future).
Fresh looks inspired by Remix. Is that right? Not that there is anything wrong with that. But given that Remix does claim to be production ready, what makes Fresh better?
I have been playing with Remix in a side project. I do like their simplicity vis-a-vis Nextjs. And the fact that it is all server rendered by design and not as a special case.
I don't think that fresh is better or worse, besides being pretty early in development, is somehow different and it doesn't run in node.js, but in deno.
462 comments
[ 3.2 ms ] story [ 346 ms ] threadThis honestly reads like satire. It sounds like something on the sarcastic VanillaJS homepage.
This gibberish being the second bullet point in a list of core features is a huge turn off. I know it’s tongue in cheek, but still
I think it's mostly like a tongue in cheek acknowledgement of how everyone in big techs is fighting so hard for a promotion that they aggressively brand the heck out of every library, exploit, and "new tech" they scheme up, even if the thing they're mentioning is using weird language for a concept that isn't new.
* Island refers to this https://jasonformat.com/islands-architecture/
* Island based hydration is a form of partial hydration where the boundary is the component islands.
https://en.wikipedia.org/wiki/Hydration_(web_development)
Docs should include obvious link to github repo: https://github.com/lucacasonato/fresh (edit: it's already in the footer)
Also, deno/x needs an update: https://deno.land/x/deno_fresh
edit: 0des edited his previous comment to be much less hostile after I wrote this one (without indicating he did so), and then told me to "settle down sport" now that my comment seems a little aggressive. Really bad etiquette.
Deno has other advantages in paper, like official ts support, all the tooling was written in rust (so it's more performant that the default ones that the others use).
The only downside right now with deno is popularity and maturity of the ecosystem, it is just too new, so you will have hard time finding what you are looking for that works out of the box, while a lot of companies invested in node official packages.
The major difference with Fresh is that it runs everything just-in-time when it is needed, hence doesn't require building no shipping anything by default to the client(but you can still ship some JS for client side interactivity).
The key here is no building (packing, bundling, transpiling). This don't just save time but actually removes the complexity as what you see is what you get. The only things that ships to users visiting your site is around 0-3kb (plus client side JS you decided to ship), not prebundled transpiled polyfilled prebuild 10mb JavaScript.
Since it is Server Side Rendering, the performance is based on design decision.
This 0-3kb includes HTML or some JavaScript runtime ?
How is that possible? In the documentation (https://fresh.deno.dev/docs/getting-started/create-a-route) I see .tsx files... so I imagine that at least one needs to compile TS to JS and then JSX to JS. Perhaps I got that wrong, though and browsers nowadays support TSX out of the box.
I think they all try to solve the same problem: how to get a modern interactive app to run on (and be performant) what is essentially a hacked-together ecosystem, HTML + Javascript, with decades of backward compatibility baggage. The essential problem is that browsers work on the ancient and really poorly designed DOM, but developing against the raw DOM sucks. It's fine if you have a simple webpage with headers and some text, but once you get into stateful UIs, it gets hard to maintain pretty quickly. So there's a mismatch between user experience (in HTML) and developer experience (terrible in HTML, better in other frameworks). So developers of complex apps end up abstracting it away with something like a JAMstack.
So you have things like React, which is essentially a UI library (vs a more fully-featured framework like Angular or even the older Rails stuff, or something like Laravel/Symfony for PHP or whatever the .NET equivalent is). React lets you compose apps not out of DOM primitives but components you define yourself, which in turn are reusable and composable.
But there's a lot of things that React don't handle out of the box: page routing, state persistence, static builds, image optimization, hot reloads, CDN caching and invalidation, etc. A lot of teams end up reinventing all those wheels, or else clobbering together 80 different open-source solutions and 10 vendors. It gets hard to maintain very quickly.
Enter Next.js, one of the earlier successful React-based frameworks. It turns a React app from a quirky UI library into something almost beautiful, because you can now make an entire app, not just a UI, using React and some easy to learn JS config objects.
For example, to make a blog with React, you'd first need a CMS (let's assume you have that part figured out) and an API (also figured out). You can write it as a single-page app, using fetch() or whatever to query the API every time. But then the client has to download that and then render the page. If the CMS is on a different host than your webpages are, it can take quite a while. That whole time your user is waiting, seeing a blank page. And if your CMS goes down, your website goes down, even if the content's been the same for days.
Anyway, you could try to statically bake all that into HTML, but then every time you add a new blog entry or update an existing one, you have to rebuild your project. And then if you want it to be fast, you have to invalidate all your CDN caches.
Next.js essentially takes care of all of that for you, in one easy to use and well documented package. Combined with Vercel (the company behind Next.js, who provides hosting) it also abstracts away all the complexities of the buildchain, CDNs, invalidations, etc.
As a duo, their most powerful feature is rehydration. You can code your app as though it were a single-page app, using React to compose components and pages, combined with file-system routing, to create a whole site. But then you push your changes and that's where the magic starts: Your Next.js server (like Vercel) picks it up, builds it with data fetched server-to-server from the CMS, bakes everything into flat HTML + CSS, and invalidates it across the CDN within seconds. At this point, any user who visits your site will be able to download the HTML + CSS, even with Javascript disabled -- the client does not ever speak to your backend directly. To them, your page is just a static HTML page, served straight from the CDN edge. This means the client doesn't need to load React to see your page. They can have JS disabled and it still shows up normally, it just won't be interactive.
Seconds later after the HTML has loaded, some "bootloader" JS then downloads all the other JS that enables interactivity and dynamic data fetches (comments, etc.)... all invisibly to t...
1. Pure front-end solution (React) they wait on the front-end to handle it all. 2. Remix or Fresh, they are still waiting, it just happens on the server.
It seems like there isn't a significant difference either way - ultimately, you are still waiting, as a user. If the payload is huge, maybe the server model is faster - unless the server is getting smashed with requests, then it'll actually be slower?
[0] https://remix.run/docs/en/v1/pages/philosophy#serverclient-m...
But many sites are more heavily read than interacted with: blogs, news, documentation, even to some extent HackerNews and comments. These are all "write rarely, read often" sites. In those cases, prerendering can be way faster both for the end-user (it's just HTML being downloaded from one single source) and also for the origin server (you build once, CDN caches it everywhere and takes over from there). Typically, the tradeoff is that it's also a PITA to manage these buildchains, especially once you get into obscure webpack or babel configs. Next.js handles it really elegantly.
Next.js has other benefits too, especially when coupled with Vercel. It is more than CRA + static builds, and even if you never end up using the rehydration system, the routing/image optimization/per-commit preview sandboxes may still be helpful, though not life-changing. For me the killer feature was being able to detach the data layer from the (write-rarely, read-often) frontend, such that the frontend could always just assume it would have access to the latest data from the API (because Next.js takes care of that).
To give you a before-and-after comparison... I worked on this page previously: https://www.fieldmuseum.org/exhibitions
That version is running on Drupal. Some of it was in a Drupal template, some of it was in-house PHP. To fetch data, we had to use a mix of Drupal built-ins and some raw SQL, mixed into some ugly templating language. Then through custom modules we had to add jQuery and React, sprinkled on top. Drupal had to "build" the page into HTML whenever we save, and then a separate buildchain would add back the Javascript on top of that and try to bundle it all. The developer experience was ugly and required needed at least four languages (Drupal, PHP, jQuery, React). Filtering is done serverside, so filtering by e.g. Type = 3D movie requires an API call and takes several seconds. If you turn off Javascript the whole page breaks and you can't access any of the links anymore. This version is pretty fast thanks to in-house optimizations and extensive caching by Pantheon (a specialist PHP host), otherwise it would be really, really slow. Our dev and staging machines were hell to use because every page took like 10-20 seconds to load.
The new version (WIP, and I don't work there anymore): https://nextfield.vercel.app/exhibitions
That is 100% Next.js/React and only that, no more PHP or jQuery needed and no other frameworks. Data was moved to a headless CMS (DatoCMS in our case, which returned convenient GraphQL responses). It is slightly smaller over the network. All filtering is clientside and instant. If you go to a different exhibition page, it just has to load the JSON data for the new exhibition (text and image URLs + thumbnails), in like a 25kB JSON instead of the whole HTML page (headers and footers and all) all over again. The images are resized on the server for your viewport needs before they're sent to you (though TBH I am not a big fan of that feature because it's not preloading images right now). Even if you had JS disabled, the page would still load and the images and links would still work, you'd just lose the interactive filters.
So for users, the new version is hopefully a bit faster. The real improvement was in the developer experience, being able to code everything in React and not have to think about how it's going to get rendered into HTML or how we're going to balance our caching strategy (invalidations vs not overloading origin). And devs didn't need to use PHP at all anymore.
CRA wouldn't handle much of that, it'd just se...
The Drupal version is seeing production traffic, while the Next version only sees a few devs now and then.
Anyway, with a bit of discipline and some frontend tricks (preconnect, preload, async) you can create a Drupal page that's super fast. And it would actually serve less code to the end user than a page based on JS frameworks (as all things happen on the server).
Example: https://www.magneticpoint.com/
You still need a place to store actual content/data, of course. But that could be any store or service that gives you an API endpoint to fetch from.
The HTML it returns is really big! 374kb before compression. I turned off Javascript to see how the page loaded without it, and it still downloaded the whole 374kb HTML (I guess that's to be expected).
I dug into the HTML and realised that the reason for the size is that Next.js includes a <script id="__NEXT_DATA__"> element that contains the entire data of the page's components as JSON for React to hydrate. This JSON takes up 60% of the whole HTML file! I suppose it's prioritising smooth rendering over reducing data use, but it doesn't seem very optimal, tbh. And it's really inefficient for browsers operating without JS, since every navigation click requires downloading a bloated HTML file.
I found Github issues, SO questions, and blogposts about this drawback, and it seems like this is a common practice for even the largest websites. This massive duplication seems to be a problem that newer frameworks are trying to solve. I wonder if non-dynamic sites like this aren't better off just being static HTML served from CDNs, since they aren't interactive.
Also, the main stylesheet is 1.12mb uncompressed! Bootstrap is part of it, but it seems like there's a lot of other CSS?
(Now I understand more about why my web browsing on mobile consumes so much data even on low-media sites, ouch.)
1) That 374kB file is only like 50kB gzipped. We had bigger fish to fry/optimize, like that massive CSS. (Which is a holdover from the PHP days. Phase 2 of the project would eventually have refactored that and tree-shaken it, but it was out of scope for the prototype.) A lot of the bloat you see is because that's still a work in progress and they haven't had a chance to do any optimizations yet. A future version would probably get rid of much of that CSS and maybe even Bootstrap, then think about webfonts, oversized images, etc. There's a lot of work on that front.
2) Our target audience wasn't expected to have Javascript disabled, and with it enabled, Next's hybrid rendering model actually makes it really fast to navigate between pages after an initial page load. In an earlier test, we had the individual exhibition pages side-by-side, the Drupal version next to the Next one in iframes, plus back/forward buttons to navigate through each exhibition in sequence. Originally that was meant just as an easy way to catch visual differences, but we realized that the Next version was loading almost instantly (couldn't even see it load), whereas the Drupal version took 4-5 seconds per navigation. It turned out that Next was able to just download the tiny JSON (~20kB) for each exhibition and injected that into the React shadow DOM for updates; it didn't have to download anything else while navigating between navigations. That was an unexpected, and really powerful, feature that would normally only be available in SPAs.
Realistically, this means that if users had JS on, the initial page load might be a bit bloated, but subsequent navigations between pages should be MUCH faster.
3) The JSON shape was also an artifact of our CMS API (in GraphQL). If we wanted to, we could've optimized it before sending it over the wire.
4) Most importantly... I want to reiterate this... the main benefit of Next.js is NOT page performance, but developer experience. To the extent that there are any improvements at all to page load speed, that is a nice side effect. But even if there weren't, it would still be worth it for us. The big difference is in being able to quickly create new pages/templates, in a single language (JS), with a zero-stack configuration. Especially once we also decided to move the content to a hosted headless CMS. That meant no more LAMP stack to maintain, no more DBs to prune, no more fiddling with CDN caching, Drupal modules, Docker, CI/CD etc. Previously we were spending 80% of our dev time fighting our own stack and framework (Drupal is really really hard to work with, even compared to the messy Node/React ecosystem). Next got us out of the DevOps and infrastructure game completely so we could focus solely on the frontend, and Next + Vercel takes care of everything else. It's not just "serverless" but almost stack-less in a way (managed). All we had to do is write React, push a commit, and done. For a small team, that was HUGE... being able to push out a new template in a matter of hours instead of days/weeks, and being able to deploy to production in seconds (and roll back in seconds) too. In the Drupal world, there are companies like Pantheon and WPEngine and Acquia that try to do the same thing for the PHP landscape (and they do it well), but Next + Vercel is waaaaaay easier and faster. Other competitors in that scape (for JS) are Netlify, Gatsby, etc. These Jamstack hosts are gaining popularity because they are so much easier to work with than the traditional backend + pipeline + frontend model. But of course they have their own tradeoffs and aren't right for every use case -- for example, if we anticipated heavy user interacti...
So until that happens the UI looks functional but isn't. The user is left to tap/click furiously on that button but nothing happens?
It sounds to me like this is only suitable for pages where interaction is an exceptional thing that users will only attempt to do after reading some content.
There might be cases where the issue you describe occurs, but I haven't actually seen it in testing. If it's a concern, you could of course add throbbers or the such. But generally, in our limited tests, it hasn't been an issue.
Still, it is an issue they (and the React ecosystem) are actively working on improving, with React Suspense (https://17.reactjs.org/docs/concurrent-mode-suspense.html) and Next.js Layouts (which I understand is copied from Remix(?) and can fetch component groups in a hierarchy https://nextjs.org/blog/layouts-rfc). There is also server components and streaming, which can render HTTP snippets/components (instead of pages) and send those back over the wire, similar to the PHP days: https://nextjs.org/docs/advanced-features/react-18/streaming
But again, the benefit is mostly to the developer experience. It's a lot easier to write everything in React than to have to switch between PHP and Drupal (as in the admin UI) and JS. There are some benefits to the user experience if done well, but the same could be said of a statically cached Drupal output.
Actually I think the big trend in JS front-end development is realizing that you do have to think about it! React rehydration is often a very slow step (whether it's Next.js or anything else, I don't think it makes a difference), definitely not "lightning fast" on non-trivial apps with lots of data. Islands architecture goes a long way towards solving that but it's still a bit limited today.
[0] https://twitter.com/dan_abramov/status/1200118229697486849
[1] https://github.com/reactwg/react-18/discussions/130
There are some ways to work around that, if it actually turns out to be an issue (which it wasn't for us)... discussed it a bit more in my other response: https://news.ycombinator.com/item?id=31727249
Where does Next fit here?
That would be Blazor for anyone interested in checking it out.
https://en.wikipedia.org/wiki/Blazor
Seems like a departure from the norm for no reason unless there's some Deno particularity about it.
This just may be the Deno standard for their import mapping functionality since they also do full URLs for imports like Go (sans schema) normally.
Deno is also just not exactly like JS ecosystems, and that's exactly the point too. Opinionated defaults, out-of-the-box support for TypeScript, death to NPM.
You mean portably. If the same code runs in multiple environments, it's running portably.
https://en.wikipedia.org/wiki/Isomorphic_JavaScript
And second of course, "portable code" had been the accepted term for this "pattern" (if you can even call it this way) for decades already. I'm not quite sure why one would feel the need to randomly rename things that have already had perfectly functional names.
Personally, I don’t really think it’s useful to dissect the semantics of every bit of jargon; plenty of it is semantically imperfect, like the word “factoid” used to describe factual information or figurative uses of literally. It’s just a word being used to describe a somewhat specific concept in the context of a niche. You would still need to be initialized in what it means in context even if it were semantically correct. The helpful thing here is that a simple search like “isomorphic js” gets you up to speed almost immediately. OTOH, if I search for “portable” libraries on NPM, it’s all “cross platform” stuff. If this term didn't exist, that would make it hard to find libraries and frameworks satisfying this niche.
It’s neither here nor there, my chief annoyance with this general thread was people claiming that “this is just like PHP” or “this is just like Rails” and the problem is, it’s not really like that at all. It’s not like older attempts at “live” server code, nor is preact components really much like templating. The different approaches have their merits, and achieve similar end goals, but the developer experience is starkly different in ways that are maybe difficult to understand from simple examples, but absolutely definitive in real world apps. Don’t look at me, though. I write all of my backends in Go.
Vercel is doing a really good job with Next, but it's good to see some competition. Of course, that means there's now 65,535 + 1 more way of serving a web page using Javascript (sigh).
Rehydration is a really big deal. Sounds dorky but it dramatically speeds up load times and such by serving flat HTML and injecting JS afterward, like the old days, except you can write code like it's not the old days.
It makes different trade offs and isn’t strictly better by every metric, but overall I’m very happy with it for the two use cases I’ve tried it with. It’s a very low overhead framework once the simple conventions click.
I’d still like to check this out, then redwood and a couple others too. I’m not huge on these frameworks in general, but they tend to have some excellent ideas and smart people behind them, so plenty to learn by experimenting with them.
I use Next not just for the routing and composition and hydration, but for all the other quality-of-life improvements (image resizing, buildchain configs, hot reload), especially when it's paired with Vercel (per-push sandbox builds, stale-while-revalidate, seamless CDN, access to serverless, etc.)
I'm really excited to see how Remix and other Next competitors evolve, but for now, I think it's still the most "full" stack of the React frameworks? Is that correct?
It isn’t too hard to get the same/similar tooling outside of the vercel ecosystem, but it does take know how and a bit of extra time. It isn’t obviously worth it unless vercel isn’t meeting your needs in my opinion/experience.
I mostly play around with other frameworks in order to learn, but for any client where a frontend framework made sense I’d almost certainly choose Next.
Edit: people also get bent out of shape about perfect hydration and shaving milliseconds here and there, but like you mention, Next offers such a comprehensive solution in a situation where routing and hydration are only a part of the big picture. Next gets you really far without any effort up front, which is crazy. I really like it!
Heck, I've heard in a podcadt they're even working on a hosting platform copying vercel.
Arguably there is nothing all that novel in either framework. We are constantly reiterating and rebuilding wheels, doing it a little better each time.
I’m glad to see the Remix take in things gaining steam though. It’s quite a bit less cognitive overhead than Next without any magical trade offs. Nothing ground breaking, but definitely better at things I care about.
Like most things, a blend of solutions would be ideal
You only need one (or none). I personally recommend Next.js for just about anything.
The problem is that that's pretty much every web app. Every time I've used Next I've end up abandoning SSR and building a plain clientside rendered app.
Same with incremental static regeneration and some other features... Next is obviously built not just by, but also for, Vercel. Vendor lock-in already is a small issue and may become a bigger one if they keep going down that route.
Take a look at their middleware. It's designed to be used solely with their serverless cloud BS. It uses a janky JS sandbox which means you can't use node APIs. It's just horrible for no good reason at all. I've never seen middleware so intentionally crippled anywhere before.
And the whole reason you need middleware is to maneuver around the flaws that the prior person mentioned with getServerSideProps.
Next.js probably seems great if you're writing greenfield code in a dead simple web app. Routing/URL handling on Next.js is just broken. This is all glaringly obvious if you've been around the SPA/SSR world for more than a day.
Hydration is actually a compromise, and not a great one for UX. It’s in fact been said to be “pure overhead”, which I think is an overstatement but only slightly.
What you’re describing in the abstract is spot on though. Serializing server state to HTML and sprinkling in interactivity to pick up where it left off is exactly where we should be headed.
And yes it is like the old days, and yes all of HN will rapidly say so. The big difference now is the convergence of code written for both server and client, and compilers which help strip down and optimize what happens in the client.
Hydration in the current sense is re-running most of what the server already did, to recreate the runtime state it already had. That may be perceptively faster in terms of metrics like first paint, but it’s a huge barrier for time to interactive. All the more so when most content is static and has to load twice—fast first as HTML, then slower and redundantly as JS.
The best way to solve this is to not serve or hydrate anything at all unless you need to. The “islands” approach is a very good, but coarse, way to solve this: isolate components which are actually interactive, treat the rest as static. A more granular approach—termed resumability by Qwik and as I understand it the forthcoming version of Marko—works by treating the server-generated HTML as the initial state. The code executed from there is much more isolated than a full component.
How I wish something, anything better could've taken over. .NET was beautiful to work in. Maybe the native apps for iOS or Android are cleaner (I dunno, never tried).
But browsers are what the world use, and they only speak HTML and Javascript (sadly). So we're stuck unless something else manages to create a sea change in how the world uses the internet.
- Primitives already present from the server render are serialized directly into the HTML, and the compiled code reads those values from the DOM
- Everything else is split into fine grain chunks, assigned a special identifier (Qwik uses URLs) which is serialized to the HTML to fetch (which can be eager or on-demand) and activate interactivity as needed
My understanding is that currently Qwik serializes more than necessary—i.e. can be optimized further to eliminate non-interactive chunks from consideration—but that they’re focused on reducing JS cost first.
I don't know whether this means that it doesn't work as SPA any more since if you want to keep the best of both, you will end up creating more4 complexity, a new framework to learn and probably get marginal improvements at best.
I understand the spirit of your comment, but this was/is also true of Google Web Toolkit (GWT).
Is that sort of what Phoenix LiveView does? Return a fully server-rendered page on initial load, then set up a "template" on the client side that can receive any values that change server-side over a websocket and patch them into the DOM?
It’s interesting that the problems with hydration is in some sense caused by the insistence on one-way data binding (deriving the view from the state). I imagine that with two-way data binding then you’d just need to attach event handlers and then the state would be derived from the view on the next interaction. Maybe.
OTOH if there were a way to produce a two-way implementation from a one-way description, that could be great for performance. But this is already more CS than engineering.
I think you can have a two-way binding with a controlled update procedure, akin to one-way data-binding. I’ve read some people claim to do it by producing a kind of one-way directionality under-the-hood (?) from two-way bindings. The goal being that views can update state (and other views).
I think it was here I read it:
«‘2-way’ shouldn't be a problem if a component reports user events (perhaps transformed/mapped) to the domain model without changing it's own core state (disregarding throttling etc.) and only changes its core state in response to events from the domain model.« — peerreynders @ https://dev.to/peerreynders/comment/1objn
Honestly it's unfair to compare a small e-commerce site made with Next to one of the biggest websites on the internet.
If Ebay was made with Next it would probably be much slower. React is the slowest at SSR of the modern frameworks. Amazon considered using it but it was too slow for them so they keep using Java + sprinkled JS.
Ironically we were already doing that 15 years ago years with PHP/ASP/Java/Rails + jQuery.
I imagine you mean that writing (frontend) code now a days is better than how it was in the old days. Well, at least from my perspective that's not the case. "Modern" frontend code requires:
- a package manager (npm)
- node (or deno or whatever)
- transpilers (or is it plugins?)
- TS
- 10K+ dependencies
And to be honest, what is all that good for? To being able to "hydrate" some server-side rendered template? Not good enough reason.
Updates are now easy-breezy (update the server and you don't have to touch clients at all).
There is a place for SPAs. I just don't think your typical grocery store website should use something like that.
Eventually, you'll have enough devs working on this you'll start to run into issues with how you coordinate your work. Your site becomes large enough the code gets more complicated and needs organising to work on it without slowing you down. You'll start to reinvent the above tools to solve these problems.
Frontend/JS tooling isn't perfect, but don't pretend like other languages/systems (can) have a complex pipeline of build tooling.
I didn't see GP make the claim of using it?
Not necessarily, at least in the case of React and Vue.
Rather than using NPM, you can self-host react/vue (or preact if you need something even smaller), or serve it from Unpkg.
You don't need node/transpiler/bundlers if you're only targeting modern browsers. You can use modern syntax, async/await, ES6 import and a bunch of other features with static .js files.
JSX is a tough one, but there are solutions to that, packages domz and HTM are made to allow using React/Preact without NPM/transpilers.
Typescript is also a tough one. But it's also optional, although a good idea to have. I hope optional type annotations land in ES6 soon so typechecking can happen without anything resembling compiler phase.
-
> To being able to "hydrate" some server-side rendered template? Not good enough reason.
The "hydrating" parts is entirely optional in "modern frontend". It also needs some stuff on the server that is IMO significantly more complex than what I described above. But apart from some very specific cases, one don't necessarily need it.
But really, what I meant about "writing code not like the old days" isn't so much about the shitty toolchain (which Next helps with, but I agree it's shitty). Rather, it's the ability to write code like:
<Header loggedIn={isLoggedIn}/>
<Sidebar options={isLoggedIn ? navOptions.loggedIn : navOptions.loggedOut}
<Dashboard>
{widgets ? widgets.map(widget => <WidgetContainer>{widget}</WidgetContainer) : <Spinner/>}
</Dashboard>
Basically, the ability to compose pages & apps out of components (which different developers can work on), and the ability to manage state in a central controller via Redux or useContext to avoid race conditions and the such. That sort of stuff is REALLY hard to do with plain HTML and JS, especially where there are multiple developers involved. React isn't a magical cure-all, it just makes it easy to componentize large apps into smaller areas of concern.
The shitty buildchain isn't a feature, it's an unfortunate side effect of browsers being limited to JS. Essentially it's a "compile" step that became necessary as the vanilla-JS developer experience wasn't able to keep pace with the complexity of desired business apps (and as devs of various skill levels flooded the market). So the developer tools kept growing, but they still had to be compiled/built into JS for the browsers. Next.js makes it relatively painless, compared to how it was just 3-4 years ago. But I agree, I hate that this is a step at all.
Ugh, as for TypeScript... I get that it's a necessary evil, but I spend more time fighting it than actual bugs... coming from PHP, it was already common practice to manually typecheck and coerce everything when needed, anyway. TypeScript often felt redundant and overly sensitive, especially when it came to async nullables, causing false alarms that React could just've silently handled with {isLoaded ? <Component/> : <Spinner/>}
But TypeScript is optional anyway. It's a superset/addon on top of JS, so you never have to use it if you don't want to. If it's scaffolded for you in someone else's project, usually it's just a matter of a either using a .JS extension instead of .TS, or adding a ts-nocheck or similar to that file. Other devs may hate you for that though, when your object or props ends up breaking theirs... so it's definitely a conversation worth having first :)
I started with https://alpinejs.dev/ linked via CDN, and OpenJSCAD, also linked via CDN - I wrote basic html, marked it up with alpine `x-model` and `x-data` tags, and sprinkled a little vanilla js on top. Everything worked well and I got 80% of the way through the project.
In the final 20% I ended up adding a bundler (parcel), so I could bring in an scss framework and override its variables. While it added a fair bit of complexity to the project (dev dependencies, parcel config files) I gained lighter files via parcel's tree-shaking and minification, auto-recompilation/reload during development, and re-usable html partials via `posthtml-include`. I'm also set up to swap to typescript quickly, if the project gets more complex and I start to get annoyed with the lack of compile-time type checking.
So, it's 2022, and you can write a web app without any of the things you mentioned (transpilers, package managers, typescript). Yes, adding even one of them nets you a 100+ dependency node_modules directory - but the reason we keep adding them to our projects is the things it gives us are NICE, and the cost (complexity) is mostly worth it.
Just scrolling list of small blocks of text with small/interactive screencasts/animations that communicate the idea via succinct bullet points.
Much more fluid than the usual approach of paragraphs or breaking the page up into large blocks/sections.
It’s closer to older HTML where you just have text and a scrollbar.
Maybe it's just years of bad habits trained by seeing too many bad marketing sites, where the typical signal to noise ratio is really bad. I guess even when I see a good sales pitch, I don't recognize it as such anymore and try to skip through it... sigh. Sorry, Remix.
https://hackernews-csr.ryansolid.workers.dev/
No need for rehydration, I'd say. Combine this with code splitting for large apps.
It's not a nice experience. Remix (and, most likely, Fresh as well) prevents this.
[0]: https://developer.chrome.com/blog/paint-holding/
The deno runtime is very interesting.
Most intriguing: no build step. That's a big difference from sveltekit which takes very readable input files and produces hardly readable files.
I always wished there was something convenient, like an html tag that made it easier to add interactivity, but I never found it.
I can’t believe we got anything done back in those days.
We don't need this circus every time a new JS thing is released.
Is this ling that I'm missing? Or a lark?
I'm just balking a bit with the word 'hydration' entering into some kind of normative lexicon.
I think there is probably a better word for that.
There’s companies that bet on deno/deno-like runtimes. It’s a move to having more options/control on sandboxing/embedding JS on server runtimes.
Think of how Lua is used. Heavy lifting in a compiled language with Lua on top to cover app specific logic.
Node is in a sense that, but with a stronger emphasis on being a general purpose runtime for JS.
Deno (and similar), gives you more options for embedding and restricting the JS side.
I think it’s worth keeping an eye on, because I think the JS world is soon in an refinement/optimization phase. It’s settling and stabilizing towards a set of core ideas and Deno might be part of that.
If you take Tailwind CSS for example, when correctly using their CLI tool, it only includes the size of the css classes actually used, keeping it to a minimum, when compared to people just doing a standard import of the entire library. I like this mentality because it's offering the ability to be very lightweight, or as large as the 'framework' it offers. NextJS offers this as part of their build process, but not sure how big their assets are with it for a simple usecase.
Semantics aside, the existence of things with different philosophies doesn't immediately invalidate everything that doesn't give you the same tradeoffs. For one thing, Tailwind deals with declarative CSS output, not imperative modular code. I'm not saying that makes it stupid or anything, but it's very apples and oranges. There are very few JS libraries or frameworks that can offer starting-from-zero KiB JS; maybe Svelte comes close? Ironically, if we're talking about client side bundles, it seems as though Fresh actually does start with 0 KiB, as it does not default to shipping JS code to the client at all.
This doesn't feel like a rational discussion at all. It feels like it's just necessary to come up with a cynical take because there's a new JavaScript thing. In a few weeks there could be some Rust FRP webassembly UI thing that has a 1.2 MiB hello world and hardly anyone will care.
If not, why in the world would a hello-world demo need optimization? By definition it's supposed to be the simplest thing you can build to showcase the features of what you're using. If the simplest project has the properties GP mentions, then it's not a good demo.
Besides, I'm pretty sure that in this framework's case the final bundle can also be trivially stripped, but would that also reduce the render time? It's difficult to tell, and maybe those things should be mentioned in the demo. (Sidenote: I haven't confirmed whether what 0des posted is true or not; I'm just going by the fact that you're defending it.)
Still… a 100KiB bundle is not that bad of a starting point. It objectively isn’t, if you measure it up to other popular frameworks.
The image of the dinosaur drinking takes 386ms, and the favicon is 132ms.
So for text and a button to increment/decrement specifically, it seems quite quick.
I set Next.js up to use Preact as the engine but it takes a bit of config work to do this and isn't an officially/OOTB supported feature.
https://www.solidjs.com/
Or is it all fully "magical"
What I read from other comments is that fresh does code splitting, so for example if the interactivity is out of your viewport and you scroll down to that element, it will then load the js required to make it interactive, while I find that idea cool, what worries my is that it could take a few ms to load the js and then other few ms to boot that component and render it interactive. But I don't have experience with any of the frameworks (besides next.js where I build a small demo project to try it out).
[0] https://astro.build
He describes it as a post-Unix web framework (i.e. built on serverless primitives like cloudflare workers/deno deploy) with the goal of <10s deployment (which he says requires JIT compilation on first-request)
React is the main driver for JS not some server-side BS.
The classic scripting arg. JS is a poor choice for scripting and hence, not used for it that much anymore.
Are you aware that Deno is very new? I wouldn't say that Ryan Dahl got left behind because everyone hasn't switched to Node yet. There is a large amount of interest in Deno, exemplified by how frequently Deno projects make it to the front page of HN.
> React is the main driver for JS not some server-side BS.
Haha. Just because you hate JS doesn't change reality.
> The classic scripting arg. JS is a poor choice for scripting and hence, not used for it that much anymore.
This statement doesn't make sense. It never was very popular as a Bash replacement, if that's what you're meaning. And otherwise, it is the only option for browser interactivity. So it doesn't make sense what you're saying.
React was the first framework that requires the coder to really understand and utilize the modern features of JS.
Scripting something simple or spinning up a simple endpoint have always been arguments for NodeJS. R always talks about this. Terrible ground for decision making.
> Routes are defined as files in the routes directory. [...] If the file name is contact.js and is placed inside of the routes/about/ folder, the route will handle requests to /about/contact.
I can't say I'm particularly keen on being told what directory to put files in, or or being told that I must only code exactly one endpoint in each file. Why aren't I allowed to code multiple endpoints (e.g. for related functionality) in the same file?
Also, in what directory do I put my files if the url is of the form /user/{username}/page/{pagename} ?
https://fresh.deno.dev/docs/getting-started/dynamic-routes
So the example above could be:
I have no idea why this is the default behaviour, it sure feels something like a lot of people put a lot of work into and by then they didn't realise their fancy new feature doesn't make things better.
But I’ve noticed that it makes it easier to quickly understand new codebases in my organization. Everyone are using Next.js and all the apps have about the same file layout.
I think it’s neat that having extremely fast project dir fuzzy finders has influenced framework design. Like how Django’s design is heavily influenced by how importlib works and would be completely different if Python modules worked differently.
Also, given a filesystem config, now I'm forced to have many very small files around for each route where each file is most likely just a call to another service handler. I'd prefer to mash most into bigger files that handle related but distinct routes.
Less important, but comes up, it's nice to be able to match routes based on code and not just string equality ... e.g. everyone seems to like having routes for usernames start with '@'
I find this very interesting. I get that adding a build step can be a pain during development / deployment, but running your TS build once per deploy seems _much_ more efficient than doing it repeatedly, as needed. Or does it get cached , so it's built at-most-once? I haven't really dug in.
I kept the demo repo around here, in case it's helpful to anyone: https://github.com/lewisl9029/buildless-hot-reload-demo.
The repo itself is quite out of date at this point, but my current project, Reflame, is essentially the spiritual successor: https://reflame.app/
Reflame has the same ideals of achieving the developer experience I've always wanted for building client rendered React apps:
- instant production deployments (usually <200ms)
- instant preview environments that match production in pretty much every imaginable way (including the URL so we don't have to worry about special whitelisting for CORS and whatnot), that can also be flipped into development mode for fast-refresh (for the seamless feedback loop we're used to in local dev) and dev-mode dependencies (for better error messaging, etc)
- close-to-instant browser tests (1-3 seconds) that enable image snapshot comparisons that run with maximum parallelism, and only rerun when their dependency graphs change, and auto flake detection/recovery
- The dev experience is closer to the early days of PHP.
- TypeScript, Preact out of the box. No need to configure build tools / deploys much faster. It's a pain in the ass to make these working at the same time and targeting both browser and server nowadays.
- You can have interactivity without bolt-on client-side scripts that are different from other parts.
- The code could be running on the edges.
- I'm not sure what does the island based client hydration means, but sounds like Remix
Many other frameworks could do some of them but not all (Ruby needs JavaScript/Turbolink, Next.js need to build then refresh, etc)
The islands approach is different: pages are server rendered, but you can easily define islands of interactivity (like, say, an auto-complete search bar) where just enough javascript is sent to make those components interactive—and only when it's needed. You can control at what point exactly each component is made interactive: as the page loads, when the component becomes visible, when the user first interacts, etc. It's a great way to balance performance and rich interactivity. If the user never scrolls down to your photo carousel at the bottom of the page, the javascript is never requested.
If this sounds like what we used to do with say PHP & JQuery, you're not wrong. The difference here is we have the same javascript-based template logic and component model both clientside and serverside.
Some other projects adopting the islands pattern: https://iles.pages.dev - https://astro.build - https://slinkity.dev
More reading: https://jasonformat.com/islands-architecture/