RFC: Introduce server-side data fetching for components

This issue has been tracked since 2023-01-06.

Which scope/s are relevant/related to the feature request?

platform

Information

This would add inline/external for components to fetch data, and be exposed to the component through an injectable function.

Requirements

  • Loaders would be inline/external to the component code
    • Loaders would be tree-shaken from the browser bundle
  • Code from the loader would run server-side only, with some glue code to run on the client
  • Type-safe API

Inline

// page.component.ts
import { AsyncPipe, JsonPipe } from "@angular/common";
import { Component } from "@angular/core";
import db from './db';

import { useLoader } from "@analogjs/router";

export const loader = async() => {
  const items = db.getItems();

  return {
    items: items
  };
};
@Component({
  selector: 'app-test',
  standalone: true,
  imports: [AsyncPipe, JsonPipe],
  template: `
    Test works

    {{ data$ | async | json }}
  `
})
export default class TestComponent {
  data$ = useLoader<typeof loader>(); // <-- { items: Item[] }
}

External

// page.server.ts
import db from './db';

export const loader = async() => {
  const items = db.getItems();

  return {
    items: items
  };
};
// page.component.ts
import { AsyncPipe, JsonPipe } from "@angular/common";
import { Component } from "@angular/core";
import { useLoader } from "@analogjs/router";

@Component({
  selector: 'app-test',
  standalone: true,
  imports: [AsyncPipe, JsonPipe],
  template: `
    Test works

    {{ data$ | async | json }}
  `
})
export default class TestComponent {
  data$ = useLoader<typeof loader>(); // <-- { items: Item[] }
}

Describe any alternatives/workarounds you're currently using

No response

I would be willing to submit a PR to fix this issue

  • Yes
  • No
marcus-sa wrote this answer on 2023-01-11

What about dependency injection?
It would've been great to define loaders as route resolvers or methods on components.

brandonroberts wrote this answer on 2023-01-11

Dependency injection works as normal on the client side, as it's a resolver that calls a backend API. The useLoader is a wrapper around the ActivatedRoute and a resolve property. Nothing too complex there to start. Loaders on route components feel too invasive and require going outside the normal component path

marcus-sa wrote this answer on 2023-01-11

Dependency injection works as normal on the client side, as it's a resolver that calls a backend API. The useLoader is a wrapper around the ActivatedRoute and a resolve property. Nothing too complex there to start. Loaders on route components feel too invasive and require going outside the normal component path

I'm referring to inversion of control/dependency injection on the server side :)

brandonroberts wrote this answer on 2023-01-11

Ahh, no its not doing that. I don't see much value in having DI there as you would mostly be using imports to access server-only code like Prisma, file-system access, etc.

marcus-sa wrote this answer on 2023-01-11

Ahh, no its not doing that. I don't see much value in having DI there as you would mostly be using imports to access server-only code like Prisma, file-system access, etc.

I don't necessarily agree with that statement. I've used Remix extensively, to build a subscription-based content creation platform, and it's a pain in the ass without DI on the server side. The amount of boilerplate code and workarounds required is crazy. Angular already supports DI for SSR, so I don't see why loaders shouldn't.

brandonroberts wrote this answer on 2023-01-11

If you have some more concrete examples that would be great. Angular DI in SSR also assumes you're using the component as an API endpoint though, correct? I'm not intending to run Angular components on the server (yet 😉), so I'm trying to see where DI would fit in

goetzrobin wrote this answer on 2023-01-11

How hard would it be to do something similar to NextJs and provide two loaders:

  1. Like getServerSideProps who runs on every new request
  2. Like getStaticProps which runs only on build time when static pages are built

Do you think there’s merit in doing that?
Interested to hear your opinion!

brandonroberts wrote this answer on 2023-01-11

Those features are worth considering, but we don't necessarily have to mimic them as-is. NextJS is moving away from getServerSideProps and getStaticProps also with the 13.x release and app directory.

goetzrobin wrote this answer on 2023-01-11

I didn't even know that until you pointed it out!
Seems like the tree shaken loader that you describe would be perfect then.
I need to try it, but I assume that Nitro automatically serves a pre-rendered route and if no static html exists it generates the page on each request. Then, having two functions definitely seems unnecessary.

I don't want to hijack this RFC with (sort of) unrelated things but looking at this NextJS documentation and this configuration option for Nitro made me think that it would be cool if you could add some config snippet (like 'use static'; or 'use swc'; ) to the top of the file and based on that the route would be marked as static, cached, etc.

More Details About Repo
Owner Name analogjs
Repo Name analog
Full Name analogjs/analog
Language TypeScript
Created Date 2022-07-06
Updated Date 2023-03-28
Star Count 885
Watcher Count 18
Fork Count 67
Issue Count 33

YOU MAY BE INTERESTED

Issue Title Created Date Updated Date