Git Product home page Git Product logo

leptos's People

Contributors

agilarity avatar akesson avatar aperepel avatar benwis avatar blorbb avatar chrisp60 avatar danheuck avatar danikvitek avatar dgsantana avatar flosse avatar fundon avatar g-re-g avatar gbj avatar gentle avatar gibbz00 avatar ilmmatias avatar indrazar avatar jquesada2016 avatar killertux avatar lpotthast avatar maccesch avatar markcatley avatar martinfrances107 avatar modprog avatar mrvillage avatar novacrazy avatar paul-hansen avatar sjud avatar sleeplessone1917 avatar tqwewe avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

leptos's Issues

Examples are excluded from workspace

Examples are excluded from the workspace and this makes rust-analyzer skip them on my machine. Do you use a special setup to circumvent that, or is this an oversight? While I don't have much experience with setting up rust projects, I feel like examples should simply be members of the workspace.

`view!` supporting `Option` on attributes, props, and event listeners

Often when receiving optional props, it would be really convenient to allow the macro to accept option types for event handlers and such. This would also allow conditionally attaching event listeners which can become performance hits on components which are heavily reused.

Components are rendering out of order when mixed with HTML elements

Using version 0.0.15, the following results in out of order rending:

use leptos::*;
use wasm_bindgen::prelude::*;

#[wasm_bindgen(start)]
pub fn start() {
  mount_to_body(view_fn);
}

fn view_fn(cx: Scope) -> impl Mountable {
  view! { cx,
    <form>
      <TextInput />
      <button>"Clcik me?"</button>
    </form>
  }
}

#[component]
fn TextInput(cx: Scope) -> Element {
  view! {cx,
    <input />
  }
}

If I inline the component, i.e, <form><input /> ..., then it works, if I remove the surrounding <form> then it also renders correctly.

Create contributors' guide

Per @jquesada2016 in #53 (comment) it would be a great idea to put together a short guide to make it easier for people to contribute.

I'm curious to hear from others what sort of stuff would be useful in there.

Outline of the various packages and what goes where? General approach of each? Normal flow of execution in the program?

What would be useful?

Update to `syn-rsx` 0.9 to allow things like `on:my-event`

Currently the syn-rsx crate doesn't allow mixing colons and dashes in attribute names, which breaks the on: syntax in custom event names, which are encouraged to have a dash like my-event.

I had a PR merged to syn-rsx that would allow this, but there are also some other breaking changes in their 0.9 release, so I'll need to make sure we're up to date.

Discord

Would it be possible to create a Discord for an informal way of communicating?

I'm possibly going to use Leptos for a project that needs to launch in some months and I'd like to know my degree of insanity for even considering it ;)

Reactive system panicking at `already borrowed: BorrowMutError`

I am working on a repro, but just wanted to raise the issue.

Here is a backtrace:

panicked at 'already borrowed: BorrowMutError', C:\Users\jose2\.cargo\git\checkouts\leptos-852582868f14a87e\21d7346\leptos_reactive\src\signal.rs:726:32

Stack:

Error
    at http://localhost:5173/src/wasm/wasm.js:428:21
    at logError (http://localhost:5173/src/wasm/wasm.js:237:18)
    at imports.wbg.__wbg_new_abda76e883ba8a5f (http://localhost:5173/src/wasm/wasm.js:427:66)
    at console_error_panic_hook::Error::new::hca9359d70b7a65b0 (http://localhost:5173/src/wasm/wasm_bg.wasm:wasm-function[7886]:0x2525df)
    at console_error_panic_hook::hook_impl::hd6342f4a1d3ee1fa (http://localhost:5173/src/wasm/wasm_bg.wasm:wasm-function[1491]:0x151490)
    at console_error_panic_hook::hook::h5583c33e69aaa70c (http://localhost:5173/src/wasm/wasm_bg.wasm:wasm-function[8484]:0x25aaca)
    at core::ops::function::Fn::call::h4709acb035a3f1ae (http://localhost:5173/src/wasm/wasm_bg.wasm:wasm-function[7565]:0x24d60d)
    at std::panicking::rust_panic_with_hook::h3534cfedda92faa6 (http://localhost:5173/src/wasm/wasm_bg.wasm:wasm-function[3320]:0x1d0181)
    at std::panicking::begin_panic_handler::{{closure}}::h0b26f08fa80310e7 (http://localhost:5173/src/wasm/wasm_bg.wasm:wasm-function[4244]:0x1fa6ba)
    at std::sys_common::backtrace::__rust_end_short_backtrace::hbf7b83761deb4f3e (http://localhost:5173/src/wasm/wasm_bg.wasm:wasm-function[9085]:0x2624d1)

Uncaught (in promise) RuntimeError: unreachable
    at __rust_start_panic (wasm_bg.wasm:0x26966c)
    at rust_panic (wasm_bg.wasm:0x264e18)
    at std::panicking::rust_panic_with_hook::h3534cfedda92faa6 (wasm_bg.wasm:0x1d01ac)
    at std::panicking::begin_panic_handler::{{closure}}::h0b26f08fa80310e7 (wasm_bg.wasm:0x1fa6ba)
    at std::sys_common::backtrace::__rust_end_short_backtrace::hbf7b83761deb4f3e (wasm_bg.wasm:0x2624d1)
    at rust_begin_unwind (wasm_bg.wasm:0x23a916)
    at core::panicking::panic_fmt::h855c11889f2fb721 (wasm_bg.wasm:0x25989d)
    at core::result::unwrap_failed::ha83ac9268ec678d9 (wasm_bg.wasm:0x212ae5)
    at core::cell::RefCell<T>::borrow_mut::h38eb0755cd71904b (wasm_bg.wasm:0x198361)
    at leptos_reactive::signal::SignalId::update::h68bb1fd62dd948e3 (wasm_bg.wasm:0x3a8e7)

Server functions create possible naming conflicts

At the moment these are all defined by urls on the pattern /function_name

This works but is obviously dumb.

  1. You should be able to prefix them with whatever you want, so for example, you as a developer should be able to specify "all my server functions should start with /api" while registering them
  2. There are obvious conflicts here. It wouldn't be a great idea but I could easily create two different functions called my_server_fn in two different modules and they'd both try to be served at /my_server_fn, with stupid consequences.

The macro should prepend the current module path to the URL, and the registration function should take an optional prefix, which should feed back into the server fn itself so it updates its URL to include that prefix.

Migrate examples to single-folder structure

Some of the examples (that use SSR + hydration) are divided into three directories: one for the server, one for the client, and one for the app. This used to be necessary to allow you to compile the hydration code to Wasm and the SSR code for the server without causing feature conflicts.

This problem no longer exists because the feature flags are no longer contradictory. So the hackernews and counter_isomorphic examples can be rewritten to use a single-create/single-directory structure instead.

See the model here.

Cannot return `<template />` from a component

The following example results in a panic:

use leptos::*;
use wasm_bindgen::prelude::*;

#[wasm_bindgen(start)]
pub fn start() {
  console_error_panic_hook::set_once();

  mount_to_body(view_fn);
}

fn view_fn(cx: Scope) -> impl Mountable {
  view! { cx,
    <TemplateComponent></TemplateComponent>
  }
}

#[component]
fn TemplateComponent(cx: Scope) -> Element {
  view! { cx,
    <template>
      <div>"Just doing the Lord's work."</div>
    </template>
  }
}

This only seems to happen if directly returning a <template /> from the top level of a component.

The full stack trace is:

Uncaught (in promise) Error: `unwrap_throw` failed
    at imports.wbg.__wbindgen_throw (wasm.js?t=1667929395579:292:15)
    at wasm_bindgen::throw_str::hafba1a1a4c068143 (wasm_bg.wasm:0x4508d)
    at <core::option::Option<T> as wasm_bindgen::UnwrapThrowExt<T>>::expect_throw::h01d589852a07341a (wasm_bg.wasm:0x3ac67)
    at wasm_bindgen::UnwrapThrowExt::unwrap_throw::h568eba629f01842e (wasm_bg.wasm:0x42212)
    at wasm::TemplateComponent::hb3dcae73f423c169 (wasm_bg.wasm:0x3149c)
    at wasm::view_fn::{{closure}}::h573caef1eccbc7ff (wasm_bg.wasm:0x3f78f)
    at leptos_reactive::scope::Scope::untrack::hf1b86e9da7ad8dd0 (wasm_bg.wasm:0x320d5)
    at leptos_dom::create_component::ha566be4d30a0487a (wasm_bg.wasm:0x3fae6)
    at wasm::view_fn::he21f89cb96e65078 (wasm_bg.wasm:0x392b3)
    at core::ops::function::Fn::call::ha4ca8e44e588d793

Also, reading the stack trace, just a heads up, using unwrap_throw is unsound as it leads the stack in a potentially non-reentrant state, so if a user catches the JS exception, they will most likely experience UB.

Migrate server functions back to `serde_urlencoded`

JSON-encoding each field separately using your chosen library (serde, serde-lite, or miniserde) sounds like a great idea, but actually works terrible for form inputs: the strings they send, because they're not wrapped in quotes, don't parse as a JSON string. Oops.

Is it possible to condense the three-directory server/client/app model into one?

We've been talking on Discord a little about this.

I think it should be possible, now that the csr/ssr/hydrate features aren't mutually exclusive, to write a complete server-rendered-and-browser-hydrated app in a single directory.

Browser/specific code can compile on the server, but not run. Server code usually can't compile for Wasm.

You'd need to use #[wasm_bindgen] to annotate the function you are using to hydrate the app (i.e., basically the few lines of code that are in hackernews-client), and call that function from the HTML you're generating on the server.

Then put the actual server code behind a #[cfg(feature = "ssr")] flag so that it doesn't try to compile actix-web or whatever to Wasm.

Bonus points if it's also Trunk-compatible for an easy dev-mode client-side-rendered version.

If someone wants to try it out in the hackernews directory and submit a PR I'd give them major kudos. @akesson it seems like this may be up your alley as you're working on cargo-leptos too... Let me know if you're interested in giving it a try.

Add more helpful error messages in `leptos_reactive`

Much of the reactive system is built on RefCell, which for some reason gives really unhelpful error messages in the browser, even in debug mode, because it doesn't give line numbers as it does in the console. (At least for me. Chrome tends to be better than Firefox with Wasm errors, but still not great.)

I usually don't see panic messages in Wasm error output either, so I have a debug_warn! macro in leptos_reactive that uses println! syntax to log a warning to the console but is stripped out in release builds for bundle size.

It would be good to replace all the borrow_mut()a in leptos_reactive with try_borrow_mut()s that catch and log an appropriate error with debug_warn!

Some of these don't even need to panic: for example if you're trying to run an effect or update a signal they can log the warning and then do nothing. Reading a signal that has been disposed does need to panic (unless someone has a better solution), because otherwise there's no value to return.

This helps with debugging issues like #25

`Element` mixed with `Vec<Element>` causes nothing to render

The following example renders nothing, I assume this is related to #53.

use leptos::*;
use wasm_bindgen::prelude::*;

#[wasm_bindgen(start)]
pub fn start() {
  mount_to_body(view_fn);
}

fn view_fn(cx: Scope) -> impl Mountable {
  let (sig, _) = create_signal(cx, view! { cx, <span /> });

  let data = || {
    view! { cx,
      <>
        <h1>"1"</h1>
        <h1>"2"</h1>
        <h1>"3"</h1>
      </>
    }
  };

  view! { cx,
    <span>
      {data}    // <-- wrapping this in a <span /> fixes rendering
      <h1>"4"</h1>
    </span>
  }
}

Bug: append_nodes Failed

Screen Shot 2022-10-18 at 3 49 03 PM

Reproduction

  1. run examples/todomvc-ssr/todomvc-ssr-server
  2. build examples/todomvc-ssr/todomvc-ssr-client
  3. open demo site
  4. click Completed
  5. then click Active

Screen Shot 2022-10-18 at 3 54 35 PM

Set up some kind of CI pipeline

I'm really ignorant about CI setups so I'd love some help with this.

Various parts of the repo use ordinary cargo test. I also have wasm-bindgen tests set up for some of the examples.

lazy loading and resumability ala qwik

consider adopting ideas from qwik framework.

leverage seralization on the client to enable:

  • lazy loading components - makes the app a lot faster to start
  • resumability between sessions - better user experience

i believe qwik is bringing some inovative ideas into the web app world and since this project is still in early development you can still possibly incorporate them.

SSR benchmarks

I'd love to see some simple benchmarks of server-side rendering performance across different Rust frameworks (Leptos, Sycamore, Yew, Dioxus?) using cargo bench This could be something fairly simple: as long as it involves two or three components, maybe a <For/> component or other relevant keyed list. If it's too simple (like just rendering a simple large static template) it will be very unfair, since Leptos would probably compile it to a single string already.

Consider consolidating the `class:` notation

Through experimentation, I've noticed that using CSS minification tooling that analyzes the source code for classes, such as TailwindCSS, purge CSS, and Atomic fail to recognize classes which start with class-, but do work with classes that start with class: due to notations from JS frameworks, such as Svelte. It might be a good idea to consolidate class names to always use class:, instead of having two seperate notations. Ideally, this should also be extended to on:, but is outside the scope of this issue.

These tools can be made to recognize classes prefixed by class-, but it might not be obvious to users.

Loader API

Loaders should probably be something more like the following. This allows them to do fine-grained reactive reloads only in response to particular params or queries on which they actually depend. Currently, they do a Remix-style “reload whenever query or params change,” which is not great. The main issue here is establishing a stable URL for the create_server_resource (or whatever) so that the loader runs on either client or server, but the server resource runs only on server and can be accessed using a JSON endpoint.

fn contact_data(cx: Scope) -> Resource<String, Contact>{
  let params = use_params_map(cx);
  let id = create_memo(cx, |_| params.get("id"));
  create_server_resource(cx, move || id(), |id: String| fetch_contact_data_for_user(&id))
}

Add `Resource::cancel` so we can abort running futures if we want

There's an on_cleanup function that can be used to run arbitrary code before a scope is disposed, e.g., before a row is dropped in a <For/> component or before a nested route is disposed in the router (because you're navigating away from it).

It would be awesome to have a Resource::cancel() available so you can do things like abort in-flight fetch requests, etc.

I've seen plenty of Futures that have some kind of cancel/abort feature. For example, the oneshot channel in the futures crate returns Result<Option<T>, Canceled>.

Does anyone know there's a common way to indicate a cancellable future? I'm imagining, for example, a Cancellable trait so that we have something like

pub fn create_cancellable_resource<S, T, Fu>(
    cx: Scope,
    source: impl Fn() -> S + 'static,
    fetcher: impl Fn(S) -> Fu + 'static,
) -> Resource<S, T>
where
    S: PartialEq + Debug + Clone + 'static,
    T: Debug + Clone + Serialize + DeserializeOwned + 'static,
    Fu: ***Cancellable*** + Future<Output = T> + 'static,
{
}

I'm realizing as I write this that, because the Resource struct isn't generic over the type of its Future at the moment (only create_resource is, then it stores it as a Pin<Box<dyn Future ...>> or somesuch) this is a little cumbersome.

I guess I could just define my own Cancellable trait for people to implement, but I'd love to have something from the wider Rust ecosystem if it exists.

Forcing all resources to be serializable seems overly restrictive

It seems like resources are currently forced to be serializable to support server side rendering (and potentially resumability in the future). This makes sense, but it excludes some use cases that would otherwise make sense as resources. For example, I was experimenting with accessing a webcam in leptos (using nokhwa). This is an async operation and, reading the docs, it seemed like a resource was a perfect fit. However, a webcam handle isn't serializable so I ended up with this slightly more awkward implementation:

use leptos::*;
use nokhwa::{js_camera::JSCameraConstraintsBuilder, JSCamera};
use std::{cell::RefCell, rc::Rc};


async fn get_camera(set_camera: WriteSignal<Option<Rc<RefCell<JSCamera>>>>) {
    let constraints = JSCameraConstraintsBuilder::new().build();
    let camera = JSCamera::new(constraints).await;

    match camera {
        Ok(camera) => {
            log::info!("Got camera");
            set_camera(Some(Rc::new(RefCell::new(camera))));
        }
        Err(e) => {
            log::error!("Failed to get camera: {}", e);
        }
    }
}

#[component]
pub fn UserWebcam(cx: scope) -> Element {
    let (camera, set_camera) = create_signal::<Option<Rc<RefCell<JSCamera>>>>(cx, None);
    spawn_local(get_camera(set_camera));

    create_effect(cx, move |_| {
        if let Some(camera) = camera.get() {
            if let Err(e) = (*camera).borrow_mut().attach("camera_out", false) {
                log::error!("Failed to attach camera: {}", e);
            } else {
                log::info!("Attached camera");
            }
        }
    });

    view! {cx,
        <video id="camera_out" class="user_webcam"/>
    }
}

It works, but it's not ideal and it can't integrate with functionality like suspense contexts (unless I'm missing something).

It feels like the most natural solution would be to split resources into serializable and non-serializable types. Serializable resources would keep the current behavior but non-serializable ones would be handled fully on the client side regardless of rendering configuration. Happy to take a stab at implementing this if you're open to a PR, but figured I'd open an issue first to at least make sure this functionality doesn't already exist somewhere.

Route actions (i.e., POST)

Currently these are just a stub... I'd like to figure them out so the router is usable for both circumstances, but I want to take some time to make sure the API is right.

Bug: Leptos_DOM Child.rs IntoChild Trait Build Error

Tried to simply build everything with cargo build from root directory:
Screen Shot 2022-10-28 at 11 59 03 AM

It builds by itself:

cd leptos_dom
cargo build

Seems to be the hackernews and todomvc-ssr examples.
Edit: ^ nvm, i just wasn't building hackernews and todomvc-ssr subdirectories individually

Only elements are allowed at the top level of `view! {}` macro

The following code is allowed:

use leptos::*;
use wasm_bindgen::prelude::*;

#[wasm_bindgen(start)]
pub fn start() {
  mount_to_body(view_fn);
}

fn view_fn(cx: Scope) -> impl Mountable {
  let (focus, set_focus) = create_signal(cx, false);

  let focused = move || {
    if focus() {
      view! { cx, <p></p> }
    } else {
      view! { cx, <span /> }
    }
  };

  view! { cx,
    <div>
      <input on:focus=move |_| set_focus(true) on:blur=move |_| set_focus(false) />
      {focused}
    </div>
  }
}

but the following is not:

  view! { cx,
    <input on:focus=move |_| set_focus(true) on:blur=move |_| set_focus(false) />
    {focused}

  }

I do understand why, because the macro expects these items to be Element rather than impl IntoElement, but thought it was worth mentioning in case this was not intentional.

Use `rustversion` crate instead of `stable` flag

We can enable use on either stable or nightly Rust by detecting version with the rustversion crate instead of using the stable flag. This should be fairly simple... only leptos_reactive and leptos_dom need to change at all, and then have the feature removed in the main leptos package.

`Form::from_action`

Implement a helper method on the <Form/> component to derive it automatically from an action, using its (server function) URL as the form's action, updating the action's version when the form submits, and sending errors to the action's error field.

Clone bounds for signals/resources/memos are mostly not necessary

Discussed briefly in #34, but I'm opening a new issue since it's mostly unrelated.

I took a look at the usage of Clone in the signals API and found it could be removed fairly easily. Resources and Memos were slightly less simple:

  • Resource sources still need to be Clone, though the Future's output does not need to be
  • A Resource::with() was added, with similar behavior to Signal::with() to allow access without cloning
  • Memo outputs do not need to be Clone, but it now takes impl FnMut(Option<&T>) -> T instead of impl FnMut(Option<T>) -> T

I have a branch for these changes, but it's built on top of my branch for #35, so I'll open a PR for it once that gets merged.

"Action" on a Form component should be dynamic

Just like the href property on an A component, Form action should take an IntoHref type, so it can update dynamically. This is important for making sure relative routes work if params change, because the form is not rerendered.

Some events not firing

Given the following code:

use leptos::*;
use wasm_bindgen::prelude::*;

#[wasm_bindgen(start)]
pub fn start() {
  mount_to_body(view_fn);
}

fn view_fn(cx: Scope) -> impl Mountable {
  let (focus, set_focus) = create_signal(cx, false);

  let focused = move || {
    if focus() {
      view! { cx, <p></p> }
    } else {
      view! { cx, <span /> }
    }
  };

  view! { cx,
    <div>
      <input on:focus=move |_| set_focus(true) on:blur=move |_| set_focus(false) />
      {focused}
    </div>
  }
}

on:focus and on:blur never fire. on:click does, however.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.