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

Add dependency on lemmy-client #51

Open
wants to merge 33 commits into
base: main
Choose a base branch
from
Open

Add dependency on lemmy-client #51

wants to merge 33 commits into from

Conversation

SleeplessOne1917
Copy link
Member

@SleeplessOne1917 SleeplessOne1917 commented Mar 13, 2024

Closes #49.

This is a big one, so I'll give some more info so this is more digestible.

Resource handling

I went back to the leptos-query approach of resource handling. To reiterate what I said in a comment in the last big PR:

As for why I'm putting up so much resistance to ditching leptos-query, it's mainly due to the fact that it solves several problems that we will run into. Caching and invalidating caches is a big plus, and I believe you are trying to accomplish something to that effect with the cache busting query param you added. Another major plus is its resource fetching deduplication. Whereas preventing resource duplication would require a lot of fiddling with contexts, the query approach makes it easy to write a server function and query in one file and use it in many different components without context management or duplication being a concern. Finally, I didn't run into the same issues with the library that you did.

In addition to above, I also found the code to be shorter and easier to read after using this approach in combination with some other things I will get to shortly.

Cookies

I'm using actix-session again for this. Besides (in my opinion) being easier to work with than the existing approach, it allows us to always use HttpOnly in the session cookie, making it more secure as it mitigates common XSS attacks. There were 2 other things that used cookies that I removed/commented out that I must also touch on:

Language

I don't think it makes sense to use a cookie for this. This is the sort of thing that can be derived, in order of precedence, from the user language, site language, and browser language. A cookie doesn't solve any problems here.

Theme

This is a more interesting issue. I would normally prefer to use a cookie for the theme, but the fact that theme is also tracked as a user setting and site setting in the backend makes me wonder if we should use an approach more similar to the existing inferno UI. This concern would be easier to disregard if this was a third-party UI, but the fact that this is meant to replace the default/official UI makes me think we should honor that.

This conversation can be extended to many of the other display related settings as well, e.g. post listing types (maybe a frontend wants to have its own post listing types, or maybe a user would prefer card view on their mobile app and list view on their browser).

Errors

Had to comment them out because they conflicted with what I was implementing. Will have to revisit them before this PR is taken out of draft.

Unpack

This pairs quite nicely with leptos query. It allows use to use the item from a query - or signals derived from one - to work cleanly and concisely with suspenses and error boundaries.

Misc.

  • No more browser console errors (on my machine at least)!
  • Deleted Layout and moved markup to surround Routes component instead since it wraps all the routes anyway
  • Added hash-files cargo leptos option, which adds a hash to the CSS, JS, and WASM files that get served between each build

@jim-taylor-business
Copy link
Collaborator

i know this is WIP but just to save time, i disagree with everything you've said and done in this PR for reasons i have stated in other discussions we have all had together

it's obvious we have a fundamental misunderstanding of how this stuff works. this is unfortunate to say the least, sorry, and re-writing the whole app in this manner is not something i can get behind

focusing on solving #49 only would be more useful IMO

@dessalines
Copy link
Member

What's negative about leptos-query, it seems to have a lot of benefits.

@SleeplessOne1917
Copy link
Member Author

SleeplessOne1917 commented Mar 13, 2024

@jim-taylor-business I've outlined the benefits of using leptos-query, along with the rest of my changes, above. IIRC your reasons for not using it was that it didn't work on your machine when you ran the app. I at least ask that you run this PR branch locally (along with a locally running lemmy backend with the latest changes on the main branch) to see if you still encounter errors, and reviewing the code to see if you agree with my comments about the readability benefits, before so strongly disagreeing with my approach.

}
"daisyui": "^4.7.3"
},
"packageManager": "pnpm@8.15.4"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The latest version of pnpm adds this when I install or update deps for some reason.

Comment on lines -135 to -226
#[cfg(not(feature = "ssr"))]
{
let iw = window()
.inner_width()
.ok()
.map(|b| b.as_f64().unwrap_or(0.0))
.unwrap_or(0.0);

let on_resize = move |_| {
let iw = window()
.inner_width()
.ok()
.map(|b| b.as_f64().unwrap_or(0.0))
.unwrap_or(0.0);

let mut query_params = query.get();
if iw >= 2560f64 {
query_params.insert("limit".into(), "30".to_string());
} else if iw >= 1536f64 {
query_params.insert("limit".into(), "20".to_string());
} else {
query_params.remove("limit");
}

if iw >= 640f64 {
csr_infinite_scroll_posts.set(None);
csr_paginator.set(None);
}

let navigate = leptos_router::use_navigate();
navigate(
&format!("{}", query_params.to_query_string()),
Default::default(),
);
};

window_event_listener_untyped("resize", on_resize);

if let Ok(e) = web_sys::Event::new("resize") {
on_resize(e);
}

if iw < 640f64 {
let on_scroll = move |_| {
let h = window()
.inner_height()
.ok()
.map(|b| b.as_f64().unwrap_or(0.0))
.unwrap_or(0.0);
let o = window().page_y_offset().ok().unwrap_or(0.0);
let b = f64::from(document().body().map(|b| b.offset_height()).unwrap_or(1));

let endOfPage = h + o >= b;

if endOfPage {
create_local_resource(
move || (user.get(), list_func(), sort_func()),
move |(_user, list_type, sort_type)| async move {
let form = GetPosts {
type_: list_type,
sort: sort_type,
community_name: None,
community_id: None,
page: None,
limit: None,
saved_only: None,
disliked_only: None,
liked_only: None,
page_cursor: csr_paginator.get(),
show_hidden: None,
};

let result = LemmyClient.list_posts(form).await;

match result {
Ok(mut o) => {
csr_paginator.set(o.next_page);
let mut p = csr_infinite_scroll_posts.get().unwrap_or(vec![]);
p.append(&mut o.posts);
csr_infinite_scroll_posts.set(Some(p));
}
Err(e) => {
error.set(Some(e));
}
}
},
);
}
};

window_event_listener_untyped("scroll", on_scroll);
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why we were using different fetch limits for different screen sizes. As for the infinite scroll logic, there is a library with various leptos utility functions that would greatly simplify things.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

more screen space, more content

@jim-taylor-business
Copy link
Collaborator

jim-taylor-business commented Mar 17, 2024

What's negative about leptos-query, it seems to have a lot of benefits.

it does work without it. "seems" is never good enough when you're actually going to do something,

@jim-taylor-business
Copy link
Collaborator

i've said all this before but here's my disagreements with this again:

  • there are no data caching solutions identified that it provides, it's just adding boilerplate and complexity and could easily be added later when caching is identified as a requirement
  • the caching problem i had to solve was a server issue between the server and the bare metal browser that forced caching
  • the cookies were useful in non authenticated mode so no session has been established. IIRC the type of cookie being used could be specified in the constructor
  • i hope it works well CSR only mode of operation where there is no leptos server
  • i hope it works well with SSR only mode also
  • not sure i can help with understanding leptos context signals they seem pretty straight forward to me

i hope things are more stable now also, these extra libraries caused show stopping issues in the past

@SleeplessOne1917
Copy link
Member Author

there are no data caching solutions identified that it provides, it's just adding boilerplate and complexity and could easily be added later when caching is identified as a requirement

I think I'm starting to get a better understanding of the issue you have with my approach. If I understand you correctly, regardless of whether or not the caching and invalidation functionality provided by lemmy-client works/is useful, we haven't gotten to a point where those are issues yet and my usage of the library is a premature optimization. Is that an accurate interpretation?

the caching problem i had to solve was a server issue between the server and the bare metal browser that forced caching

Looking back at the PR you introduced that change in, the problem you were solving was ds9.lemmy.ml not sending back cache control headers. This isn't a problem when testing against a locally running instance. @dessalines is the the lack of cache control headers in ds9's responses a deliberate configuration choice or accidental misconfiguration?

the cookies were useful in non authenticated mode so no session has been established. IIRC the type of cookie being used could be specified in the constructor

Makes sense considering cookies were also being used for language and theme. I've detailed my thoughts on using cookies for those in the OP. I think the actix-session is easiest when dealing only with authentication, however how currently set theme should be tracked is something that needs to be ironed out and goes outside the scope of this PR (and even this project).

i hope it works well CSR only mode of operation where there is no leptos server
If you're asking if it can be run with trunk, I haven't tested it with that yet and will need to get back to you. However, I don't know why we would want to rely on CSR only as opposed to a SSR page that gets hydrated with client side reactivity.

i hope it works well with SSR only mode also
I've tested it out with javascript and wasm disabled on my browser and everything supported so far works (will attach screen recording when I get the chance).

not sure i can help with understanding leptos context signals they seem pretty straight forward to me
I'm not having trouble understanding them. The use of contexts and leptos-query isn't mutually exclusive however. I've even added a context for site state that uses the advantages of leptos-query's caching/invalidation while removing the need for creating a query scope everywhere it is used.

@jim-taylor-business
Copy link
Collaborator

jim-taylor-business commented Mar 24, 2024

I think I'm starting to get a better understanding of the issue you have with my approach. If I understand you correctly, regardless of whether or not the caching and invalidation functionality provided by lemmy-client works/is useful, we haven't gotten to a point where those are issues yet and my usage of the library is a premature optimization. Is that an accurate interpretation?

yes, it's a solution looking for a problem at the moment. it has caused all sorts of problems for me in the past. i'm guessing it will not solve the caching problem. i haven't seen it progressively enhance to CSR only mode. so at the moment it obfuscates server communication and the vanilla leptos version works fine without it.

This isn't a problem when testing against a locally running instance. @dessalines is the the lack of cache control headers in ds9's responses a deliberate configuration choice or accidental misconfiguration?

i have replicated this locally. i totally agree that if we are going to use the site get request to tell us important information like whether we are authenticated or not then the server should add a pragma no-cache header. will submit PR with some e2e tests to test for it locally today. it's very timing and maybe browser sensitive but i'm sure the cache header would fix it. might submit a PR to the server project to get some discussion going over there.

Makes sense considering cookies were also being used for language and theme. I've detailed my thoughts on using cookies for those in the OP. I think the actix-session is easiest when dealing only with authentication, however how currently set theme should be tracked is something that needs to be ironed out and goes outside the scope of this PR (and even this project).

i agree the final solution has not been defined yet and will involve the lemmy server significantly so what is there is just useful for testing and i think, for now, is a nice feature. i also don't think we need to copy what's currently happening in Lemmy UI if it is small useful addition to a feature.

If you're asking if it can be run with trunk, I haven't tested it with that yet and will need to get back to you. However, I don't know why we would want to rely on CSR only as opposed to a SSR page that gets hydrated with client side reactivity.

CSR mode is naturally used when the same code is used for a Android/iOS/Windows/MacOS app and it is currently a declared objective of the project on the homepage so that's why i made everything work with that mode. it's a feature of Leptos generally and i think the whole isomorphic rust thing is cool.

I'm not having trouble understanding them. The use of contexts and leptos-query isn't mutually exclusive however. I've even added a context for site state that uses the advantages of leptos-query's caching/invalidation while removing the need for creating a query scope everywhere it is used.

cool. i seem to remember i put the site state in the context as well and had some performance issues with it as it can be pretty large and is copied around a lot which is why i went for a simple boolean flag to indicate logged in status. that was a while ago though so Leptos might have optimized that better now. oh actually now i think about it contexts don't work in SSR mode so i had to make the site info a signal passed down in a property.

@dessalines
Copy link
Member

Looking back at the PR you introduced that change in, the problem you were solving was ds9.lemmy.ml not sending back cache control headers. This isn't a problem when testing against a locally running instance. @dessalines is the the lack of cache control headers in ds9's responses a deliberate configuration choice or accidental misconfiguration?

Those are set in the back-end, and don't look like they're being overridden in nginx, but I do see that ds9.lemmy.ml is running a test back-end version. voyager.lemmy.ml is on 0.19.3.

@jim-taylor-business
Copy link
Collaborator

jim-taylor-business commented Mar 26, 2024

Those are set in the back-end, and don't look like they're being overridden in nginx, but I do see that ds9.lemmy.ml is running a test back-end version. voyager.lemmy.ml is on 0.19.3.

the reason the site cache bug is not happening in lemmy UI is because it does not refresh the site object when you logout, only when you log in.

the browser cache defaults to "private" when you're logged in. i guess because there is a auth token header set at that time.

when you are logged out the cache default is 60s which is why the bug occurs when you immediately log back in.

the work around is not to refresh the site information on logout, just clear the my_user information which i guess is roughly what happens in lemmy UI.

another work around is to explicitly prevent caching by setting headers in lemmy server on the site endpoint.

both work in my testing

@SleeplessOne1917
Copy link
Member Author

@jim-taylor-business now that I better understand your gripe with leptos-query, I think we're on the same page. At this point, I could rewrite what I currently have to use vanilla resources, though I want to hold off pulling the trigger unless smoke testing of the app reveals that it's causing problems.

Regarding the caching issues you mentioned: is there a way to consistently reproduce the bug? It could very well be a browser issue as you said. I've tested my changes on Firefox, Chromium, and Librewolf and haven't run into the issue.

About CSR: I haven't tested that yet and definitely need to make sure my changes work there (which I doubt they do at the time of making this comment). Do you use trunk to test CSR? Or is there some feature of cargo leptos that lets me use CSR instead of SSR with hydrate?

Finally, I will re-add the cookie stuff for the languages and themes, although I would like to keep the actix session approach for handling the auth cookie.

@jim-taylor-business
Copy link
Collaborator

jim-taylor-business commented Apr 5, 2024

@jim-taylor-business now that I better understand your gripe with leptos-query, I think we're on the same page. At this point, I could rewrite what I currently have to use vanilla resources, though I want to hold off pulling the trigger unless smoke testing of the app reveals that it's causing problems.

Finally, I will re-add the cookie stuff for the languages and themes, although I would like to keep the actix session approach for handling the auth cookie.

so is the only reason these two libraries are being used is that you are convinced they will be useful in the future?

Regarding the caching issues you mentioned: is there a way to consistently reproduce the bug? It could very well be a browser issue as you said. I've tested my changes on Firefox, Chromium, and Librewolf and haven't run into the issue.

the cache bug details are in my post just above and are reproduced in the end to end tests. maybe something you've already done has fixed it.

About CSR: I haven't tested that yet and definitely need to make sure my changes work there (which I doubt they do at the time of making this comment). Do you use trunk to test CSR? Or is there some feature of cargo leptos that lets me use CSR instead of SSR with hydrate?

yeah you can use trunk

@SleeplessOne1917
Copy link
Member Author

I removed leptos-query from the dependencies for now. I thought I needed it to manually refetch the resources, but it turns out resources already have that functionality. I'll see what I can do about removing actix-session. I will be shifting my priority to the JS UI for the next few days to get it ready for 0.19.4.

@jim-taylor-business
Copy link
Collaborator

cool, good luck with Lemmy UI

i'm just interested to know what your idea is for the design in future and how these crates play a role, because i do recognise that they do things that could be useful and i just can't think of the features or design where that happens

@dessalines
Copy link
Member

No probs, and no rush on this of course, but it still would be nice to have this dependent on your lemmy-client-rs, I think we're all in agreement there.

@SleeplessOne1917
Copy link
Member Author

@jim-taylor-business How did you run the project with CSR before? Trunk's docs mention that it needs to have an index.html, but there was no such file before I started this PR.

@dessalines
Copy link
Member

ping me when you want me to take another look.

@SleeplessOne1917
Copy link
Member Author

@dessalines trying to make this work in CSR while using the server actions/functions as a single source of truth for making API requests lead me down a rabbit hole. You can see an experiment I made investigating this here: https://github.com/SleeplessOne1917/trunk-cargo-leptos-example. If you're fine needing to go through some inconvenient steps to test this locally, I think this is good to take out of draft.

@SleeplessOne1917 SleeplessOne1917 marked this pull request as ready for review April 29, 2024 19:38
Comment on lines +10 to +12
leptos = { version = "0.6", features = ["nightly"] }
leptos_meta = { version = "0.6", features = ["nightly"] }
leptos_router = { version = "0.6", features = ["nightly"] }
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leptos 0.7 is going to be a full rewrite of the reactive system. While the maintainer said he is doing everything he can to keep the API changes minimal, I think it's safer to handle upgrading to 0.7 as its own PR. At the very least, I know there are changes in how suspenses are handled in 0.7. You can learn more about the changes coming in 0.7 in the most recent monthly meetup.

@jim-taylor-business
Copy link
Collaborator

jim-taylor-business commented Apr 30, 2024

@jim-taylor-business How did you run the project with CSR before? Trunk's docs mention that it needs to have an index.html, but there was no such file before I started this PR.

I actually tested it as part of a Tauri app and generated some HTML and CSS in that project. I found that leptos handles the transition to CSR-only very gracefully as long as you don't force the use of the leptos server functions

@jim-taylor-business
Copy link
Collaborator

jim-taylor-business commented Apr 30, 2024

@SleeplessOne1917 is there any chance you could make a new summary of what's changed just to provide an overview?

I'm guessing the summary at the beginning of this PR is out of date.

just a bullet list of the improvements and feature removals or changes would give a better idea of what you've done and why

@jim-taylor-business
Copy link
Collaborator

@SleeplessOne1917 i can't see any handling of the errors returned by the lemmy_client or any user feedback

also the login goes into some kind of infinite loop on a bad login.

i guess this is still WIP as i notice the pipeline tests are not passing?

@jim-taylor-business
Copy link
Collaborator

jim-taylor-business commented Apr 30, 2024

@dessalines trying to make this work in CSR while using the server actions/functions as a single source of truth for making API requests lead me down a rabbit hole. You can see an experiment I made investigating this here: https://github.com/SleeplessOne1917/trunk-cargo-leptos-example. If you're fine needing to go through some inconvenient steps to test this locally, I think this is good to take out of draft.

@SleeplessOne1917 in CSR mode the Leptos SSR server does not exist. Trunk is only used to test this because it is a simple web server.

when you are running the code on the desktop or mobile app Trunk is not guaranteed to exist either. the HTML and CSS will be hard coded and everything will be rendered in the browser and the only server to be communicated with will be the Lemmy instance.

that's why the client moves to using the direct communication to the lemmy instance, it doesn't need the server function as a proxy. you can easily share common functions (sources of truth) between the two.

@SleeplessOne1917
Copy link
Member Author

I actually tested it as part of a Tauri app and generated some HTML and CSS in that project.

That explains why I couldn't get it working with Trunk out of the gate.

is there any chance you could make a new summary of what's changed just to provide an overview? I'm guessing the summary at the beginning of this PR is out of date.

I'll look over the changes again and make a review either later tonight or tomorrow. The scope of this PR definitely crept while I was working on it.

@SleeplessOne1917 in CSR mode the Leptos SSR server does not exist. Trunk is only used to test this because it is a simple web server.
when you are running the code on the desktop or mobile app Trunk is not guaranteed to exist either. the HTML and CSS will be hard coded and everything will be rendered in the browser and the only server to be communicated with will be the Lemmy instance.
that's why the client moves to using the direct communication to the lemmy instance, it doesn't need the server function as a proxy. you can easily share common functions (sources of truth) between the two.

I admittedly went down a rabbit hole trying to figure out how to reuse server actions between all of our use cases to no avail. I'll shift closer to what you were originally doing for CSR, although I'm going to try using client side actions before trying regular on submit handlers.

Also, are we set on Tauri as the desktop app framework? I know in the README it says we've yet to agree on a framework for that, but it's the only framework I know of that lets us use our webapp code for a desktop app. The closest thing to alternative that meets that criterion and comes to my mind is if we wait for if/when Leptos supports being use with GTK or another UI library, but the closest thing that exists to that currently is a tiny demo example app. If we are going with Tauri, we may have a better way of storing sessions/selected theme than using cookies since we'll have access to more than just the browser APIs.

@SleeplessOne1917
Copy link
Member Author

SleeplessOne1917 commented May 1, 2024

Per @jim-taylor-business's request, here is a list of changes.

Additions

  • lemmy-client for requests
  • Theme enum for themes
  • Unwrap component to make it easier to use resources with Suspenses and ErrorBoundarys
  • A cookie middleware for handling session cookies
  • Contexts for current site state and theme
  • derive_query_signal fn to make it easier to derive signals from resources that use server fns
  • derive_user_is_logged_in to easily get whether to use is logged in from the site state.

Removals

  • Client side cookie handling (will go into this more in a minute)
  • Error types specific to our app (I think matching off of the LemmyErrorType returned in failed requests works for now, and any errors specific to this frontend app alone can be addressed once we reach a point we need to do it)
  • Infinite scroll logic
  • CSR event handling/resource fetching

Regarding CSR/Desktop App

After working and thinking on this awhile, I'm starting to question if we should be worrying about CSR at this point of development. We know for certain that this is going to be used in the browser, so handling SSR and hydrated cases is a given. However, how strongly decided are we on making this into a desktop app as well? I ask because having access to more than just the browser APIs on the frontend likely warrants doing some things differently. For example, it could be the case that something like tauri-plugin-stronghold is a more appropriate way of storing login sessions than cookies. I consulted both the Leptos and Tauri discords on the subject and there is no preferred/idiomatic way of doing this. It doesn't help that tauri + leptos examples and templates are few and far between, and none I found demonstrated managing sessions.

Since this is already a big initiative with it being a re-implementation of a large existing frontend we want to reach feature parity with, and since how to handle a leptos app with tauri is currently sparse on examples we can reference and completely undocumented, I think it would be wiser to focus on making this a working webapp for use in browsers (so SSR and hydrate) first and refactor if we ever end up using this for a desktop app as well.

@dessalines
Copy link
Member

I've had no time to work on this tho, so I really don't get a say.

IMO we should prioritize this as an SSR app. This is still a web framework, not "native" at all. If someone wants to create a native app they should use a desktop UI framework like GTK or QT or one of the rust cross-platform-ish ones, or else just create a thin web wrapper that calls the SSR. A javascript SPA (which is what the CSR would be), doesn't really make sense IMO.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add dependency on lemmy-client
3 participants