Sorting out all sorts of feature flags etc. so everything will build and test

This commit is contained in:
Greg Johnston 2022-11-02 21:46:47 -04:00
parent 51142ad894
commit db69145fd9
23 changed files with 133 additions and 165 deletions

View file

@ -20,7 +20,6 @@ members = [
"examples/counters",
"examples/counters-stable",
"examples/fetch",
"examples/gtk",
"examples/hackernews/hackernews-app",
"examples/hackernews/hackernews-client",
"examples/hackernews/hackernews-server",
@ -31,11 +30,13 @@ members = [
"examples/todomvc-ssr/todomvc-ssr-server",
]
exclude = [
"benchmarks"
"benchmarks",
# not gonna lie, this is because my arm64 mac fails when linking a GTK binary
"examples/gtk",
]
[profile.release]
codegen-units = 1
lto = true
opt-level = 'z'
opt-level = 'z'

View file

@ -6,12 +6,14 @@ edition = "2021"
[dependencies]
anyhow = "1"
console_log = "0.2"
leptos = { path = "../../../leptos", default-features = false, features = ["serde"] }
leptos = { path = "../../../leptos", default-features = false, features = [
"serde",
] }
leptos_meta = { path = "../../../meta", default-features = false }
leptos_router = { path = "../../../router", default-features = false }
log = "0.4"
gloo-net = { version = "0.2", features = ["http"] }
reqwest = { version = "0.11", features = ["json"], optional = true }
reqwest = { version = "0.11", features = ["json"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
console_error_panic_hook = "0.1.7"
@ -21,4 +23,4 @@ console_error_panic_hook = "0.1.7"
default = ["csr"]
csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr"]
hydrate = ["leptos/hydrate", "leptos_meta/hydrate", "leptos_router/hydrate"]
ssr = ["leptos/ssr", "leptos_meta/ssr", "leptos_router/ssr", "dep:reqwest"]
ssr = ["leptos/ssr", "leptos_meta/ssr", "leptos_router/ssr"]

View file

@ -123,15 +123,3 @@ pub use leptos_server;
pub use leptos_server::*;
pub use leptos_reactive::debug_warn;
#[cfg(not(any(feature = "csr", feature = "ssr", feature = "hydrate")))]
compile_error!("set one of the following feature flags: 'csr', 'ssr' or 'hydrate'");
#[cfg(all(feature = "csr", feature = "ssr"))]
compile_error!("leptos features 'csr' and feature 'ssr' cannot be enabled at the same time");
#[cfg(all(feature = "csr", feature = "hydrate"))]
compile_error!("leptos features 'csr' and feature 'hydrate' cannot be enabled at the same time");
#[cfg(all(feature = "hydrate", feature = "ssr"))]
compile_error!("leptos features 'hydrate' and feature 'ssr' cannot be enabled at the same time");

View file

@ -1,15 +1,9 @@
#[cfg(any(feature = "csr", feature = "hydrate", feature = "ssr"))]
mod for_component;
#[cfg(any(feature = "csr", feature = "hydrate", feature = "ssr"))]
mod map;
#[cfg(any(feature = "csr", feature = "hydrate", feature = "ssr"))]
mod suspense;
#[cfg(any(feature = "csr", feature = "hydrate", feature = "ssr"))]
pub use for_component::*;
#[cfg(any(feature = "csr", feature = "hydrate", feature = "ssr"))]
pub use map::*;
#[cfg(any(feature = "csr", feature = "hydrate", feature = "ssr"))]
pub use suspense::*;
pub trait Prop {

View file

@ -15,7 +15,6 @@ where
}
#[allow(non_snake_case)]
#[cfg(any(feature = "csr", feature = "hydrate", feature = "ssr"))]
pub fn Suspense<F, E, G>(cx: Scope, props: SuspenseProps<F, E, G>) -> impl Fn() -> Child
where
F: IntoChild + Clone,
@ -32,17 +31,7 @@ where
render_suspense(cx, context, props.fallback.clone(), child)
}
#[cfg(not(any(feature = "csr", feature = "hydrate", feature = "ssr")))]
pub fn Suspense<F, E, G>(cx: Scope, props: SuspenseProps<F, E, G>) -> impl Fn() -> Child
where
F: IntoChild + Clone,
E: IntoChild,
G: Fn() -> E + 'static,
{
compile_error!("<Suspense/> can only be used when one of the following features is set on the `leptos` package: 'csr', 'ssr', or 'hydrate'");
}
#[cfg(not(feature = "ssr"))]
#[cfg(any(feature = "csr", feature = "hydrate"))]
fn render_suspense<'a, F, E, G>(
cx: Scope,
context: SuspenseContext,
@ -69,7 +58,7 @@ where
}
}
#[cfg(feature = "ssr")]
#[cfg(not(any(feature = "csr", feature = "hydrate")))]
fn render_suspense<'a, F, E, G>(
cx: Scope,
context: SuspenseContext,

View file

@ -177,19 +177,19 @@ cfg_if! {
if #[cfg(feature = "stable")] {
use leptos_reactive::{Memo, ReadSignal, RwSignal};
impl IntoChild for Memo<Vec<Element>> {
impl IntoChild for Memo<Vec<crate::Element>> {
fn into_child(self, cx: Scope) -> Child {
(move || self.get()).into_child(cx)
}
}
impl IntoChild for ReadSignal<Vec<Element>> {
impl IntoChild for ReadSignal<Vec<crate::Element>> {
fn into_child(self, cx: Scope) -> Child {
(move || self.get()).into_child(cx)
}
}
impl IntoChild for RwSignal<Vec<Element>> {
impl IntoChild for RwSignal<Vec<crate::Element>> {
fn into_child(self, cx: Scope) -> Child {
(move || self.get()).into_child(cx)
}

View file

@ -5,6 +5,7 @@ pub mod child;
pub mod class;
pub mod event_delegation;
pub mod logging;
pub mod mount;
pub mod operations;
pub mod property;
@ -21,11 +22,9 @@ cfg_if! {
pub type Element = web_sys::Element;
pub type Node = web_sys::Node;
pub mod mount;
pub mod reconcile;
pub mod render;
pub use mount::*;
pub use reconcile::*;
pub use render::*;
}
@ -35,6 +34,7 @@ pub use attribute::*;
pub use child::*;
pub use class::*;
pub use logging::*;
pub use mount::*;
pub use operations::*;
pub use property::*;

View file

@ -1,4 +1,5 @@
use crate::{document, Element};
use cfg_if::cfg_if;
use leptos_reactive::Scope;
use wasm_bindgen::UnwrapThrowExt;
@ -8,14 +9,22 @@ pub trait Mountable {
impl Mountable for Element {
fn mount(&self, parent: &web_sys::Element) {
parent.append_child(self).unwrap_throw();
cfg_if! {
if #[cfg(any(feature = "csr", feature = "hydrate"))] {
parent.append_child(self).unwrap_throw();
}
}
}
}
impl Mountable for Vec<Element> {
fn mount(&self, parent: &web_sys::Element) {
for element in self {
parent.append_child(element).unwrap_throw();
cfg_if! {
if #[cfg(any(feature = "csr", feature = "hydrate"))] {
for element in self {
parent.append_child(element).unwrap_throw();
}
}
}
}
}

View file

@ -84,7 +84,6 @@ impl SharedContext {
}
}
#[cfg(feature = "ssr")]
pub fn current_fragment_key(&self) -> String {
if let Some(context) = &self.context {
format!("{}{}f", context.id, context.count)

View file

@ -561,7 +561,6 @@ where
});
}
#[cfg(feature = "ssr")]
pub fn resource_to_serialization_resolver(
&self,
id: ResourceId,
@ -585,7 +584,6 @@ pub(crate) enum AnyResource {
pub(crate) trait SerializableResource {
fn as_any(&self) -> &dyn Any;
#[cfg(feature = "ssr")]
fn to_serialization_resolver(
&self,
id: ResourceId,
@ -601,7 +599,6 @@ where
self
}
#[cfg(feature = "ssr")]
fn to_serialization_resolver(
&self,
id: ResourceId,

View file

@ -3,25 +3,20 @@ use crate::{
EffectId, Memo, ReadSignal, ResourceId, ResourceState, RwSignal, Scope, ScopeDisposer, ScopeId,
ScopeProperty, SignalId, WriteSignal,
};
use cfg_if::cfg_if;
use futures::stream::FuturesUnordered;
use slotmap::{SecondaryMap, SlotMap, SparseSecondaryMap};
use std::{
any::{Any, TypeId},
cell::{Cell, RefCell},
collections::{HashMap, HashSet},
fmt::Debug,
future::Future,
marker::PhantomData,
pin::Pin,
rc::Rc,
};
cfg_if! {
if #[cfg(feature = "ssr")] {
use std::{future::Future, pin::Pin};
use futures::stream::FuturesUnordered;
pub(crate) type PinnedFuture<T> = Pin<Box<dyn Future<Output = T>>>;
}
}
pub(crate) type PinnedFuture<T> = Pin<Box<dyn Future<Output = T>>>;
#[derive(Default)]
pub(crate) struct Runtime {
@ -255,7 +250,6 @@ impl Runtime {
.collect()
}
#[cfg(feature = "ssr")]
pub(crate) fn serialization_resolvers(
&self,
) -> FuturesUnordered<PinnedFuture<(ResourceId, String)>> {

View file

@ -1,15 +1,11 @@
use cfg_if::cfg_if;
use crate::{hydration::SharedContext, EffectId, ResourceId, Runtime, SignalId};
use crate::{PinnedFuture, SuspenseContext};
use futures::stream::FuturesUnordered;
use std::collections::HashMap;
use std::fmt::Debug;
cfg_if! {
if #[cfg(feature = "ssr")] {
use crate::{PinnedFuture, SuspenseContext};
use futures::stream::FuturesUnordered;
use std::{collections::HashMap, future::Future, pin::Pin};
}
}
use std::{future::Future, pin::Pin};
#[must_use = "Scope will leak memory if the disposer function is never called"]
/// Creates a child reactive scope and runs the function within it. This is useful for applications
@ -333,58 +329,54 @@ impl Scope {
self.runtime.all_resources()
}
cfg_if! {
if #[cfg(feature = "ssr")] {
/// Returns IDs for all [Resource](crate::Resource)s found on any scope.
pub fn serialization_resolvers(&self) -> FuturesUnordered<PinnedFuture<(ResourceId, String)>> {
self.runtime.serialization_resolvers()
}
pub fn current_fragment_key(&self) -> String {
self.runtime
.shared_context
.borrow()
.as_ref()
.map(|context| context.current_fragment_key())
.unwrap_or_else(|| String::from("0f"))
}
pub fn current_fragment_key(&self) -> String {
self.runtime
.shared_context
.borrow()
.as_ref()
.map(|context| context.current_fragment_key())
.unwrap_or_else(|| String::from("0f"))
}
/// Returns IDs for all [Resource](crate::Resource)s found on any scope.
pub fn serialization_resolvers(&self) -> FuturesUnordered<PinnedFuture<(ResourceId, String)>> {
self.runtime.serialization_resolvers()
}
pub fn register_suspense(
&self,
context: SuspenseContext,
key: &str,
resolver: impl FnOnce() -> String + 'static,
) {
use crate::create_isomorphic_effect;
use futures::StreamExt;
pub fn register_suspense(
&self,
context: SuspenseContext,
key: &str,
resolver: impl FnOnce() -> String + 'static,
) {
use crate::create_isomorphic_effect;
use futures::StreamExt;
if let Some(ref mut shared_context) = *self.runtime.shared_context.borrow_mut() {
let (mut tx, mut rx) = futures::channel::mpsc::channel::<()>(1);
if let Some(ref mut shared_context) = *self.runtime.shared_context.borrow_mut() {
let (mut tx, mut rx) = futures::channel::mpsc::channel::<()>(1);
create_isomorphic_effect(*self, move |_| {
let pending = context.pending_resources.try_with(|n| *n).unwrap_or(0);
if pending == 0 {
_ = tx.try_send(());
}
});
shared_context.pending_fragments.insert(
key.to_string(),
Box::pin(async move {
rx.next().await;
resolver()
}),
);
create_isomorphic_effect(*self, move |_| {
let pending = context.pending_resources.try_with(|n| *n).unwrap_or(0);
if pending == 0 {
_ = tx.try_send(());
}
}
});
pub fn pending_fragments(&self) -> HashMap<String, Pin<Box<dyn Future<Output = String>>>> {
if let Some(ref mut shared_context) = *self.runtime.shared_context.borrow_mut() {
std::mem::take(&mut shared_context.pending_fragments)
} else {
HashMap::new()
}
}
shared_context.pending_fragments.insert(
key.to_string(),
Box::pin(async move {
rx.next().await;
resolver()
}),
);
}
}
pub fn pending_fragments(&self) -> HashMap<String, Pin<Box<dyn Future<Output = String>>>> {
if let Some(ref mut shared_context) = *self.runtime.shared_context.borrow_mut() {
std::mem::take(&mut shared_context.pending_fragments)
} else {
HashMap::new()
}
}
}

View file

@ -7,14 +7,14 @@ edition = "2021"
leptos_dom = { path = "../leptos_dom", default-features = false, version = "0.0.11" }
leptos_reactive = { path = "../leptos_reactive", default-features = false, version = "0.0.11" }
form_urlencoded = "1"
gloo-net = { version = "0.2", optional = true }
gloo-net = "0.2"
lazy_static = "1"
linear-map = "1"
serde = { version = "1", features = ["derive"] }
thiserror = "1"
[features]
csr = ["leptos_dom/csr", "leptos_reactive/csr", "dep:gloo-net"]
hydrate = ["leptos_dom/hydrate", "leptos_reactive/hydrate", "dep:gloo-net"]
csr = ["leptos_dom/csr", "leptos_reactive/csr"]
hydrate = ["leptos_dom/hydrate", "leptos_reactive/hydrate"]
ssr = ["leptos_dom/ssr", "leptos_reactive/ssr"]
stable = ["leptos_dom/stable", "leptos_reactive/stable"]

View file

@ -69,7 +69,7 @@
pub use form_urlencoded;
use leptos_reactive::*;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde::{Deserialize, Serialize};
use std::{future::Future, pin::Pin, rc::Rc};
use thiserror::Error;
@ -174,7 +174,7 @@ pub enum ServerFnError {
MissingArg(String),
}
#[cfg(any(feature = "csr", feature = "hydrate"))]
#[cfg(not(feature = "ssr"))]
pub async fn call_server_fn<T>(url: &str, args: impl ServerFn) -> Result<T, ServerFnError>
where
T: Serializable + Sized,

View file

@ -9,6 +9,7 @@ description = "Router for the Leptos web framework."
[dependencies]
leptos = { path = "../leptos", version = "0.0", default-features = false }
cfg-if = "1"
common_macros = "0.1"
gloo-net = "0.2"
itertools = "0.10"
@ -21,9 +22,9 @@ url = { version = "2", optional = true }
urlencoding = "2"
thiserror = "1"
typed-builder = "0.10"
js-sys = { version = "0.3", optional = true }
wasm-bindgen = { version = "0.2", optional = true }
wasm-bindgen-futures = { version = "0.4", optional = true }
js-sys = { version = "0.3" }
wasm-bindgen = { version = "0.2" }
wasm-bindgen-futures = { version = "0.4" }
[dependencies.web-sys]
version = "0.3"
@ -51,12 +52,7 @@ features = [
]
[features]
default = ["csr"]
csr = ["leptos/csr", "dep:js-sys", "dep:wasm-bindgen"]
hydrate = [
"leptos/hydrate",
"dep:js-sys",
"dep:wasm-bindgen",
"dep:wasm-bindgen-futures",
]
default = []
csr = ["leptos/csr"]
hydrate = ["leptos/hydrate"]
ssr = ["leptos/ssr", "dep:url", "dep:regex"]

View file

@ -1,3 +1,4 @@
use cfg_if::cfg_if;
use leptos::leptos_dom::IntoChild;
use leptos::*;
use typed_builder::TypedBuilder;
@ -89,14 +90,27 @@ where
}
let child = children.remove(0);
view! { cx,
<a
href=move || href().unwrap_or_default()
prop:state={props.state.map(|s| s.to_js_value())}
prop:replace={props.replace}
aria-current=move || if is_active() { Some("page") } else { None }
>
{child}
</a>
cfg_if! {
if #[cfg(any(feature = "csr", feature = "hydrate"))] {
view! { cx,
<a
href=move || href().unwrap_or_default()
prop:state={props.state.map(|s| s.to_js_value())}
prop:replace={props.replace}
aria-current=move || if is_active() { Some("page") } else { None }
>
{child}
</a>
}
} else {
view! { cx,
<a
href=move || href().unwrap_or_default()
aria-current=move || if is_active() { Some("page") } else { None }
>
{child}
</a>
}
}
}
}

View file

@ -1,3 +1,4 @@
use cfg_if::cfg_if;
use std::ops::IndexMut;
use std::{cell::RefCell, rc::Rc};
@ -72,11 +73,14 @@ impl std::fmt::Debug for RouterContextInner {
impl RouterContext {
pub fn new(cx: Scope, base: Option<&'static str>, fallback: Option<fn() -> Element>) -> Self {
#[cfg(any(feature = "csr", feature = "hydrate"))]
let history = use_context::<RouterIntegrationContext>(cx)
.unwrap_or_else(|| RouterIntegrationContext(Rc::new(crate::BrowserIntegration {})));
#[cfg(not(any(feature = "csr", feature = "hydrate")))]
let history = use_context::<RouterIntegrationContext>(cx).expect("You must call provide_context::<RouterIntegrationContext>(cx, ...) somewhere above the <Router/>.");
cfg_if! {
if #[cfg(any(feature = "csr", feature = "hydrate"))] {
let history = use_context::<RouterIntegrationContext>(cx)
.unwrap_or_else(|| RouterIntegrationContext(Rc::new(crate::BrowserIntegration {})));
} else {
let history = use_context::<RouterIntegrationContext>(cx).expect("You must call provide_context::<RouterIntegrationContext>(cx, ...) somewhere above the <Router/>.");
}
};
// Any `History` type gives a way to get a reactive signal of the current location
// in the browser context, this is drawn from the `popstate` event
@ -143,7 +147,7 @@ impl RouterContext {
});
// handle all click events on anchor tags
#[cfg(any(feature = "csr", feature = "hydrate"))]
#[cfg(not(feature = "ssr"))]
leptos_dom::window_event_listener("click", {
let inner = Rc::clone(&inner);
move |ev| inner.clone().handle_anchor_click(ev)
@ -253,7 +257,7 @@ impl RouterContextInner {
}
}
#[cfg(any(feature = "csr", feature = "hydrate"))]
#[cfg(not(feature = "ssr"))]
pub(crate) fn handle_anchor_click(self: Rc<Self>, ev: web_sys::Event) {
let ev = ev.unchecked_into::<web_sys::MouseEvent>();
if ev.default_prevented()

View file

@ -184,7 +184,7 @@ impl std::fmt::Debug for Loader {
}
}
#[cfg(feature = "ssr")]
#[cfg(all(feature = "ssr", not(feature = "hydrate")))]
pub async fn loader_to_json(view: impl Fn(Scope) -> String + 'static) -> Option<String> {
let (data, _, disposer) = run_scope_undisposed(move |cx| async move {
let _shell = view(cx);

View file

@ -24,11 +24,9 @@ pub trait History {
fn navigate(&self, loc: &LocationChange);
}
#[cfg(any(feature = "csr", feature = "hydrate"))]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct BrowserIntegration {}
#[cfg(any(feature = "csr", feature = "hydrate"))]
impl BrowserIntegration {
fn current() -> LocationChange {
let loc = leptos_dom::location();
@ -43,7 +41,6 @@ impl BrowserIntegration {
}
}
#[cfg(any(feature = "csr", feature = "hydrate"))]
impl History for BrowserIntegration {
fn location(&self, cx: Scope) -> ReadSignal<LocationChange> {
use crate::{NavigateOptions, RouterContext};

View file

@ -1,16 +1,9 @@
#[cfg(not(feature = "ssr"))]
use leptos::wasm_bindgen::JsValue;
#[derive(Debug, Clone, Default, PartialEq)]
#[cfg(not(feature = "ssr"))]
pub struct State(pub Option<JsValue>);
#[derive(Debug, Clone, Default, PartialEq)]
#[cfg(feature = "ssr")]
pub struct State(pub Option<()>);
impl State {
#[cfg(not(feature = "ssr"))]
pub fn to_js_value(&self) -> JsValue {
match &self.0 {
Some(v) => v.clone(),
@ -19,7 +12,6 @@ impl State {
}
}
#[cfg(not(feature = "ssr"))]
impl<T> From<T> for State
where
T: Into<JsValue>,

View file

@ -36,7 +36,7 @@ pub fn unescape(s: &str) -> String {
.replace('+', " ")
}
#[cfg(any(feature = "csr", feature = "hydrate"))]
#[cfg(not(feature = "ssr"))]
pub fn unescape(s: &str) -> String {
js_sys::decode_uri(s).unwrap().into()
}
@ -46,12 +46,12 @@ pub fn escape(s: &str) -> String {
urlencoding::encode(s).into()
}
#[cfg(any(feature = "csr", feature = "hydrate"))]
#[cfg(not(feature = "ssr"))]
pub fn escape(s: &str) -> String {
js_sys::encode_uri(s).as_string().unwrap()
}
#[cfg(any(feature = "csr", feature = "hydrate"))]
#[cfg(not(feature = "ssr"))]
impl TryFrom<&str> for Url {
type Error = String;

View file

@ -1,7 +1,7 @@
use std::borrow::Cow;
#[doc(hidden)]
#[cfg(any(feature = "csr", feature = "hydrate"))]
#[cfg(not(feature = "ssr"))]
pub fn expand_optionals(pattern: &str) -> Vec<Cow<str>> {
use wasm_bindgen::JsValue;

View file

@ -44,7 +44,7 @@ fn has_scheme(path: &str) -> bool {
HAS_SCHEME_RE.is_match(path)
}
#[cfg(any(feature = "csr", feature = "hydrate"))]
#[cfg(not(feature = "ssr"))]
fn has_scheme(path: &str) -> bool {
let re = js_sys::RegExp::new(HAS_SCHEME, "");
re.test(path)
@ -75,7 +75,7 @@ const BEGINS_WITH_QUERY_OR_HASH: &str = r#"^[?#]"#;
const HAS_SCHEME: &str = r#"^(?:[a-z0-9]+:)?//"#;
const QUERY: &str = r#"/*(\*.*)?$"#;
#[cfg(any(feature = "csr", feature = "hydrate"))]
#[cfg(not(feature = "ssr"))]
fn replace_trim_path<'a>(text: &'a str, replace: &str) -> Cow<'a, str> {
let re = js_sys::RegExp::new(TRIM_PATH, "g");
js_sys::JsString::from(text)
@ -85,13 +85,13 @@ fn replace_trim_path<'a>(text: &'a str, replace: &str) -> Cow<'a, str> {
.into()
}
#[cfg(any(feature = "csr", feature = "hydrate"))]
#[cfg(not(feature = "ssr"))]
fn begins_with_query_or_hash(text: &str) -> bool {
let re = js_sys::RegExp::new(BEGINS_WITH_QUERY_OR_HASH, "");
re.test(text)
}
#[cfg(any(feature = "csr", feature = "hydrate"))]
#[cfg(not(feature = "ssr"))]
fn replace_query(text: &str) -> String {
let re = js_sys::RegExp::new(QUERY, "g");
js_sys::JsString::from(text)