diff --git a/demo/src/components/switch_version.rs b/demo/src/components/switch_version.rs index b4c31bd..3b8c6c2 100644 --- a/demo/src/components/switch_version.rs +++ b/demo/src/components/switch_version.rs @@ -23,7 +23,7 @@ pub fn SwitchVersion() -> impl IntoView { } }); } else { - let version = RwSignal::new(None::); + // let version = RwSignal::new(None::); } } diff --git a/examples/ssr_axum/Cargo.toml b/examples/ssr_axum/Cargo.toml index 74f96a0..9e221a4 100644 --- a/examples/ssr_axum/Cargo.toml +++ b/examples/ssr_axum/Cargo.toml @@ -9,28 +9,23 @@ crate-type = ["cdylib", "rlib"] [dependencies] axum = { version = "0.7.4", optional = true } console_error_panic_hook = "0.1" -console_log = "1" -cfg-if = "1" -leptos = { version = "0.6.10" } -leptos_axum = { version = "0.6.10", optional = true } -leptos_meta = { version = "0.6.10" } -leptos_router = { version = "0.6.10" } -log = "0.4" -simple_logger = "4" -tokio = { version = "1.35.1", features = ["rt-multi-thread"], optional = true } -tower = { version = "0.4.13", optional = true } -tower-http = { version = "0.5.1", features = ["fs"], optional = true } +leptos = { version = "0.7.0-beta" } +leptos_axum = { version = "0.7.0-beta", optional = true } +leptos_meta = { version = "0.7.0-beta" } +leptos_router = { version = "0.7.0-beta" } +tokio = { version = "1", features = ["rt-multi-thread"], optional = true } +tower = { version = "0.4", optional = true } +tower-http = { version = "0.5", features = ["fs"], optional = true } wasm-bindgen = "=0.2.92" -thiserror = "1.0.56" -tracing = { version = "0.1.40", optional = true } -http = "0.2.8" +thiserror = "1" +tracing = { version = "0.1", optional = true } +http = "1" + demo = { path = "../../demo", default-features = false } [features] hydrate = [ "leptos/hydrate", - "leptos_meta/hydrate", - "leptos_router/hydrate", "demo/hydrate", ] ssr = [ diff --git a/examples/ssr_axum/end2end/package-lock.json b/examples/ssr_axum/end2end/package-lock.json deleted file mode 100644 index f12af44..0000000 --- a/examples/ssr_axum/end2end/package-lock.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "name": "end2end", - "version": "1.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "end2end", - "version": "1.0.0", - "license": "ISC", - "devDependencies": { - "@playwright/test": "^1.28.0" - } - }, - "node_modules/@playwright/test": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.28.0.tgz", - "integrity": "sha512-vrHs5DFTPwYox5SGKq/7TDn/S4q6RA1zArd7uhO6EyP9hj3XgZBBM12ktMbnDQNxh/fL1IUKsTNLxihmsU38lQ==", - "dev": true, - "dependencies": { - "@types/node": "*", - "playwright-core": "1.28.0" - }, - "bin": { - "playwright": "cli.js" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@types/node": { - "version": "18.11.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", - "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", - "dev": true - }, - "node_modules/playwright-core": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.28.0.tgz", - "integrity": "sha512-nJLknd28kPBiCNTbqpu6Wmkrh63OEqJSFw9xOfL9qxfNwody7h6/L3O2dZoWQ6Oxcm0VOHjWmGiCUGkc0X3VZA==", - "dev": true, - "bin": { - "playwright": "cli.js" - }, - "engines": { - "node": ">=14" - } - } - }, - "dependencies": { - "@playwright/test": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.28.0.tgz", - "integrity": "sha512-vrHs5DFTPwYox5SGKq/7TDn/S4q6RA1zArd7uhO6EyP9hj3XgZBBM12ktMbnDQNxh/fL1IUKsTNLxihmsU38lQ==", - "dev": true, - "requires": { - "@types/node": "*", - "playwright-core": "1.28.0" - } - }, - "@types/node": { - "version": "18.11.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", - "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", - "dev": true - }, - "playwright-core": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.28.0.tgz", - "integrity": "sha512-nJLknd28kPBiCNTbqpu6Wmkrh63OEqJSFw9xOfL9qxfNwody7h6/L3O2dZoWQ6Oxcm0VOHjWmGiCUGkc0X3VZA==", - "dev": true - } - } -} diff --git a/examples/ssr_axum/end2end/package.json b/examples/ssr_axum/end2end/package.json deleted file mode 100644 index ed78585..0000000 --- a/examples/ssr_axum/end2end/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "end2end", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": {}, - "keywords": [], - "author": "", - "license": "ISC", - "devDependencies": { - "@playwright/test": "^1.28.0" - } -} diff --git a/examples/ssr_axum/end2end/playwright.config.ts b/examples/ssr_axum/end2end/playwright.config.ts deleted file mode 100644 index e9891c0..0000000 --- a/examples/ssr_axum/end2end/playwright.config.ts +++ /dev/null @@ -1,107 +0,0 @@ -import type { PlaywrightTestConfig } from "@playwright/test"; -import { devices } from "@playwright/test"; - -/** - * Read environment variables from file. - * https://github.com/motdotla/dotenv - */ -// require('dotenv').config(); - -/** - * See https://playwright.dev/docs/test-configuration. - */ -const config: PlaywrightTestConfig = { - testDir: "./tests", - /* Maximum time one test can run for. */ - timeout: 30 * 1000, - expect: { - /** - * Maximum time expect() should wait for the condition to be met. - * For example in `await expect(locator).toHaveText();` - */ - timeout: 5000, - }, - /* Run tests in files in parallel */ - fullyParallel: true, - /* Fail the build on CI if you accidentally left test.only in the source code. */ - forbidOnly: !!process.env.CI, - /* Retry on CI only */ - retries: process.env.CI ? 2 : 0, - /* Opt out of parallel tests on CI. */ - workers: process.env.CI ? 1 : undefined, - /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: "html", - /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ - use: { - /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */ - actionTimeout: 0, - /* Base URL to use in actions like `await page.goto('/')`. */ - // baseURL: 'http://localhost:3000', - - /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: "on-first-retry", - }, - - /* Configure projects for major browsers */ - projects: [ - { - name: "chromium", - use: { - ...devices["Desktop Chrome"], - }, - }, - - { - name: "firefox", - use: { - ...devices["Desktop Firefox"], - }, - }, - - { - name: "webkit", - use: { - ...devices["Desktop Safari"], - }, - }, - - /* Test against mobile viewports. */ - // { - // name: 'Mobile Chrome', - // use: { - // ...devices['Pixel 5'], - // }, - // }, - // { - // name: 'Mobile Safari', - // use: { - // ...devices['iPhone 12'], - // }, - // }, - - /* Test against branded browsers. */ - // { - // name: 'Microsoft Edge', - // use: { - // channel: 'msedge', - // }, - // }, - // { - // name: 'Google Chrome', - // use: { - // channel: 'chrome', - // }, - // }, - ], - - /* Folder for test artifacts such as screenshots, videos, traces, etc. */ - // outputDir: 'test-results/', - - /* Run your local dev server before starting the tests */ - // webServer: { - // command: 'npm run start', - // port: 3000, - // }, -}; - -export default config; diff --git a/examples/ssr_axum/end2end/tests/example.spec.ts b/examples/ssr_axum/end2end/tests/example.spec.ts deleted file mode 100644 index a461f35..0000000 --- a/examples/ssr_axum/end2end/tests/example.spec.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { test, expect } from "@playwright/test"; - -test("homepage has title and links to intro page", async ({ page }) => { - await page.goto("http://localhost:3000/"); - - await expect(page).toHaveTitle("Welcome to Leptos"); - - await expect(page.locator("h1")).toHaveText("Welcome to Leptos!"); -}); diff --git a/examples/ssr_axum/src/app.rs b/examples/ssr_axum/src/app.rs new file mode 100644 index 0000000..d985518 --- /dev/null +++ b/examples/ssr_axum/src/app.rs @@ -0,0 +1,21 @@ +pub use demo::App; +use leptos::prelude::*; +use leptos_meta::MetaTags; + +pub fn shell(options: LeptosOptions) -> impl IntoView { + view! { + + + + + + + + + + + + + + } +} diff --git a/examples/ssr_axum/src/fileserv.rs b/examples/ssr_axum/src/fileserv.rs deleted file mode 100644 index a71b53a..0000000 --- a/examples/ssr_axum/src/fileserv.rs +++ /dev/null @@ -1,42 +0,0 @@ -use axum::{ - body::Body, - extract::State, - http::{Request, Response, StatusCode, Uri}, - response::{IntoResponse, Response as AxumResponse}, -}; -use demo::App; -use leptos::{view, LeptosOptions}; -use tower::ServiceExt; -use tower_http::services::ServeDir; - -pub async fn file_and_error_handler( - uri: Uri, - State(options): State, - req: Request, -) -> AxumResponse { - let root = options.site_root.clone(); - let res = get_static_file(uri.clone(), &root).await.unwrap(); - - if res.status() == StatusCode::OK { - res.into_response() - } else { - let handler = leptos_axum::render_app_to_stream(options.to_owned(), move || view! {}); - handler(req).await.into_response() - } -} - -async fn get_static_file(uri: Uri, root: &str) -> Result, (StatusCode, String)> { - let req = Request::builder() - .uri(uri.clone()) - .body(Body::empty()) - .unwrap(); - // `ServeDir` implements `tower::Service` so we can call it with `tower::ServiceExt::oneshot` - // This path is relative to the cargo root - match ServeDir::new(root).oneshot(req).await { - Ok(res) => Ok(res.into_response()), - Err(err) => Err(( - StatusCode::INTERNAL_SERVER_ERROR, - format!("Something went wrong: {err}"), - )), - } -} diff --git a/examples/ssr_axum/src/lib.rs b/examples/ssr_axum/src/lib.rs index a1249d7..151489d 100644 --- a/examples/ssr_axum/src/lib.rs +++ b/examples/ssr_axum/src/lib.rs @@ -1,14 +1,9 @@ -#[cfg(feature = "ssr")] -pub mod fileserv; +pub mod app; #[cfg(feature = "hydrate")] #[wasm_bindgen::prelude::wasm_bindgen] pub fn hydrate() { - use demo::App; - - // initializes logging using the `log` crate - _ = console_log::init_with_level(log::Level::Debug); + use crate::app::*; console_error_panic_hook::set_once(); - - leptos::mount_to_body(App); + leptos::mount::hydrate_body(App); } diff --git a/examples/ssr_axum/src/main.rs b/examples/ssr_axum/src/main.rs index 3647ee9..0ec0707 100644 --- a/examples/ssr_axum/src/main.rs +++ b/examples/ssr_axum/src/main.rs @@ -1,34 +1,28 @@ #[cfg(feature = "ssr")] #[tokio::main] async fn main() { - use axum::{routing::post, Router}; - use demo::App; - use leptos::*; + use axum::Router; + use leptos::prelude::*; use leptos_axum::{generate_route_list, LeptosRoutes}; - use ssr_axum::fileserv::file_and_error_handler; + use ssr_axum::app::*; - simple_logger::init_with_level(log::Level::Debug).expect("couldn't initialize logging"); - - // Setting get_configuration(None) means we'll be using cargo-leptos's env values - // For deployment these variables are: - // - // Alternately a file can be specified such as Some("Cargo.toml") - // The file would need to be included with the executable when moved to deployment - let conf = get_configuration(None).await.unwrap(); + let conf = get_configuration(None).unwrap(); + let addr = conf.leptos_options.site_addr; let leptos_options = conf.leptos_options; - let addr = leptos_options.site_addr; + // Generate the list of routes in your Leptos App let routes = generate_route_list(App); - // build our application with a route let app = Router::new() - .route("/api/*fn_name", post(leptos_axum::handle_server_fns)) - .leptos_routes(&leptos_options, routes, App) - .fallback(file_and_error_handler) + .leptos_routes(&leptos_options, routes, { + let leptos_options = leptos_options.clone(); + move || shell(leptos_options.clone()) + }) + .fallback(leptos_axum::file_and_error_handler(shell)) .with_state(leptos_options); // run our app with hyper // `axum::Server` is a re-export of `hyper::Server` - log::info!("listening on http://{}", &addr); + log!("listening on http://{}", &addr); let listener = tokio::net::TcpListener::bind(&addr).await.unwrap(); axum::serve(listener, app.into_make_service()) .await diff --git a/thaw_utils/src/class_list.rs b/thaw_utils/src/class_list.rs index 8175e06..b32b492 100644 --- a/thaw_utils/src/class_list.rs +++ b/thaw_utils/src/class_list.rs @@ -1,7 +1,5 @@ -#[cfg(not(feature = "ssr"))] -use leptos::prelude::RenderEffect; use leptos::{ - prelude::{MaybeProp, Memo, Oco, RwSignal}, + prelude::{MaybeProp, Memo, Oco, RenderEffect, RwSignal}, reactive_graph::traits::{Get, Update, With, WithUntracked}, tachys::renderer::DomRenderer, }; @@ -10,8 +8,11 @@ use std::{collections::HashSet, sync::Arc}; #[derive(Clone, Default)] pub struct ClassList { value: RwSignal>>, + #[cfg(not(feature = "ssr"))] effects_oco: Vec>>>, + #[cfg(not(feature = "ssr"))] effects_option_oco: Vec>>>>, + #[cfg(not(feature = "ssr"))] effects_bool: Vec>>, } @@ -33,7 +34,7 @@ impl ClassList { #[cfg(feature = "ssr")] { let name = f(); - self.0.update(|set| { + self.value.update(|set| { set.insert(name); }); } @@ -62,7 +63,7 @@ impl ClassList { #[cfg(feature = "ssr")] { if let Some(name) = f() { - self.0.update(|set| { + self.value.update(|set| { set.insert(name); }); } @@ -103,11 +104,11 @@ impl ClassList { #[cfg(feature = "ssr")] { let new = f(); - self.0.update(|set| { - if new { + if new { + self.value.update(|set| { set.insert(name); - } - }); + }); + } } #[cfg(not(feature = "ssr"))] { diff --git a/thaw_utils/src/dom/mount_style.rs b/thaw_utils/src/dom/mount_style.rs index 4a88735..e6cdb40 100644 --- a/thaw_utils/src/dom/mount_style.rs +++ b/thaw_utils/src/dom/mount_style.rs @@ -3,11 +3,14 @@ use cfg_if::cfg_if; pub fn mount_style(id: &str, content: &'static str) { cfg_if! { if #[cfg(feature = "ssr")] { - use leptos::html::style; - use leptos_meta::use_head; - let meta = use_head(); - let style_el = style().attr("data-thaw-id", id).child(content); - meta.tags.register(format!("leptos-thaw-{id}").into(), style_el.into_any()); + use leptos::{tachys::view::Render, view}; + use leptos_meta::Style; + + let _ = view! { + + }; } else { use leptos::prelude::document; let head = document().head().expect("head no exist"); @@ -15,9 +18,6 @@ pub fn mount_style(id: &str, content: &'static str) { .query_selector(&format!("style[data-thaw-id=\"{id}\"]")) .expect("query style element error"); - #[cfg(feature = "hydrate")] - let _ = leptos::leptos_dom::HydrationCtx::id(); - if style.is_some() { return; } @@ -35,12 +35,14 @@ pub fn mount_style(id: &str, content: &'static str) { pub fn mount_dynamic_style String + Send + Sync + 'static>(id: String, f: T) { cfg_if! { if #[cfg(feature = "ssr")] { - use leptos::html::style; - use leptos_meta::use_head; - let meta = use_head(); - let content = leptos::untrack(|| f()); - let style_el = style().attr("data-thaw-id", id).child(content); - meta.tags.register(format!("leptos-thaw-{id}").into(), style_el.into_any()); + use leptos::{tachys::view::Render, view}; + use leptos_meta::Style; + + let _ = view! { + + }; } else { use leptos::prelude::document; use send_wrapper::SendWrapper; @@ -58,9 +60,6 @@ pub fn mount_dynamic_style String + Send + Sync + 'static>(id: String style }); - #[cfg(feature = "hydrate")] - let _ = leptos::leptos_dom::HydrationCtx::id(); - let style = SendWrapper::new(style); leptos::prelude::Effect::new_isomorphic(move |_| { let content = f(); diff --git a/thaw_utils/src/lib.rs b/thaw_utils/src/lib.rs index e55b712..e02427c 100644 --- a/thaw_utils/src/lib.rs +++ b/thaw_utils/src/lib.rs @@ -19,15 +19,3 @@ pub use optional_prop::OptionalProp; pub use signals::*; pub use throttle::throttle; pub use time::now_date; - -pub fn with_hydration_off(f: impl FnOnce() -> T) -> T { - #[cfg(feature = "hydrate")] - { - use leptos::leptos_dom::HydrationCtx; - HydrationCtx::with_hydration_off(f) - } - #[cfg(not(feature = "hydrate"))] - { - f() - } -}