Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

load function not working #911

Closed
2 tasks
jdgamble555 opened this issue Feb 28, 2024 · 13 comments
Closed
2 tasks

load function not working #911

jdgamble555 opened this issue Feb 28, 2024 · 13 comments
Labels
bug Something isn't working

Comments

@jdgamble555
Copy link

jdgamble555 commented Feb 28, 2024

Please provide the environment you discovered this bug in.

I'm following the directions:
https://analogjs.org/docs/features/data-fetching/server-side-data-fetching

And I get an undefined error in both dev and prod.

Which area/package is the issue in?

vite-plugin-angular

Description

ERROR TypeError: Cannot read properties of undefined (reading 'loaded')

Please provide the exception or error you saw

main.ts:5 ERROR TypeError: Cannot read properties of undefined (reading 'loaded')
    at HomeComponent_Template (index.page.ts?v=138da47c:38:56)
    at executeTemplate (chunk-C4LID52L.js?v=138da47c:6347:5)
    at refreshView (chunk-C4LID52L.js?v=138da47c:7384:7)
    at detectChangesInView (chunk-C4LID52L.js?v=138da47c:7547:5)
    at detectChangesInViewIfAttached (chunk-C4LID52L.js?v=138da47c:7531:3)
    at detectChangesInComponent (chunk-C4LID52L.js?v=138da47c:7525:3)
    at detectChangesInChildComponents (chunk-C4LID52L.js?v=138da47c:7567:5)
    at refreshView (chunk-C4LID52L.js?v=138da47c:7440:7)
    at detectChangesInView (chunk-C4LID52L.js?v=138da47c:7547:5)
    at detectChangesInViewIfAttached (chunk-C4LID52L.js?v=138da47c:7531:3)

Other information

I want the variable to load on the server, not get hydrated and then updated either way. I would also think the load function would use a resolver?

Here is the affected pages:

https://github.com/jdgamble555/analog-test/tree/master/src/app/pages

Trying to figure out Analog for the first time :)

J

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

  • Yes
  • No
@jdgamble555 jdgamble555 added the bug Something isn't working label Feb 28, 2024
@brandonroberts
Copy link
Member

Not sure why the bare input isn't working yet, but using the injectLoad + async pipe works fine

brandonroberts/jdgamble555-analog-test@7c8ffcb

https://jdgamble555-analog-test.vercel.app/

@jdgamble555
Copy link
Author

Ok, that fixes it, but the data still jumps:

https://analog-test-mu.vercel.app/

https://github.com/jdgamble555/analog-test/blob/master/src/app/pages/index.page.ts

I'm trying to figure out where the state transfer takes place on this.

J

@brandonroberts
Copy link
Member

I see. It happens here https://github.com/analogjs/analog/blob/main/packages/router/src/lib/route-config.ts#L51-L56

HttpClient isn't used during prerendering though, as it's a direct API request.

@brandonroberts
Copy link
Member

brandonroberts commented Feb 28, 2024

Is there some other way to detect its using edge rendering at build time than the globalThis in the Vercel environment?

@brandonroberts
Copy link
Member

brandonroberts commented Feb 28, 2024

I think if you visit a non-prerendered page and use SSR it should work correctly. You can also skip prerendering of the / page by using an empty array in the prerender config

analog({
  prerender: {
    routes: []
  }
})

@brandonroberts
Copy link
Member

@jdgamble555
Copy link
Author

Ok got it!

https://analog-test-mu.vercel.app/

So it was prerendering thing. I would think that should be disabled by default as most front pages are going to be dynamic?

J

@brandonroberts
Copy link
Member

brandonroberts commented Feb 28, 2024

We discussed this previously and most sites building with Analog would prerender the root URL unless using something like tRPC

https://analogjs.org/docs/features/server/server-side-rendering#prerendering-routes

@jdgamble555
Copy link
Author

@brandonroberts - I've been thinking more about this. I think the async part of the function should be done before the component even loads. You can do this with APP_INITIALIZER and abstractions.

I updating an old article on preloading data in angular universal to show how this is done now-a-days.

REPO: GitHub
data.service.ts: GitHub
Demo:: Vercel

Maybe the core code of Analog should work this way. This is how SvelteKit, Nuxt, Next, etc would do it. @brandonroberts what are your thoughts?

J

@jdgamble555 jdgamble555 reopened this Mar 3, 2024
@jdgamble555
Copy link
Author

@brandonroberts - Just wanted to give you an example of the resolver version:

  1. Create a resolver for the path
    https://github.com/jdgamble555/angular-17-todo/blob/master/src/app/components/about/about.resolver.ts
  2. Add the resolver to the route
    https://github.com/jdgamble555/angular-17-todo/blob/master/src/app/app.routes.ts
  3. Show the data from the resolver
    https://github.com/jdgamble555/angular-17-todo/blob/master/src/app/components/about/about.component.ts

The component will not load until the data is resolved. If you use an observable (toSignal is best), and you have data that could change, you could easily convert it for child routes etc. and the data will get updated by the observable.

https://angular-17-todo.vercel.app/


So in Analog's case, you could:

  1. You could import the server route instead of the service, call it with fetch (or http), and it will get updated on each page load.
  2. You could add an option to cache the results or not.
  3. Of course you would also want to use CSRF - Use the Edge Middleware Package probably.
  4. And it will reload the resolver on every load, but cache the server data if you want it to.

All of this under-the-hood.

Some ideas... either way, I firmly believe the resolver is made for this.

J

@brandonroberts
Copy link
Member

@jdgamble555 we're missing the CSRF/cache part, but this is also what the injectLoad with .page.ts and .server.ts files do today.

1/2. "load" resolver for the route

  1. Show the data

You can also define a resolver in the RouteMeta for a page route.

// about.page.ts
export const routeMeta: RouteMeta = {
  resolve: {
    load: LoadResolver
  }
};

@Component({...})
export default class AboutComponent {
  data = toSignal(injectLoad(), { requireSync: true });
}

We could make this work for manually configured routes also. I agree a resolver works for both here though

@jdgamble555
Copy link
Author

No I figured that's how it works, but you could probably simplify the code with a resolver.

Does your code refetch on the browser after the server loads? I forgot that the resolver is ran on both the server and browser so you would need to transfer the state to avoid refetching. That actually is a cache itself, so I was able to get rid of the random cache service.

https://github.com/jdgamble555/angular-17-todo/blob/master/src/app/components/about/about.resolver.ts


Side Note: It looks like this is how SvelteKit is getting the URL on the server so you could avoid the ENV variable. (I'm not understanding why you have it).

https://github.com/sveltejs/kit/blob/877f4bbd2e111602b222c10621c431b09accf7a7/packages/kit/src/utils/url.js#L144

J

@jdgamble555
Copy link
Author

Closing in favor of this:

#1033

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants