73 comments

[ 4.6 ms ] story [ 117 ms ] thread

   "I don't recommend having components responsible for querying data because their responsibility is already in presenting the data. More accurately, components need only receive data from view models, format it, and output it to the screen. Instead, I advise you to follow either of the three following ways:

  Render the data on the server and pass it to components as a view model, as shown in this guide.
  Use a state management library that supports dispatching actions (e.g. Redux or MobX), deriving view models from the state, and passing them to components as properties."
This is opposite to what Next.js new React Server Components stuff is advocating for in the new app/ dir structure. It expects every component to fetch the required data, and just cache any duplicate calls. It's probably good for a Serverless / Edge deployment but I much rather use a MobX store that takes care of state, fetching and mutations.
I came from a centralized store background — and honestly I'm falling in love with the decentralized data responsibilities. Between React Query (fetch batching & caching) and Jotai (decentralized state) I love that every component can just take care of itself. No more prop-drilling, everyone just declares their dependencies and takes care of their own.
That sounds like absolute hell to dig through once you hit N+1 queries.
Yeah, this is the kind of thing that seems elegant and convenient when the requirements are simple, but completely falls apart as soon as any complexity is involved.
This tracks for me as well. Very quickly, you start having to manage 10, 15, 20, or more places where data in a store is being manipulated from outside the store and it quickly becomes unmanageable on anything beyond a toy-sized application. It almost feels like a rite of passage to decentralize like that and then start to pull back when it becomes a nightmare to debug and maintain.
That's the purpose of the in-app request caching layer. Another way to see it is that you do have state in a separate store, it's just that you have one piece of state for each resource that can be requested. So it's not that all the components are requesting the /users resource, it's more that all the components a requesting the value of the /users store, and the /users store fetches the data once and determines whether the data is loading, present, needs to be updated, etc.
That caching layer sounds like a footgun.

RTK Query does something similar, offering multiple ways to initiate, update and use the data of the queries.

(comment deleted)
It all sucks. The grass is not greener on the other side. Just wait for the usEffect hell that awaits you.
If you end up with useEffect hell, you are coding wrong. As OP said: it deduplicates and caches requests, there is no need to use useEffect.

Here is some example code, and imo it‘s really greener than anything else.

  async function getData() {
    const res = await fetch('https://api.example.com/...');
  
    if (!res.ok) {
      throw new Error('Failed to fetch data');
    }
  
    return res.json();
  }
  
  export default async function Page() {
    const data = await getData();
  
    return <main></main>;
  }
Where's the caching in this example?
Handled under the hood by Next 13. To be honest, they probably could have done something to make that a bit more obvious when looking at the code - it probably wouldn't hurt to throw in a simple 'cache' keyword or something.
This is the documentation I could find although it's not for 13 but Beta: https://beta.nextjs.org/docs/data-fetching/caching

They say there's a new `cache` function in React and they have patched `fetch` to use it by default (for GET requests).

Does this include a solution to the N+1 queries issue (container element requests a list of items, then item elements each request their details)? I see you can do pre-fetching, perhaps those can be batched.

EDIT: Found an example that uses DataLoader by "caching the cache". The src/api.ts module exports a cached DataLoader for characters, and src/components/CharacterAvatar.tsx imports and calls it during render simply like this:

  const character = await characters().load(id);
https://github.com/AndrewIngram/next-rick-morty
Ok, and how does this work when I need actual client side interactivity?
The problem is the moment you need to do complex combination and computation from multiple async sources, it's game over. It's the repeating of the history of flux -> redux back then all over again. Further more, what happens when you need to share this computation across multiple components?
For all of that: Jotai
Yes the point is that in this case the complexity is not by choice. If u have the business needs then u have to deal with them
Right, you put the complexity inside the Jotai
This is probably very tinfoil-haty, but I can't help but wonder how much of this recommendation is a perverse incentive to sell edge compute on Vercel's platform. In general I am very wary of VC-funded open source, like Next.js.
They poached pretty much the entire react team in order to bet on:

- react being the most popular FE library for time to come

- gain the user's mindshare as react being now a Vercel product (something which is becoming increasingly true)

- users attracted by react and next eventually becoming Vercel customers.

They have also tried or employed several other major library authors in order to position themselves uniquely at the crossroads of major FE software and thus be uniquely positioned to transform those users again in Vercel customers.

I don't judge any of this negatively or positively but that's the case I see.

This is just a meme, an overwhelming majority of the React team ar still at Meta.
A very large chunk of the longest serving and more important jumped ship though.
> They poached pretty much the entire react team

I remember they got Sebastian :-) Who else?

Grabbing contributions (commits specifically) between Dec 20, 2021 – Apr 15, 2023 and looking at the workplace of authors (first #20) it seems:

- at least 2 (top #2) works at Vercel

- at least 4 works at Facebook

Edit: but this is just commits for facebook/react, reality might look differently :)

Andrew Clark just moved over to Vercel. I believe they also got Dominic Gannaway, who used to work on the React team, although he said he'll be working on Svelte compiler stuff now.
> Dominic Gannaway

Whom React got from InfernoJS

I don't think Dominic ever stopped working on Inferno
Honestly I don't see a large use case for React Server Components, to me it's really more of a way to woo those that were still adamant about server rendering. I can see it being very useful in some specific instances, but for the most part I still advocate that one build a React site the way they always have.
Facebook has their own internal use cases (they talked about it at some show and tell when they over-hauled the FB design a few years back).

In the rest of the world, SEO is the main use case, e.g. Company X (some kind of retailer) has invested in an SPA (when what they needed was an enriched MPA) and then found they were loosing their search engine rankings. Either they:

1. Render that in a headless browser, cache the results, and serve that to crawlers (non-optimal as detecting bots is hard); or 2. Rewrite their new website to be properly architected (at cost); or 3. Buy into server rendering to serve both normal visitors and crawlers.

I worked at a company that had _exactly_ this journey. Don't forget the non-functional requirements when designing solutions, kids.

If you buy into server rendering before you write a single line of code and understand it's a trade-off it turns out to be only mildly unpleasant in practice.

The best such codebase I can think of might still have been better off overall as an enriched MPA, but given how few normal pages it had compared to the app-ish bits - thereby making staying on a single technology stack a bigger advantage - I'm not quite willing to say it -definitely- would've been better as an enriched MPA. Not quite ;)

I don't see any tinfoil-hatness in exposing the incentives that are in place of every opinator.

In philosophy, the first thing to understand a philosopher's thinking (make a model of his mind) is to read his work but the second is to read who are his influencers.

No field is truly neutral or deeply agnostic (except reality itself which is The Great Equalizer).

Vercel also employs Rich Harris the creator and driving force behind Svelte and Sveltekit. I highly doubt these are top down decisions to pump usage of Vercel’s platform. Nothing forces users to use Vercel at all.
Something like React Query and other hooks based approaches are fine and very useful for certain scenarios. At the end you always need a hook (or something very similar).

But it can lead to defining asynchronous workflows through the nesting of components, controlled by their mounting/unmounting and other state. I much rather have something like RTK Query which lets me both use it in a hook for simplicity and in Thunks or Sagas for more complex things.

That sounds to me like it'd cause all sorts of trouble in the real world (authentication, changes to endpoint URLs, difficulty to agglomerate data), and not surprisingly the Next.js documentation states `For now, if you need to fetch data in a Client Component, we recommend using a third-party library such as SWR or React Query.`
Objectively your application has already been designed by the framework you choose. It tells you how to do and where to put most things and it also does all of the heavy lifting, a.k.a. actually doing something useful. The design the application developer needs to be concerned with is how to split functionality into reusable components where it's needed. I mostly see big fails here: a lot of kind of best practice theater, but what you end up with are very complex components doused with concrete.

I also see some straw man arguments, e.g.

> Developers dislike design because it's time-consuming.

I've never met a developer who doesn't like to design. I'd say the vast majority of developers even if tasked with something as simple as creating a button first try to craft a universal solution that can somehow be reused. Instead the correct design methodology most of the time is called KISS. You can always make it more complex later, but making it simpler is usually a lot more difficult.

I view premature abstraction as a type of premature optimization mistake, this is how senior dev bad code is written a lot of the time either because of faulty generalizations and anticipation or a strict adherance to some principle they don't really understand.

Because frameworks are sets of premature abstractions it really depends on how they do it and how much of benefit they provide compared to other existing solutions. I think we came a long way and SvelteKit really does provide minmal bloat and redundant complexity.

There's nothing stopping you to use Redux Toolkit and RTK Query in Svelte. It may not be "clean" from an OOP perspective, but it is trivial to test, mostly without mocking, it is easy to reason with, and even less code and complexity than what this blog tries to push.

When developers talk about a "clean way" to do things, I immediately think of overconfidence. Can't help it.

When developers talk about a "clean way" I immediately think of an over-engineered and over-abstracted piece of crap that will be so complicated to understand that the next team will rewrite from scratch.

YMMV.

> Long gone in the past1 are websites that purely displayed static, seldom changing content to visitors. Today, almost all user interfaces are web applications instead of websites.

Most of the websites I visit are static and when they are not their dynamic content is annoying. Look at new vs old reddit for a good example.

Most websites would be better off being statically rendered.

These things aren't mutually exclusive. Most websites are static, but most people's time is spent on dynamic websites.
Dynamic in the sense dynamic VS static doesn't mean what you think it means.

Being able to collapse a comment thread, or upvote a comment, or post a reply, without reloading the page, means the website is dynamic. Static only means that nothing changes without a page reload, which is thankfully long gone.

Also, the new and old reddit are exactly the same in terms of "staticity". It's just that the new design sucks.

Similarly I'm sure you'd qualify Facebook of being an evil dynamic website. But open Facebook and HackerNews side by side, the content on the former won't update dynamically more often than the latter.

> Being able to collapse a comment thread, or upvote a comment, or post a reply, without reloading the page, means the website is dynamic. Static only means that nothing changes without a page reload, which is thankfully long gone.

No! That is interactive!

Dynamic means hot loading content without refreshing the page. I’ve been doing web dev since web 1.0 so again, no.

Both of you are correct, the list of things is mixed.

Interactivity = collapsing a thread

Dynamic = posting a reply and it being sent and displayed without reloading the page

FWIW, I don't believe Reddit does the latter.

You're right.

I'm not sure if Reddit does it for messages but they do for votes for example. HN too.

SvelteKit's routing pattern is anything but clean. It uses filesystem based routes where every file is called "+page.svelte" (or +page.server.js/ts for API only routes).

For anything but a demo app with just a couple of routes it's a headache to navigate.

Edit: Another smell of the routing system to me is that you need to resort to complexity like this [1] to have anything but top down inheritance. I love Svelte btw and have used it in many projects.

[1] https://kit.svelte.dev/docs/advanced-routing#advanced-layout...

Having built a rather large app using SvelteKit, I found the routing scheme to make lots of sense actually. You always know what code is located where, concepts transfer everywhere consistently, and concerns are nicely separated.
This.

It might look complicated at first sight, but once you actually use it you really appreciate the way it's structured.

Well yeah you can get used to anything. Doesn't mean it's a good idea to begin with.
In theory it seems neat but in practice I'm here with 10 tabs all called "+page.svelte" or "+page.server.ts" and it completely breaks my workflow since I can't tell them apart or navigate with fuzzy name matching. How do you deal with that?
Generally you should try to get away from clicking around on file tabs and use your command palette but one thing you can do, if you're using VS Code, is change the "Label format" to "short" in the settings.
Why should you get away from clicking tabs, apart from having to deal with this issue?
Because it's much faster, goes for most navigation in code editors, try it! :)
I'm offended! I don't click around like some lowly peasant, I navigate by keyboard like God intended.
As I've grown older, I've seen lots of improvements to software usability - it warms my hear to see the attitude of yesteryear's "you're not using it right, consider changing your lifestyle" still alive and well.
Try a JetBrains IDE - if two tabs with the same filename are open, it will automatically prepend the name of the containing folder (recursively up, until the names are different). I wouldn't know how to stay sane for the same reason otherwise.
For anyone wishing for a VS Code fix, comment on this issue: https://github.com/microsoft/vscode/issues/41909#issuecommen...
It would be great if VSCode provided an API for the tab labels but the Svelte team really created the problem in the first place.

This whole file-based routing wasn't a great idea to begin with, as a general solution to routing. It works (up to a point) for a static site generator, but most SSGs provide a permalink setting so there's an escape hatch.

The whole thing gets even worse when you start introducing issues like having dozens if not hundreds of files with the same filename, weird characters in folder and file names, etc.

I agree with this comment. SvelteKit is unnecessarily complicated. The `+page.svelte` etc are just the start of it.

Plus I can't use it with Go, PHP, Ruby, Rust etc when it comes to SSR (without running multiple servers and handling deployment nightmares).

Something about this whole Node + SSR Front-end is smelly. (next, nuxt, solidstart) I love Svelte as a framework and a way of writing UI, but SvelteKit. Eh! Not so much.

SvelteKit is too much complexity for no reason. Goes opposite of what Svelte was meant to be: Simple and intuitive.

Curious to hear more, what specifically is complicated about it?

SvelteKit is a JavaScript framework, it makes sense that you can't use it with other languages. You can pair it with a backend of your choice of course, but to get the SSR benefits you do need to work within the framework.

There are other ways of using Svelte with other languages, I would take a look at something like Inertia.js [0].

[0] https://inertiajs.com

Hey Kevin! First of all. I am a regular listener to your podcast! Love it!

Now, I am not specifically targeting SvelteKit to be fair. But the whole host of meta-frameworks like NextJS, NuxtJS etc which Vercel is pushing.

These frameworks in general are too much complexity added. SSR is hard and the best way to handle all of these is to not have a server layer at all. That is just abstract the rendering/routing part and leave the rest of the server stuffs to the user.

I want to simply write my Fastify/Express/Go-gin/Django app. Then add SvelteKit as my front-end with SSR support.

Right now, I first write SvelteKit and then think how am I going to integrate Express and Fastify to it (for a moment let's leave non-node solutions).

Trust me. If you simply leave the server out of SK and generate a simple API abstraction like `res.send(renderSKPath('/users/:id', { serverData }))`. It would have done the job.

I think its difficult to express what I want to say, but in short, remove the server and keep SK as a rendering layer only.

P.S. I know that there is an express adapter for SK. But that is not the point of this comment at all.

You're asking for two things that seem largely incompatible. How do you expect to do SSR in a Go-gin or Django app? Svelte components get compiled to JavaScript and SvelteKit is written in JavaScript. Doing SSR in those frameworks would necessitate calling JavaScript from Go or Python and introduce far more complexity if you could get it to work at all. The simplest options are either to run a Node server or turn off SSR, which you can do with 1-line in SvelteKit.
“SvelteKit is too complicated, it doesn’t even have this thing that would certainly make it more complicated!”
I completely agree.

I've been using Svelte happily for years, but I won't be using SvelteKit. In part because of the routing but also because it doesn't really solve much in the backend.

It's amazing that all the full stack frameworks (Next, Nuxt, SvelteKit, Remix, Astro, etc) are investing so much effort into reinvent the backend and after years they still don't provide even basic backend functionality. For example, out of the box, Fastify gives you validation, sessions, CORS, cache headers, etc. Features that you need in probably all backend projects.

I started this repo to figure out how to integrate Svelte with Fastify using Vite. It has hot reload, partial hydration, etc. It's very quick and dirty code, but it works.

https://github.com/PierBover/fastify-vite-svelte-template

It's only a headache if you make it one. With an open mind, it looks pretty neat to be honest. The top down inheritance doesn't look complex, just weird.
> Long gone in the past are websites that purely displayed static, seldom changing content to visitors. Today, almost all user interfaces are web applications instead of websites.

Erm, how much of the web is still powered by Wordpress, again?

> Developers dislike contributing to a legacy codebase with high technical debt.

It's more than an aesthetic & workflow preferences. It's also a client management risk. Clients who have no development experience are often used to the same level of productivity to create the initial feature set. As development slows due to maintenance & performance issues, the client does not understand why. Clients also will use analogies, such as a mechanic overcharging for work & using words the client does not understand to justify high fees & billable hours...without understanding that changing a complex system with many undocumented & haphazardly implemented parts can create bugs.

Enter a maintenance project at your own risk. Due diligence of the business, codebase, and client's temperment, understanding of software development, decision making, & payment schedule can save you from headaches over the next few months.