Thanks for your interesting in contributing to Leptos! This is a truly community-driven framework, and while we have a central maintainer (@gbj) large parts of the renderer, reactive system, and server integrations have all been written by other contributors. Contributions are always welcome.
Participation in this community is governed by a Code of Conduct. Some of the most active conversations around development take place on our Discord server.
This guide seeks to
- describe some of the framework’s values (in a technical, not an ethical, sense)
- provide a high-level overview of how the pieces of the framework fit together
- orient you to the organization of this repository
Leptos, as a framework, reflects certain technical values:
- Expose primitives rather than imposing patterns. Provide building blocks that users can combine together to build up more complex behavior, rather than requiring users follow certain templates, file formats, etc. e.g., components are defined as functions, rather than a bespoke single-file component format. The reactive system feeds into the rendering system, rather than being defined by it.
- Bottom-up over top-down. If you envision a user’s application as a tree (like an HTML document), push meaning toward the leaves of the tree. e.g., If data needs to be loaded, load it in a granular primitive (resources) rather than a route- or page-level data structure.
- Performance by default. When possible, users should only pay for what they use. e.g., we don’t make all component props reactive by default. This is because doing so would force the overhead of a reactive prop onto props that don’t need to be reactive.
- Full-stack performance. Performance can’t be limited to a single metric, whether that’s a DOM rendering benchmark, WASM binary size, or server response time. Use methods like HTTP streaming and progressive enhancement to enable applications to load, become interactive, and respond as quickly as possible.
- Use safe Rust. There’s no need for
unsafe
Rust in the framework, and avoiding it at all costs reduces the maintenance and testing burden significantly. - Embrace Rust semantics. Especially in things like UI templating, use Rust
semantics or extend them in a predictable way with control-flow components
rather than overloading the meaning of Rust terms like
if
orfor
in a framework-specific way. - Enhance ergonomics without obfuscating what’s happening. This is by far the hardest to achieve. It’s often the case that adding additional layers to improve DX (like a custom build tool and starter templates) comes across as “too magic” to some people who haven’t had to build the same things manually. When possible, make it easier to see how the pieces fit together, without sacrificing the improved DX.
We do not have PR templates or formal processes for approving PRs. But there are a few guidelines that will make it a better experience for everyone:
- Run
cargo fmt
before submitting your code. - Keep PRs limited to addressing one feature or one issue, in general. In some cases (e.g., “reduce allocations in the reactive system”) this may touch a number of different areas, but is still conceptually one thing.
- If it’s an unsolicited PR not linked to an open issue, please include a specific explanation for what it’s trying to achieve. For example: “When I was trying to deploy my app under circumstances X, I found that the way function Z was implemented caused issue Z. This PR should fix that by solution.”
- Our CI tests every PR against all the existing examples, sometimes requiring
compilation for both server and client side, etc. It’s thorough but slow. If
you want to run CI locally to reduce frustration, you can do that by installing
cargo-make
and usingcargo make check && cargo make test && cargo make check-examples
.
We have a fairly extensive CI setup that runs both lints (like rustfmt
and clippy
)
and tests on PRs. You can run most of these locally if you have cargo-make
installed.
If you added an example, make sure to add it to the list in examples/Makefile.toml
.
From the root directory of the repo, run
cargo +nightly fmt
cargo +nightly make check
cargo +nightly make test
cargo +nightly make check-examples
cargo +nightly make --profile=github-actions ci
If you modified an example:
cd examples/your_example
cargo +nightly fmt -- --config-path ../..
cargo +nightly make --profile=github-actions verify-flow
See ARCHITECTURE.md.