top | item 31720110

Fresh – Next-gen web framework

791 points| exists | 3 years ago |fresh.deno.dev | reply

430 comments

order
[+] solardev|3 years ago|reply
Ooh, some competition for Next.js?

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.

[+] eyelidlessness|3 years ago|reply
> 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.

[+] sdevonoes|3 years ago|reply
> 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.

[+] chrisweekly|3 years ago|reply
https://Remix.run is the real competition for (/successor to) Next.js. It can target a Deno runtime so I guess it's competition for "Fresh", too.
[+] steve_adams_86|3 years ago|reply
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.

[+] jonny_eh|3 years ago|reply
> that means there's now 65,535 + 1 more way of serving a web page using Javascript (sigh).

You only need one (or none). I personally recommend Next.js for just about anything.

[+] WuxiFingerHold|3 years ago|reply
The next-gen SPA frameworks/libs like SolidJS or Svelte are already very fast and more importantly very small in bundle size. At least much faster and smaller than React or Angular. Therefore the advantages of SSR frameworks like this new one are much smaller when compared to e.g. SolidJS.

The performance claims made for this new framework need to be proven by benchmarks. Check out this SolidJS Hackernews clone (Client Side Rendered) https://hackernews-csr.ryansolid.workers.dev (by the way, there're other implementations like Remix or Svelte as well)

IMO very hard to beat. For larger apps we can use component based code splitting.

The new SSR frameworks are very complex. So there's a downside to it.

Of course there's a big market for the cloud providers as you need to run and pay for a server for your SSR instead of simply serving static JS! That's why there's such a hype lately. I'm not convinced that the performance gains are worth the complexity, costs or vendor lock in.

Again, check out the SolidJS example app I've linked above and measure for yourself if you really need the additional cost and complexity of a server pre-rendering, hydrating, etc..

[+] totallymike|3 years ago|reply
This feels like a strange argument to make when server-rendered HTML has been the norm for decades, and it's only been recently that SPAs have become popular.
[+] psadri|3 years ago|reply
The problem is accessing backend data sources. Fetching that data in the first request and responding with server side rendered html > serve js that then initiates network calls to get that data (while showing a spinner in the ui)
[+] yencabulator|3 years ago|reply
Meanwhile, the Svelte people are working on SvelteKit, their integrated SSR+SPA.
[+] francis-li|3 years ago|reply
Ryan Dahl talks a bit about it in this talk at Remix Conf 2022: https://www.youtube.com/watch?v=4_nxvVTNY9s&t=10781s

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)

[+] AtNightWeCode|3 years ago|reply
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.
[+] 3np|3 years ago|reply
So my reading of that is that Fresh as it stands now is more of a demo and challenge to the Remix community to step up.
[+] lmiller1990|3 years ago|reply
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?
[+] damowangcy|3 years ago|reply
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.

[+] eyelidlessness|3 years ago|reply
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.
[+] solardev|3 years ago|reply
(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 the user. 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.

So take that rehydration stuff and add on a bunch of other quality-of-life developer experience improvements. For example, images are traditionally another headache, needing something like Imgix or Cloudinary to be able to dynamically resize them on the server (so the el cheapo 320p Android doesn't get served the same 4k retina image). Same with script updates... if you change your SPA, you have to figure out how to invalidate current caches, how to sure visitors who've cached the old version still works with your backend API, etc. Or hot refreshes, or page-by-page invalidations, or whatever. It does all of this in one framework, so you can get rid of ReactRouter, Redux (useContext can handle many uses cases), image processors, Preact, Express, etc. Really the only thing you need to provide is a CMS of some sort, typically a headless one.

That's Next.js (the open-source framework). Behind them is Vercel (the hosting/PaaS company which maintains Next.js). Next is the one I'm most familiar with, but I believe the others are similar (but someone correct me if I'm wrong):

Nuxt.js is to Vue what Next is to React. I believe it's a little less featureful than Next, and it's maintained by a different company.

Remix takes some of the Next.js principles but implements them differently; instead of having a server rebuild and bake your project at push, you can do a similar thing on edge compute/serverless (like Cloudflare Workers directly). It has a really neat feature: nested routes (really more like UI layouts), which are composable UI units that are hydrated serverside, similar to Next.js, and then sent to the client as HTML wholesale. So like your <Dashboard> can include <Widget> and <Chart> and <Comments>, but each one can be individually hydrated, composed, and reused -- all invisibly to the client. My understanding (again, not familiar with Remix) is that this was such an amazing feature that Next.js straight up copied it last month with their Layouts RFC (https://nextjs.org/blog/layouts-rfc?utm_source=next-site&utm...).

Fresh looks like Deno's attempt to produce something similar, but it's still early and not quite as powerful.

If you're a web dev and you've never tried this stuff, I strongly recommend taking a look. I've been coding webpages since Netscape, before CSS was invented. Next.js was the single biggest improvement to my professional life in decades, especially coming from the hell that was Drupal + jQuery. I coupled Next/Vercel with a vendor-supported headless CMS, and the overall developer experience made me fall in love with my job for the first time ever. So much so, I actually switched careers from being full-stack to solely frontend/React focused, because Next.js just made it so enjoyable. No more infra and DevOps hell, it all just works, it's all in JS/Typescript, and I can just focus on coding for UX. What used to take weeks to do in the old PHP + jQuery framework would only take minutes to prototype, a day or two to finish in Next. I hope the other frameworks bring you as much joy!

[+] tunesmith|3 years ago|reply
Deno vs Node appears to be one of them.
[+] bartq|3 years ago|reply
1. With this approach of sending "only the small JS chunk needed for interactivity" aren't we going to end up with the situation where chunks A and B need common part C? And what if C needs D etc. There should be provided a dynamic modules loader. Is it implemented in all those hydration based frameworks?

2. How is solved the situation when <button> is delivered to the user, but "onClick" action is not because network failed?

[+] lucacasonato|3 years ago|reply
> Is it implemented in all those hydration based frameworks?

I can't speak for all frameworks, but fresh can dynamically break out shared dependencies so you don't have to download the same code twice.

> How is solved the situation when <button> is delivered to the user, but "onClick" action is not because network failed?

Developers need to deal with this in their applications. The counter example on the fresh homepage uses <button disabled> for the server side render, and only enables the button in the client side when the counter island hydrates.

[+] halfmatthalfcat|3 years ago|reply
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.

[+] 0x6c6f6c|3 years ago|reply
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.

[+] tbeseda|3 years ago|reply
I think the convention of `~somepackage` is more common than using `@` as a shortcut.
[+] sriku|3 years ago|reply
Slowly getting somewhat cynical. This is the only space where both "prebuilds everything and therefore saves rendering time and improves caching" and "no build step and so speeds up deployment" are both considered valid feature pitches.
[+] qudat|3 years ago|reply
> Slowly getting somewhat cynical

Are you equally cynical about the hundreds (thousands?) of different ways to setup and deploy infrastructure (all with different pros/cons)? FE is timid compared to devops churn.

[+] marcosdumay|3 years ago|reply
On the last decade and half the entire group mind of the computing discipline switched from "no build step will speed-up development and deployment" into "a heavy build step will speed-up development and deployment". So, it's not like the web developers were going at it alone.

Anyway, the change happened because of real environmental changes. Developers everywhere didn't just wake-up and decide their old values were the exact opposite of the truth, both opinions stand on valid models of the world and hard-acquired empirical information.

[+] madeofpalk|3 years ago|reply
Why does that make you cynical?

They're two different spins on how to render content. They both have pros and cons. It's good to know this and make an informed decision about which strategy you take.

[+] norman784|3 years ago|reply
To me it reads more focused on developers than users of the site you build.

I like that in the last couple of years the developer experience was improved in some ways, this kind of apps that you could develop "easily" as monolithic could be served in a serverless hosting as a microservice (if I understood correctly how serverless works) serving each endpoint as a separate service, everything without you as dev put too much effort into it.

[+] xavdid|3 years ago|reply
> 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.

[+] eyelidlessness|3 years ago|reply
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.
[+] colordrops|3 years ago|reply
Even if it isn't caching, it could be added with a service worker.
[+] digitalsanctum|3 years ago|reply
Am I the only one that sees the "do not use in production" warning as a challenge? ;)
[+] gavinray|3 years ago|reply

  > "The framework uses Preact and JSX for rendering and templating on both the server and the client."
Really nice to see Preact used here, it's a much more rational choice than React if you were planning on using React anyways.

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.

[+] shafyy|3 years ago|reply
God, the landig page animation with the lemon is delightful!
[+] manigandham|3 years ago|reply
Fresh = Deno version of Astro (static-first with SSR) and Isle (vue-focused) and bigger Next.js/Nuxt SSR (with no client js) modes. Remix also does well here with a focus on only SSR.

It's basically what the original "isomorphic" javascript promise was to have the same code seamlessly running on server and client with a flexible split on what part ran where, now possible down to an individual tag/component.

Also worth mentioning projects like .NET Blazor, Phoenix Liveview and Rails Hotwire that approach client interactivity through their own backend languages instead of JS, usually with some partial refresh mechanism using AJAX or websockets.

[+] kuon|3 years ago|reply
I suggest you take a look to Phoenix Live View, it's like that (very little client side JS) with the added benefits of the BEAM. You can serve thousands if not million of simultaneous clients with a small machine.
[+] DrFell|3 years ago|reply
These JS/TS full-stack frameworks need to be banned right along with fruit-flavored vapes. Think of the children.
[+] asadlionpk|3 years ago|reply
Does anyone know what software can be used to design the juicy hero animation seen here?
[+] seydor|3 years ago|reply
A JS framework, not a web framework
[+] qbasic_forever|3 years ago|reply
I love that the pendulum is swinging back to file-based routing. It reminds me a lot of the simplicity of cgi and php scripts. I'm sure there's a point where it explodes into a monster of complexity with enormous sites, but for everything smaller it's so much simpler and easier.
[+] zelphirkalt|3 years ago|reply
Next (no pun intended) thing we will rediscover is using templating engines (only in JS or so), because we realize, that mixing state and behavior is a problem. Then we will have gone full circle, but probably with some unreasonable overhead as a result. Maybe the whole thing of rendering templates will somehow become a part of webpack and everyone will have to configure webpack.

Good that classic web frameworks are still around and healthy, which have been rendering templates on the server side for a decade or so.

[+] xrd|3 years ago|reply
Very similar to sveltekit as well. I hope in the future you can swap out the preact for svelte.

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.

[+] oreilles|3 years ago|reply
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)
[+] MarquesMa|3 years ago|reply
Why this can be great:

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

[+] toddmorey|3 years ago|reply
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.

Some other projects adopting the islands pattern: https://iles.pages.dev - https://astro.build - https://slinkity.dev

More reading: https://jasonformat.com/islands-architecture/

[+] pyrolistical|3 years ago|reply
Yep. We have come full circle. This is php with a better experience