mirror of
https://github.com/adoyle0/thaw.git
synced 2025-02-02 08:34:15 -05:00
feat: support SSR
This commit is contained in:
parent
68659411b9
commit
66791d88f2
13 changed files with 74 additions and 326 deletions
|
@ -23,7 +23,7 @@ pub fn SwitchVersion() -> impl IntoView {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
let version = RwSignal::new(None::<String>);
|
// let version = RwSignal::new(None::<String>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,28 +9,23 @@ crate-type = ["cdylib", "rlib"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
axum = { version = "0.7.4", optional = true }
|
axum = { version = "0.7.4", optional = true }
|
||||||
console_error_panic_hook = "0.1"
|
console_error_panic_hook = "0.1"
|
||||||
console_log = "1"
|
leptos = { version = "0.7.0-beta" }
|
||||||
cfg-if = "1"
|
leptos_axum = { version = "0.7.0-beta", optional = true }
|
||||||
leptos = { version = "0.6.10" }
|
leptos_meta = { version = "0.7.0-beta" }
|
||||||
leptos_axum = { version = "0.6.10", optional = true }
|
leptos_router = { version = "0.7.0-beta" }
|
||||||
leptos_meta = { version = "0.6.10" }
|
tokio = { version = "1", features = ["rt-multi-thread"], optional = true }
|
||||||
leptos_router = { version = "0.6.10" }
|
tower = { version = "0.4", optional = true }
|
||||||
log = "0.4"
|
tower-http = { version = "0.5", features = ["fs"], optional = true }
|
||||||
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 }
|
|
||||||
wasm-bindgen = "=0.2.92"
|
wasm-bindgen = "=0.2.92"
|
||||||
thiserror = "1.0.56"
|
thiserror = "1"
|
||||||
tracing = { version = "0.1.40", optional = true }
|
tracing = { version = "0.1", optional = true }
|
||||||
http = "0.2.8"
|
http = "1"
|
||||||
|
|
||||||
demo = { path = "../../demo", default-features = false }
|
demo = { path = "../../demo", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
hydrate = [
|
hydrate = [
|
||||||
"leptos/hydrate",
|
"leptos/hydrate",
|
||||||
"leptos_meta/hydrate",
|
|
||||||
"leptos_router/hydrate",
|
|
||||||
"demo/hydrate",
|
"demo/hydrate",
|
||||||
]
|
]
|
||||||
ssr = [
|
ssr = [
|
||||||
|
|
74
examples/ssr_axum/end2end/package-lock.json
generated
74
examples/ssr_axum/end2end/package-lock.json
generated
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
|
@ -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!");
|
|
||||||
});
|
|
21
examples/ssr_axum/src/app.rs
Normal file
21
examples/ssr_axum/src/app.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
pub use demo::App;
|
||||||
|
use leptos::prelude::*;
|
||||||
|
use leptos_meta::MetaTags;
|
||||||
|
|
||||||
|
pub fn shell(options: LeptosOptions) -> impl IntoView {
|
||||||
|
view! {
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||||
|
<AutoReload options=options.clone() />
|
||||||
|
<HydrationScripts options/>
|
||||||
|
<MetaTags/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<App/>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<LeptosOptions>,
|
|
||||||
req: Request<Body>,
|
|
||||||
) -> 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! {<App/>});
|
|
||||||
handler(req).await.into_response()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_static_file(uri: Uri, root: &str) -> Result<Response<Body>, (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}"),
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +1,9 @@
|
||||||
#[cfg(feature = "ssr")]
|
pub mod app;
|
||||||
pub mod fileserv;
|
|
||||||
|
|
||||||
#[cfg(feature = "hydrate")]
|
#[cfg(feature = "hydrate")]
|
||||||
#[wasm_bindgen::prelude::wasm_bindgen]
|
#[wasm_bindgen::prelude::wasm_bindgen]
|
||||||
pub fn hydrate() {
|
pub fn hydrate() {
|
||||||
use demo::App;
|
use crate::app::*;
|
||||||
|
|
||||||
// initializes logging using the `log` crate
|
|
||||||
_ = console_log::init_with_level(log::Level::Debug);
|
|
||||||
console_error_panic_hook::set_once();
|
console_error_panic_hook::set_once();
|
||||||
|
leptos::mount::hydrate_body(App);
|
||||||
leptos::mount_to_body(App);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,34 +1,28 @@
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
use axum::{routing::post, Router};
|
use axum::Router;
|
||||||
use demo::App;
|
use leptos::prelude::*;
|
||||||
use leptos::*;
|
|
||||||
use leptos_axum::{generate_route_list, LeptosRoutes};
|
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");
|
let conf = get_configuration(None).unwrap();
|
||||||
|
let addr = conf.leptos_options.site_addr;
|
||||||
// Setting get_configuration(None) means we'll be using cargo-leptos's env values
|
|
||||||
// For deployment these variables are:
|
|
||||||
// <https://github.com/leptos-rs/start-axum#executing-a-server-on-a-remote-machine-without-the-toolchain>
|
|
||||||
// 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 leptos_options = conf.leptos_options;
|
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);
|
let routes = generate_route_list(App);
|
||||||
|
|
||||||
// build our application with a route
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/api/*fn_name", post(leptos_axum::handle_server_fns))
|
.leptos_routes(&leptos_options, routes, {
|
||||||
.leptos_routes(&leptos_options, routes, App)
|
let leptos_options = leptos_options.clone();
|
||||||
.fallback(file_and_error_handler)
|
move || shell(leptos_options.clone())
|
||||||
|
})
|
||||||
|
.fallback(leptos_axum::file_and_error_handler(shell))
|
||||||
.with_state(leptos_options);
|
.with_state(leptos_options);
|
||||||
|
|
||||||
// run our app with hyper
|
// run our app with hyper
|
||||||
// `axum::Server` is a re-export of `hyper::Server`
|
// `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();
|
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
|
||||||
axum::serve(listener, app.into_make_service())
|
axum::serve(listener, app.into_make_service())
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#[cfg(not(feature = "ssr"))]
|
|
||||||
use leptos::prelude::RenderEffect;
|
|
||||||
use leptos::{
|
use leptos::{
|
||||||
prelude::{MaybeProp, Memo, Oco, RwSignal},
|
prelude::{MaybeProp, Memo, Oco, RenderEffect, RwSignal},
|
||||||
reactive_graph::traits::{Get, Update, With, WithUntracked},
|
reactive_graph::traits::{Get, Update, With, WithUntracked},
|
||||||
tachys::renderer::DomRenderer,
|
tachys::renderer::DomRenderer,
|
||||||
};
|
};
|
||||||
|
@ -10,8 +8,11 @@ use std::{collections::HashSet, sync::Arc};
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct ClassList {
|
pub struct ClassList {
|
||||||
value: RwSignal<HashSet<Oco<'static, str>>>,
|
value: RwSignal<HashSet<Oco<'static, str>>>,
|
||||||
|
#[cfg(not(feature = "ssr"))]
|
||||||
effects_oco: Vec<Arc<RenderEffect<Oco<'static, str>>>>,
|
effects_oco: Vec<Arc<RenderEffect<Oco<'static, str>>>>,
|
||||||
|
#[cfg(not(feature = "ssr"))]
|
||||||
effects_option_oco: Vec<Arc<RenderEffect<Option<Oco<'static, str>>>>>,
|
effects_option_oco: Vec<Arc<RenderEffect<Option<Oco<'static, str>>>>>,
|
||||||
|
#[cfg(not(feature = "ssr"))]
|
||||||
effects_bool: Vec<Arc<RenderEffect<bool>>>,
|
effects_bool: Vec<Arc<RenderEffect<bool>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +34,7 @@ impl ClassList {
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
{
|
{
|
||||||
let name = f();
|
let name = f();
|
||||||
self.0.update(|set| {
|
self.value.update(|set| {
|
||||||
set.insert(name);
|
set.insert(name);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -62,7 +63,7 @@ impl ClassList {
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
{
|
{
|
||||||
if let Some(name) = f() {
|
if let Some(name) = f() {
|
||||||
self.0.update(|set| {
|
self.value.update(|set| {
|
||||||
set.insert(name);
|
set.insert(name);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -103,11 +104,11 @@ impl ClassList {
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
{
|
{
|
||||||
let new = f();
|
let new = f();
|
||||||
self.0.update(|set| {
|
if new {
|
||||||
if new {
|
self.value.update(|set| {
|
||||||
set.insert(name);
|
set.insert(name);
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "ssr"))]
|
#[cfg(not(feature = "ssr"))]
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,11 +3,14 @@ use cfg_if::cfg_if;
|
||||||
pub fn mount_style(id: &str, content: &'static str) {
|
pub fn mount_style(id: &str, content: &'static str) {
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature = "ssr")] {
|
if #[cfg(feature = "ssr")] {
|
||||||
use leptos::html::style;
|
use leptos::{tachys::view::Render, view};
|
||||||
use leptos_meta::use_head;
|
use leptos_meta::Style;
|
||||||
let meta = use_head();
|
|
||||||
let style_el = style().attr("data-thaw-id", id).child(content);
|
let _ = view! {
|
||||||
meta.tags.register(format!("leptos-thaw-{id}").into(), style_el.into_any());
|
<Style attr:data-thaw-id=id>
|
||||||
|
{content}
|
||||||
|
</Style>
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
use leptos::prelude::document;
|
use leptos::prelude::document;
|
||||||
let head = document().head().expect("head no exist");
|
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}\"]"))
|
.query_selector(&format!("style[data-thaw-id=\"{id}\"]"))
|
||||||
.expect("query style element error");
|
.expect("query style element error");
|
||||||
|
|
||||||
#[cfg(feature = "hydrate")]
|
|
||||||
let _ = leptos::leptos_dom::HydrationCtx::id();
|
|
||||||
|
|
||||||
if style.is_some() {
|
if style.is_some() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -35,12 +35,14 @@ pub fn mount_style(id: &str, content: &'static str) {
|
||||||
pub fn mount_dynamic_style<T: Fn() -> String + Send + Sync + 'static>(id: String, f: T) {
|
pub fn mount_dynamic_style<T: Fn() -> String + Send + Sync + 'static>(id: String, f: T) {
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature = "ssr")] {
|
if #[cfg(feature = "ssr")] {
|
||||||
use leptos::html::style;
|
use leptos::{tachys::view::Render, view};
|
||||||
use leptos_meta::use_head;
|
use leptos_meta::Style;
|
||||||
let meta = use_head();
|
|
||||||
let content = leptos::untrack(|| f());
|
let _ = view! {
|
||||||
let style_el = style().attr("data-thaw-id", id).child(content);
|
<Style attr:data-thaw-id=id>
|
||||||
meta.tags.register(format!("leptos-thaw-{id}").into(), style_el.into_any());
|
{f()}
|
||||||
|
</Style>
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
use leptos::prelude::document;
|
use leptos::prelude::document;
|
||||||
use send_wrapper::SendWrapper;
|
use send_wrapper::SendWrapper;
|
||||||
|
@ -58,9 +60,6 @@ pub fn mount_dynamic_style<T: Fn() -> String + Send + Sync + 'static>(id: String
|
||||||
style
|
style
|
||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(feature = "hydrate")]
|
|
||||||
let _ = leptos::leptos_dom::HydrationCtx::id();
|
|
||||||
|
|
||||||
let style = SendWrapper::new(style);
|
let style = SendWrapper::new(style);
|
||||||
leptos::prelude::Effect::new_isomorphic(move |_| {
|
leptos::prelude::Effect::new_isomorphic(move |_| {
|
||||||
let content = f();
|
let content = f();
|
||||||
|
|
|
@ -19,15 +19,3 @@ pub use optional_prop::OptionalProp;
|
||||||
pub use signals::*;
|
pub use signals::*;
|
||||||
pub use throttle::throttle;
|
pub use throttle::throttle;
|
||||||
pub use time::now_date;
|
pub use time::now_date;
|
||||||
|
|
||||||
pub fn with_hydration_off<T>(f: impl FnOnce() -> T) -> T {
|
|
||||||
#[cfg(feature = "hydrate")]
|
|
||||||
{
|
|
||||||
use leptos::leptos_dom::HydrationCtx;
|
|
||||||
HydrationCtx::with_hydration_off(f)
|
|
||||||
}
|
|
||||||
#[cfg(not(feature = "hydrate"))]
|
|
||||||
{
|
|
||||||
f()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue