mirror of
https://github.com/leptos-rs/leptos.git
synced 2025-12-27 07:34:35 -05:00
Merge remote-tracking branch 'origin' into wasm-splitting-support
This commit is contained in:
4
.github/workflows/run-cargo-make-task.yml
vendored
4
.github/workflows/run-cargo-make-task.yml
vendored
@@ -169,7 +169,9 @@ jobs:
|
||||
cd '${{ inputs.directory }}'
|
||||
cargo make --no-workspace --profile=github-actions ci
|
||||
# check the direct-minimal-versions on release
|
||||
if [[ "${{ github.ref_name }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
COMMIT_MSG=$(git log -1 --pretty=format:'%s')
|
||||
# Supports: v1.2.3, v1.2.3-alpha, v1.2.3-beta1, v1.2.3-rc.1, etc.
|
||||
if [[ "$COMMIT_MSG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+(\.?[0-9]+)?)?$ ]]; then
|
||||
cargo make --no-workspace --profile=github-actions check-minimal-versions
|
||||
fi
|
||||
# Check if the counter_isomorphic can be built with leptos_debuginfo cfg flag in release mode
|
||||
|
||||
43
Cargo.lock
generated
43
Cargo.lock
generated
@@ -589,6 +589,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "cfg-expr"
|
||||
version = "0.20.1"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d0390889d58f934f01cd49736275b4c2da15bcfc328c78ff2349907e6cabf22"
|
||||
dependencies = [
|
||||
@@ -1788,7 +1789,7 @@ checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388"
|
||||
|
||||
[[package]]
|
||||
name = "leptos"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
dependencies = [
|
||||
"any_spawner",
|
||||
"base64",
|
||||
@@ -1844,7 +1845,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_actix"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
dependencies = [
|
||||
"actix-files",
|
||||
"actix-http",
|
||||
@@ -1869,7 +1870,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_axum"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
dependencies = [
|
||||
"any_spawner",
|
||||
"axum",
|
||||
@@ -1892,7 +1893,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_config"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
dependencies = [
|
||||
"config",
|
||||
"regex",
|
||||
@@ -1906,7 +1907,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_dom"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"leptos",
|
||||
@@ -1923,7 +1924,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_hot_reload"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"camino",
|
||||
@@ -1939,7 +1940,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_integration_utils"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"hydration_context",
|
||||
@@ -1952,7 +1953,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_macro"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
dependencies = [
|
||||
"attribute-derive",
|
||||
"cfg-if",
|
||||
@@ -1972,7 +1973,7 @@ dependencies = [
|
||||
"rustc_version",
|
||||
"serde",
|
||||
"server_fn",
|
||||
"server_fn_macro 0.8.3",
|
||||
"server_fn_macro 0.8.4",
|
||||
"syn 2.0.104",
|
||||
"tracing",
|
||||
"trybuild",
|
||||
@@ -1982,7 +1983,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_meta"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"indexmap",
|
||||
@@ -1996,7 +1997,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_router"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
dependencies = [
|
||||
"any_spawner",
|
||||
"either_of",
|
||||
@@ -2020,7 +2021,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_router_macro"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
dependencies = [
|
||||
"leptos_macro",
|
||||
"leptos_router",
|
||||
@@ -2032,7 +2033,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_server"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
dependencies = [
|
||||
"any_spawner",
|
||||
"base64",
|
||||
@@ -2745,7 +2746,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "reactive_graph"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
dependencies = [
|
||||
"any_spawner",
|
||||
"async-lock",
|
||||
@@ -2768,7 +2769,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "reactive_stores"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
dependencies = [
|
||||
"any_spawner",
|
||||
"dashmap",
|
||||
@@ -2787,7 +2788,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "reactive_stores_macro"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
dependencies = [
|
||||
"convert_case 0.8.0",
|
||||
"proc-macro-error2",
|
||||
@@ -3281,7 +3282,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "server_fn"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
dependencies = [
|
||||
"actix-web",
|
||||
"actix-ws",
|
||||
@@ -3344,7 +3345,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "server_fn_macro"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
dependencies = [
|
||||
"const_format",
|
||||
"convert_case 0.8.0",
|
||||
@@ -3357,9 +3358,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "server_fn_macro_default"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
dependencies = [
|
||||
"server_fn_macro 0.8.3",
|
||||
"server_fn_macro 0.8.4",
|
||||
"syn 2.0.104",
|
||||
]
|
||||
|
||||
@@ -3561,7 +3562,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tachys"
|
||||
version = "0.2.4"
|
||||
version = "0.2.5"
|
||||
dependencies = [
|
||||
"any_spawner",
|
||||
"async-trait",
|
||||
|
||||
46
Cargo.toml
46
Cargo.toml
@@ -40,7 +40,7 @@ members = [
|
||||
exclude = ["benchmarks", "examples", "projects"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
edition = "2021"
|
||||
rust-version = "1.88"
|
||||
|
||||
@@ -51,26 +51,26 @@ any_spawner = { path = "./any_spawner/", version = "0.3.0" }
|
||||
const_str_slice_concat = { path = "./const_str_slice_concat", version = "0.1" }
|
||||
either_of = { path = "./either_of/", version = "0.1.6" }
|
||||
hydration_context = { path = "./hydration_context", version = "0.3.0" }
|
||||
leptos = { path = "./leptos", version = "0.8.3" }
|
||||
leptos_config = { path = "./leptos_config", version = "0.8.3" }
|
||||
leptos_dom = { path = "./leptos_dom", version = "0.8.3" }
|
||||
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.8.3" }
|
||||
leptos_integration_utils = { path = "./integrations/utils", version = "0.8.3" }
|
||||
leptos_macro = { path = "./leptos_macro", version = "0.8.3" }
|
||||
leptos_router = { path = "./router", version = "0.8.3" }
|
||||
leptos_router_macro = { path = "./router_macro", version = "0.8.3" }
|
||||
leptos_server = { path = "./leptos_server", version = "0.8.3" }
|
||||
leptos_meta = { path = "./meta", version = "0.8.3" }
|
||||
leptos = { path = "./leptos", version = "0.8.4" }
|
||||
leptos_config = { path = "./leptos_config", version = "0.8.4" }
|
||||
leptos_dom = { path = "./leptos_dom", version = "0.8.4" }
|
||||
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.8.4" }
|
||||
leptos_integration_utils = { path = "./integrations/utils", version = "0.8.4" }
|
||||
leptos_macro = { path = "./leptos_macro", version = "0.8.4" }
|
||||
leptos_router = { path = "./router", version = "0.8.4" }
|
||||
leptos_router_macro = { path = "./router_macro", version = "0.8.4" }
|
||||
leptos_server = { path = "./leptos_server", version = "0.8.4" }
|
||||
leptos_meta = { path = "./meta", version = "0.8.4" }
|
||||
next_tuple = { path = "./next_tuple", version = "0.1.0" }
|
||||
oco_ref = { path = "./oco", version = "0.2.0" }
|
||||
or_poisoned = { path = "./or_poisoned", version = "0.1.0" }
|
||||
reactive_graph = { path = "./reactive_graph", version = "0.2.3" }
|
||||
reactive_stores = { path = "./reactive_stores", version = "0.2.3" }
|
||||
reactive_stores_macro = { path = "./reactive_stores_macro", version = "0.2.3" }
|
||||
server_fn = { path = "./server_fn", version = "0.8.3" }
|
||||
server_fn_macro = { path = "./server_fn_macro", version = "0.8.3" }
|
||||
server_fn_macro_default = { path = "./server_fn/server_fn_macro_default", version = "0.8.3" }
|
||||
tachys = { path = "./tachys", version = "0.2.4" }
|
||||
reactive_graph = { path = "./reactive_graph", version = "0.2.4" }
|
||||
reactive_stores = { path = "./reactive_stores", version = "0.2.4" }
|
||||
reactive_stores_macro = { path = "./reactive_stores_macro", version = "0.2.4" }
|
||||
server_fn = { path = "./server_fn", version = "0.8.4" }
|
||||
server_fn_macro = { path = "./server_fn_macro", version = "0.8.4" }
|
||||
server_fn_macro_default = { path = "./server_fn/server_fn_macro_default", version = "0.8.4" }
|
||||
tachys = { path = "./tachys", version = "0.2.5" }
|
||||
wasm_split_helpers = { path = "./wasm_split", version = "0.1.0" }
|
||||
wasm_split_macros = { path = "./wasm_split_macros", version = "0.1.0" }
|
||||
|
||||
@@ -79,7 +79,7 @@ async-once-cell = { default-features = false, version = "0.5.3" }
|
||||
itertools = { default-features = false, version = "0.14.0" }
|
||||
convert_case = { default-features = false, version = "0.8.0" }
|
||||
serde_json = { default-features = false, version = "1.0.140" }
|
||||
trybuild = { default-features = false, version = "1.0.105" }
|
||||
trybuild = { default-features = false, version = "1.0.106" }
|
||||
typed-builder = { default-features = false, version = "0.21.0" }
|
||||
thiserror = { default-features = false, version = "2.0.12" }
|
||||
wasm-bindgen = { default-features = false, version = "0.2.100" }
|
||||
@@ -101,7 +101,7 @@ proc-macro-error2 = { default-features = false, version = "2.0.1" }
|
||||
const_format = { default-features = false, version = "0.2.34" }
|
||||
gloo-net = { default-features = false, version = "0.6.0" }
|
||||
url = { default-features = false, version = "2.5.4" }
|
||||
tokio = { default-features = false, version = "1.45.1" }
|
||||
tokio = { default-features = false, version = "1.46.1" }
|
||||
base64 = { default-features = false, version = "0.22.1" }
|
||||
cfg-if = { default-features = false, version = "1.0.0" }
|
||||
wasm-bindgen-futures = { default-features = false, version = "0.4.50" }
|
||||
@@ -132,7 +132,7 @@ actix-ws = { default-features = false, version = "0.3.0" }
|
||||
tower-http = { default-features = false, version = "0.6.4" }
|
||||
prettyplease = { default-features = false, version = "0.2.35" }
|
||||
inventory = { default-features = false, version = "0.3.20" }
|
||||
config = { default-features = false, version = "0.15.11" }
|
||||
config = { default-features = false, version = "0.15.13" }
|
||||
camino = { default-features = false, version = "1.1.9" }
|
||||
ciborium = { default-features = false, version = "0.2.2" }
|
||||
multer = { default-features = false, version = "3.1.0" }
|
||||
@@ -152,12 +152,12 @@ futures-lite = { default-features = false, version = "2.6.0" }
|
||||
log = { default-features = false, version = "0.4.27" }
|
||||
percent-encoding = { default-features = false, version = "2.3.1" }
|
||||
async-executor = { default-features = false, version = "1.13.2" }
|
||||
const-str = { default-features = false, version = "0.6.2" }
|
||||
const-str = { default-features = false, version = "0.6.3" }
|
||||
http-body-util = { default-features = false, version = "0.1.3" }
|
||||
hyper = { default-features = false, version = "1.6.0" }
|
||||
postcard = { default-features = false, version = "1.1.1" }
|
||||
rmp-serde = { default-features = false, version = "1.3.0" }
|
||||
reqwest = { default-features = false, version = "0.12.18" }
|
||||
reqwest = { default-features = false, version = "0.12.22" }
|
||||
tower-layer = { default-features = false, version = "0.3.3" }
|
||||
attribute-derive = { default-features = false, version = "0.10.3" }
|
||||
insta = { default-features = false, version = "1.43.1" }
|
||||
|
||||
@@ -125,7 +125,7 @@ Yes, I’m sure there are. You can see from the state of our issue tracker over
|
||||
|
||||
This may be the big one: “production ready” implies a certain orientation to a library: that you can basically use it, without any special knowledge of its internals or ability to contribute. Everyone has this at some level in their stack: for example I (@gbj) don’t have the capacity or knowledge to contribute to something like `wasm-bindgen` at this point: I simply rely on it to work.
|
||||
|
||||
There are several people in the community using Leptos right now for internal apps at work, who have also become significant contributors. I think this is the right level of production use for now. There may be missing features that you need, and you may end up building them! But for internal apps, if you’re willing to build and contribute missing pieces along the way, the framework is definitely usable right now.
|
||||
There are several people in the community using Leptos right now for many websites at work, who have also become significant contributors. There may be missing features that you need, and you may end up building them! But, if you're willing to contribute a few missing pieces along the way, the framework is most definitely usable for production applications, especially given the ecosystem of libraries that have sprung up around it.
|
||||
|
||||
### Can I use this for native GUI?
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ leptos_meta = { path = "../../meta" }
|
||||
leptos_axum = { path = "../../integrations/axum", optional = true }
|
||||
leptos_router = { path = "../../router" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
thiserror = "1.0"
|
||||
thiserror = "2.0.12"
|
||||
tokio = { version = "1.39", features = [
|
||||
"rt-multi-thread",
|
||||
"macros",
|
||||
|
||||
@@ -18,7 +18,7 @@ tower = { version = "0.4.13", optional = true }
|
||||
tower-http = { version = "0.5.2", features = ["fs"], optional = true }
|
||||
tokio = { version = "1.39", features = ["full"], optional = true }
|
||||
http = { version = "1.1" }
|
||||
thiserror = "1.0"
|
||||
thiserror = "2.0.12"
|
||||
wasm-bindgen = "0.2.93"
|
||||
|
||||
[features]
|
||||
|
||||
@@ -15,7 +15,7 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
log = "0.4.22"
|
||||
console_log = "1.0"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
thiserror = "1.0"
|
||||
thiserror = "2.0.12"
|
||||
tracing = "0.1.40"
|
||||
tracing-subscriber = "0.3.18"
|
||||
tracing-subscriber-wasm = "0.1.0"
|
||||
|
||||
@@ -15,7 +15,7 @@ leptos_meta = { path = "../../meta" }
|
||||
leptos_axum = { path = "../../integrations/axum", optional = true }
|
||||
leptos_router = { path = "../../router" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
thiserror = "1.0"
|
||||
thiserror = "2.0.12"
|
||||
tokio = { version = "1.39", features = [ "rt-multi-thread", "macros", "time" ], optional = true }
|
||||
wasm-bindgen = "0.2.92"
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ tower-http = { version = "0.6.2", features = [
|
||||
"trace",
|
||||
], optional = true }
|
||||
tokio = { version = "1.39", features = ["full"], optional = true }
|
||||
thiserror = "2.0.11"
|
||||
thiserror = "2.0.12"
|
||||
wasm-bindgen = "0.2.93"
|
||||
serde_toml = "0.0.1"
|
||||
toml = "0.8.19"
|
||||
|
||||
@@ -17,7 +17,7 @@ leptos_actix = { path = "../../integrations/actix", optional = true }
|
||||
leptos_router = { path = "../../router" }
|
||||
log = "0.4.22"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
thiserror = "1.0"
|
||||
thiserror = "2.0.12"
|
||||
tokio = { version = "1.39", features = ["time"] }
|
||||
wasm-bindgen = "0.2.93"
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ leptos_axum = { path = "../../integrations/axum", optional = true }
|
||||
leptos_router = { path = "../../router" }
|
||||
log = "0.4.22"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
thiserror = "1.0"
|
||||
thiserror = "2.0.12"
|
||||
axum = { version = "0.8.1", optional = true }
|
||||
tower = { version = "0.4.13", optional = true }
|
||||
tower-http = { version = "0.5.2", features = ["fs"], optional = true }
|
||||
|
||||
@@ -17,7 +17,7 @@ leptos_axum = { path = "../../integrations/axum", optional = true }
|
||||
leptos_router = { path = "../../router" }
|
||||
log = "0.4.22"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
thiserror = "1.0"
|
||||
thiserror = "2.0.12"
|
||||
axum = { version = "0.8.1", optional = true }
|
||||
tower = { version = "0.4.13", optional = true }
|
||||
tower-http = { version = "0.5.2", features = ["fs"], optional = true }
|
||||
|
||||
@@ -20,7 +20,7 @@ tokio = { version = "1.39", features = [
|
||||
tower = { version = "0.4.13", optional = true }
|
||||
tower-http = { version = "0.5.2", features = ["fs"], optional = true }
|
||||
wasm-bindgen = "0.2.93"
|
||||
thiserror = "1.0"
|
||||
thiserror = "2.0.12"
|
||||
tracing = { version = "0.1.40", optional = true }
|
||||
http = "1.1"
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ leptos_actix = { path = "../../integrations/actix", optional = true }
|
||||
log = "0.4.22"
|
||||
simple_logger = "5.0"
|
||||
gloo = { git = "https://github.com/rustwasm/gloo" }
|
||||
sqlx = { version = "0.8.0", features = [
|
||||
sqlx = { version = "0.8.6", features = [
|
||||
"runtime-tokio-rustls",
|
||||
"sqlite",
|
||||
], optional = true }
|
||||
@@ -44,12 +44,12 @@ denylist = ["actix-files", "actix-web", "leptos_actix", "sqlx"]
|
||||
skip_feature_sets = [["csr", "ssr"], ["csr", "hydrate"], ["ssr", "hydrate"], []]
|
||||
|
||||
[package.metadata.leptos]
|
||||
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name
|
||||
# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name
|
||||
output-name = "todo_app_sqlite"
|
||||
# The site root folder is where cargo-leptos generate all output. WARNING: all content of this folder will be erased on a rebuild. Use it in your server setup.
|
||||
site-root = "target/site"
|
||||
# The site-root relative folder where all compiled output (JS, WASM and CSS) is written
|
||||
# Defaults to pkg
|
||||
# Defaults to pkg
|
||||
site-pkg-dir = "pkg"
|
||||
# [Optional] The source CSS file. If it ends with .sass or .scss then it will be compiled by dart-sass into CSS. The CSS is optimized by Lightning CSS before being written to <site-root>/<site-pkg>/app.css
|
||||
style-file = "./style.css"
|
||||
|
||||
@@ -20,11 +20,11 @@ axum = { version = "0.8.1", optional = true }
|
||||
tower = { version = "0.4.13", optional = true }
|
||||
tower-http = { version = "0.5.2", features = ["fs"], optional = true }
|
||||
tokio = { version = "1.39", features = ["full"], optional = true }
|
||||
sqlx = { version = "0.8.0", features = [
|
||||
sqlx = { version = "0.8.6", features = [
|
||||
"runtime-tokio-rustls",
|
||||
"sqlite",
|
||||
], optional = true }
|
||||
thiserror = "1.0"
|
||||
thiserror = "2.0.12"
|
||||
wasm-bindgen = "0.2.93"
|
||||
|
||||
[features]
|
||||
|
||||
@@ -20,11 +20,11 @@ tower = { version = "0.5.1", features = ["util"], optional = true }
|
||||
tower-http = { version = "0.6.1", features = ["fs"], optional = true }
|
||||
tokio = { version = "1.39", features = ["full"], optional = true }
|
||||
http = { version = "1.1" }
|
||||
sqlx = { version = "0.8.0", features = [
|
||||
sqlx = { version = "0.8.6", features = [
|
||||
"runtime-tokio-rustls",
|
||||
"sqlite",
|
||||
], optional = true }
|
||||
thiserror = "2.0"
|
||||
thiserror = "2.0.12"
|
||||
wasm-bindgen = "0.2.93"
|
||||
|
||||
[features]
|
||||
|
||||
@@ -17,7 +17,7 @@ simple_logger = "5.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
axum = { version = "0.8.1", optional = true }
|
||||
tokio = { version = "1.39", features = ["full"], optional = true }
|
||||
thiserror = "2.0"
|
||||
thiserror = "2.0.12"
|
||||
wasm-bindgen = "0.2.100"
|
||||
|
||||
[features]
|
||||
|
||||
@@ -11,7 +11,7 @@ edition.workspace = true
|
||||
[dependencies]
|
||||
actix-http = { workspace = true, default-features = true }
|
||||
actix-files = { workspace = true, default-features = true }
|
||||
actix-web = { workspace = true, default-features = true }
|
||||
actix-web = { workspace = true, default-features = false }
|
||||
futures = { workspace = true, default-features = true }
|
||||
any_spawner = { workspace = true, features = ["tokio"] }
|
||||
hydration_context = { workspace = true }
|
||||
@@ -20,7 +20,7 @@ leptos_integration_utils = { workspace = true }
|
||||
leptos_macro = { workspace = true, features = ["actix"] }
|
||||
leptos_meta = { workspace = true, features = ["nonce"] }
|
||||
leptos_router = { workspace = true, features = ["ssr"] }
|
||||
server_fn = { workspace = true, features = ["actix"] }
|
||||
server_fn = { workspace = true, features = ["actix-no-default"] }
|
||||
tachys = { workspace = true }
|
||||
serde_json = { workspace = true , default-features = true }
|
||||
parking_lot = { workspace = true, default-features = true }
|
||||
@@ -33,6 +33,8 @@ dashmap = { workspace = true, default-features = true }
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
[features]
|
||||
default = ["actix-default"]
|
||||
actix-default = ["actix-web/default"]
|
||||
islands-router = ["tachys/islands"]
|
||||
tracing = ["dep:tracing"]
|
||||
|
||||
|
||||
@@ -282,6 +282,7 @@ pub fn redirect(path: &str) {
|
||||
/// // call ServerFn::register() for each of the server functions you've defined
|
||||
/// }
|
||||
///
|
||||
/// # #[cfg(feature = "default")]
|
||||
/// #[actix_web::main]
|
||||
/// async fn main() -> std::io::Result<()> {
|
||||
/// // make sure you actually register your server functions
|
||||
@@ -297,6 +298,8 @@ pub fn redirect(path: &str) {
|
||||
/// .run()
|
||||
/// .await
|
||||
/// }
|
||||
/// # #[cfg(not(feature = "default"))]
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// ## Provided Context Types
|
||||
@@ -442,6 +445,7 @@ pub fn handle_server_fns_with_context(
|
||||
/// view! { <main>"Hello, world!"</main> }
|
||||
/// }
|
||||
///
|
||||
/// # #[cfg(feature = "default")]
|
||||
/// #[actix_web::main]
|
||||
/// async fn main() -> std::io::Result<()> {
|
||||
/// let conf = get_configuration(Some("Cargo.toml")).unwrap();
|
||||
@@ -461,6 +465,8 @@ pub fn handle_server_fns_with_context(
|
||||
/// .run()
|
||||
/// .await
|
||||
/// }
|
||||
/// # #[cfg(not(feature = "default"))]
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// ## Provided Context Types
|
||||
@@ -499,6 +505,7 @@ where
|
||||
/// view! { <main>"Hello, world!"</main> }
|
||||
/// }
|
||||
///
|
||||
/// # #[cfg(feature = "default")]
|
||||
/// #[actix_web::main]
|
||||
/// async fn main() -> std::io::Result<()> {
|
||||
/// let conf = get_configuration(Some("Cargo.toml")).unwrap();
|
||||
@@ -521,6 +528,9 @@ where
|
||||
/// .run()
|
||||
/// .await
|
||||
/// }
|
||||
///
|
||||
/// # #[cfg(not(feature = "default"))]
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// ## Provided Context Types
|
||||
@@ -557,6 +567,7 @@ where
|
||||
/// view! { <main>"Hello, world!"</main> }
|
||||
/// }
|
||||
///
|
||||
/// # #[cfg(feature = "default")]
|
||||
/// #[actix_web::main]
|
||||
/// async fn main() -> std::io::Result<()> {
|
||||
/// let conf = get_configuration(Some("Cargo.toml")).unwrap();
|
||||
@@ -576,6 +587,8 @@ where
|
||||
/// .run()
|
||||
/// .await
|
||||
/// }
|
||||
/// # #[cfg(not(feature = "default"))]
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// ## Provided Context Types
|
||||
|
||||
@@ -4,7 +4,7 @@ authors = ["Greg Johnston"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/leptos-rs/leptos"
|
||||
description = "Axum integrations for the Leptos web framework."
|
||||
version = "0.8.3"
|
||||
version = { workspace = true }
|
||||
rust-version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||
use tachys::prelude::IntoAttributeValue;
|
||||
|
||||
/// Describes a value that is either a static or a reactive string, i.e.,
|
||||
/// a [`String`], a [`&str`], or a reactive `Fn() -> String`.
|
||||
/// a [`String`], a [`&str`], a `Signal` or a reactive `Fn() -> String`.
|
||||
#[derive(Clone)]
|
||||
pub struct TextProp(Arc<dyn Fn() -> Oco<'static, str> + Send + Sync>);
|
||||
|
||||
@@ -82,3 +82,93 @@ impl IntoAttributeValue for TextProp {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! textprop_reactive {
|
||||
($name:ident, <$($gen:ident),*>, $v:ty, $( $where_clause:tt )*) =>
|
||||
{
|
||||
#[allow(deprecated)]
|
||||
impl<$($gen),*> From<$name<$($gen),*>> for TextProp
|
||||
where
|
||||
$v: Into<Oco<'static, str>> + Clone + Send + Sync + 'static,
|
||||
$($where_clause)*
|
||||
{
|
||||
#[inline(always)]
|
||||
fn from(s: $name<$($gen),*>) -> Self {
|
||||
TextProp(Arc::new(move || s.get().into()))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
mod stable {
|
||||
use super::TextProp;
|
||||
use oco_ref::Oco;
|
||||
#[allow(deprecated)]
|
||||
use reactive_graph::wrappers::read::MaybeSignal;
|
||||
use reactive_graph::{
|
||||
computed::{ArcMemo, Memo},
|
||||
owner::Storage,
|
||||
signal::{ArcReadSignal, ArcRwSignal, ReadSignal, RwSignal},
|
||||
traits::Get,
|
||||
wrappers::read::{ArcSignal, Signal},
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
textprop_reactive!(
|
||||
RwSignal,
|
||||
<V, S>,
|
||||
V,
|
||||
RwSignal<V, S>: Get<Value = V>,
|
||||
S: Storage<V> + Storage<Option<V>>,
|
||||
S: Send + Sync + 'static,
|
||||
);
|
||||
textprop_reactive!(
|
||||
ReadSignal,
|
||||
<V, S>,
|
||||
V,
|
||||
ReadSignal<V, S>: Get<Value = V>,
|
||||
S: Storage<V> + Storage<Option<V>>,
|
||||
S: Send + Sync + 'static,
|
||||
);
|
||||
textprop_reactive!(
|
||||
Memo,
|
||||
<V, S>,
|
||||
V,
|
||||
Memo<V, S>: Get<Value = V>,
|
||||
S: Storage<V> + Storage<Option<V>>,
|
||||
S: Send + Sync + 'static,
|
||||
);
|
||||
textprop_reactive!(
|
||||
Signal,
|
||||
<V, S>,
|
||||
V,
|
||||
Signal<V, S>: Get<Value = V>,
|
||||
S: Storage<V> + Storage<Option<V>>,
|
||||
S: Send + Sync + 'static,
|
||||
);
|
||||
textprop_reactive!(
|
||||
MaybeSignal,
|
||||
<V, S>,
|
||||
V,
|
||||
MaybeSignal<V, S>: Get<Value = V>,
|
||||
S: Storage<V> + Storage<Option<V>>,
|
||||
S: Send + Sync + 'static,
|
||||
);
|
||||
textprop_reactive!(ArcRwSignal, <V>, V, ArcRwSignal<V>: Get<Value = V>);
|
||||
textprop_reactive!(ArcReadSignal, <V>, V, ArcReadSignal<V>: Get<Value = V>);
|
||||
textprop_reactive!(ArcMemo, <V>, V, ArcMemo<V>: Get<Value = V>);
|
||||
textprop_reactive!(ArcSignal, <V>, V, ArcSignal<V>: Get<Value = V>);
|
||||
}
|
||||
|
||||
/// Extension trait for `Option<TextProp>`
|
||||
pub trait OptionTextPropExt {
|
||||
/// Accesses the current value of the `Option<TextProp>` as an `Option<Oco<'static, str>>`.
|
||||
fn get(&self) -> Option<Oco<'static, str>>;
|
||||
}
|
||||
|
||||
impl OptionTextPropExt for Option<TextProp> {
|
||||
fn get(&self) -> Option<Oco<'static, str>> {
|
||||
self.as_ref().map(|text_prop| text_prop.get())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,19 @@ macro_rules! error {
|
||||
($($t:tt)*) => ($crate::logging::console_error(&format_args!($($t)*).to_string()))
|
||||
}
|
||||
|
||||
/// Uses `println!()`-style formatting to log something to the console (in the browser)
|
||||
/// or via `println!()` (if not in the browser), but only if it's a debug build.
|
||||
#[macro_export]
|
||||
macro_rules! debug_log {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
if cfg!(debug_assertions) {
|
||||
$crate::log!($($x)*)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Uses `println!()`-style formatting to log warnings to the console (in the browser)
|
||||
/// or via `eprintln!()` (if not in the browser), but only if it's a debug build.
|
||||
#[macro_export]
|
||||
@@ -36,6 +49,19 @@ macro_rules! debug_warn {
|
||||
}
|
||||
}
|
||||
|
||||
/// Uses `println!()`-style formatting to log errors to the console (in the browser)
|
||||
/// or via `eprintln!()` (if not in the browser), but only if it's a debug build.
|
||||
#[macro_export]
|
||||
macro_rules! debug_error {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
if cfg!(debug_assertions) {
|
||||
$crate::error!($($x)*)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const fn log_to_stdout() -> bool {
|
||||
cfg!(not(all(
|
||||
target_arch = "wasm32",
|
||||
@@ -55,7 +81,7 @@ pub fn console_log(s: &str) {
|
||||
}
|
||||
|
||||
/// Log a warning to the console (in the browser)
|
||||
/// or via `println!()` (if not in the browser).
|
||||
/// or via `eprintln!()` (if not in the browser).
|
||||
pub fn console_warn(s: &str) {
|
||||
if log_to_stdout() {
|
||||
eprintln!("{s}");
|
||||
@@ -65,7 +91,7 @@ pub fn console_warn(s: &str) {
|
||||
}
|
||||
|
||||
/// Log an error to the console (in the browser)
|
||||
/// or via `println!()` (if not in the browser).
|
||||
/// or via `eprintln!()` (if not in the browser).
|
||||
#[inline(always)]
|
||||
pub fn console_error(s: &str) {
|
||||
if log_to_stdout() {
|
||||
@@ -75,21 +101,29 @@ pub fn console_error(s: &str) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Log an error to the console (in the browser)
|
||||
/// Log a string to the console (in the browser)
|
||||
/// or via `println!()` (if not in the browser), but only in a debug build.
|
||||
#[inline(always)]
|
||||
pub fn console_debug_warn(s: &str) {
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
if log_to_stdout() {
|
||||
eprintln!("{s}");
|
||||
} else {
|
||||
web_sys::console::warn_1(&JsValue::from_str(s));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
{
|
||||
let _ = s;
|
||||
pub fn console_debug_log(s: &str) {
|
||||
if cfg!(debug_assertions) {
|
||||
console_log(s)
|
||||
}
|
||||
}
|
||||
|
||||
/// Log a warning to the console (in the browser)
|
||||
/// or via `eprintln!()` (if not in the browser), but only in a debug build.
|
||||
#[inline(always)]
|
||||
pub fn console_debug_warn(s: &str) {
|
||||
if cfg!(debug_assertions) {
|
||||
console_warn(s)
|
||||
}
|
||||
}
|
||||
|
||||
/// Log an error to the console (in the browser)
|
||||
/// or via `eprintln!()` (if not in the browser), but only in a debug build.
|
||||
#[inline(always)]
|
||||
pub fn console_debug_error(s: &str) {
|
||||
if cfg!(debug_assertions) {
|
||||
console_error(s)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,93 +251,67 @@ impl LNode {
|
||||
action: PatchAction::ClearChildren,
|
||||
}]
|
||||
} else {
|
||||
let mut a = 0;
|
||||
let mut b = std::cmp::max(old.len(), new.len()) - 1; // min is 0, have checked both have items
|
||||
let width = old.len() + 1;
|
||||
let height = new.len() + 1;
|
||||
let mut mat = vec![0; width * height];
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
for i in 1..width {
|
||||
mat[i] = i;
|
||||
}
|
||||
for i in 1..height {
|
||||
mat[i * width] = i;
|
||||
}
|
||||
for j in 1..height {
|
||||
for i in 1..width {
|
||||
if old[i - 1] == new[j - 1] {
|
||||
mat[j * width + i] = mat[(j - 1) * width + (i - 1)];
|
||||
} else {
|
||||
mat[j * width + i] = (mat[(j - 1) * width + i] + 1)
|
||||
.min(mat[j * width + (i - 1)] + 1)
|
||||
.min(mat[(j - 1) * width + (i - 1)] + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
let (mut i, mut j) = (old.len(), new.len());
|
||||
let mut patches = vec![];
|
||||
// common prefix
|
||||
while a < b {
|
||||
let old = old.get(a);
|
||||
let new = new.get(a);
|
||||
|
||||
match (old, new) {
|
||||
(None, Some(new)) => patches.push(Patch {
|
||||
path: path.to_owned(),
|
||||
action: PatchAction::InsertChild {
|
||||
before: a,
|
||||
child: new.to_replacement_node(old_children),
|
||||
},
|
||||
}),
|
||||
(Some(_), None) => patches.push(Patch {
|
||||
path: path.to_owned(),
|
||||
action: PatchAction::RemoveChild { at: a },
|
||||
}),
|
||||
(Some(old), Some(new)) if old != new => {
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
a += 1;
|
||||
}
|
||||
|
||||
// common suffix
|
||||
while b >= a {
|
||||
let old = old.get(b);
|
||||
let new = new.get(b);
|
||||
|
||||
match (old, new) {
|
||||
(None, Some(new)) => patches.push(Patch {
|
||||
path: path.to_owned(),
|
||||
action: PatchAction::InsertChildAfter {
|
||||
after: b - 1,
|
||||
child: new.to_replacement_node(old_children),
|
||||
},
|
||||
}),
|
||||
(Some(_), None) => patches.push(Patch {
|
||||
path: path.to_owned(),
|
||||
action: PatchAction::RemoveChild { at: b },
|
||||
}),
|
||||
(Some(old), Some(new)) if old != new => {
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if b == 0 {
|
||||
break;
|
||||
}
|
||||
b -= 1;
|
||||
}
|
||||
|
||||
// diffing in middle
|
||||
if b >= a {
|
||||
let old_slice_end =
|
||||
if b >= old.len() { old.len() - 1 } else { b };
|
||||
let new_slice_end =
|
||||
if b >= new.len() { new.len() - 1 } else { b };
|
||||
let old = &old[a..=old_slice_end];
|
||||
let new = &new[a..=new_slice_end];
|
||||
|
||||
for (new_idx, new_node) in new.iter().enumerate() {
|
||||
match old.get(new_idx) {
|
||||
Some(old_node) => {
|
||||
let mut new_path = path.to_vec();
|
||||
new_path.push(new_idx + a);
|
||||
let diffs = old_node.diff_at(
|
||||
new_node,
|
||||
&new_path,
|
||||
old_children,
|
||||
);
|
||||
patches.extend(&mut diffs.into_iter());
|
||||
}
|
||||
None => patches.push(Patch {
|
||||
while i > 0 || j > 0 {
|
||||
if i > 0 && j > 0 && old[i - 1] == new[j - 1] {
|
||||
i -= 1;
|
||||
j -= 1;
|
||||
} else {
|
||||
let current = mat[j * width + i];
|
||||
if i > 0
|
||||
&& j > 0
|
||||
&& mat[(j - 1) * width + i - 1] + 1 == current
|
||||
{
|
||||
let mut new_path = path.to_owned();
|
||||
new_path.push(i - 1);
|
||||
let diffs = old[i - 1].diff_at(
|
||||
&new[j - 1],
|
||||
&new_path,
|
||||
old_children,
|
||||
);
|
||||
patches.extend(&mut diffs.into_iter());
|
||||
i -= 1;
|
||||
j -= 1;
|
||||
} else if i > 0 && mat[j * width + i - 1] + 1 == current {
|
||||
patches.push(Patch {
|
||||
path: path.to_owned(),
|
||||
action: PatchAction::RemoveChild { at: i - 1 },
|
||||
});
|
||||
i -= 1;
|
||||
} else if j > 0 && mat[(j - 1) * width + i] + 1 == current {
|
||||
patches.push(Patch {
|
||||
path: path.to_owned(),
|
||||
action: PatchAction::InsertChild {
|
||||
before: new_idx,
|
||||
child: new_node
|
||||
before: i,
|
||||
child: new[j - 1]
|
||||
.to_replacement_node(old_children),
|
||||
},
|
||||
}),
|
||||
});
|
||||
j -= 1;
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -514,23 +488,17 @@ mod tests {
|
||||
let delta = a.diff(&b);
|
||||
assert_eq!(
|
||||
delta,
|
||||
vec![
|
||||
Patch {
|
||||
path: vec![],
|
||||
action: PatchAction::InsertChildAfter {
|
||||
after: 0,
|
||||
child: ReplacementNode::Element {
|
||||
name: "button".into(),
|
||||
attrs: vec![],
|
||||
children: vec![ReplacementNode::Html("bar".into())]
|
||||
}
|
||||
vec![Patch {
|
||||
path: vec![],
|
||||
action: PatchAction::InsertChild {
|
||||
before: 0,
|
||||
child: ReplacementNode::Element {
|
||||
name: "button".into(),
|
||||
attrs: vec![],
|
||||
children: vec![ReplacementNode::Html("foo".into())]
|
||||
}
|
||||
},
|
||||
Patch {
|
||||
path: vec![0, 0],
|
||||
action: PatchAction::SetText("foo".into())
|
||||
}
|
||||
]
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -121,6 +121,10 @@ impl ViewMacros {
|
||||
}
|
||||
diffs
|
||||
} else {
|
||||
// TODO: instead of simply returning no patches, when number of views differs,
|
||||
// we can compare views content to determine which views were shifted
|
||||
// or come up with another idea that will allow to send patches when views were shifted/removed/added
|
||||
lock.insert(path.clone(), new_views);
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,9 @@ impl LNode {
|
||||
LNode::parse_node(child, views)?;
|
||||
}
|
||||
}
|
||||
Node::RawText(text) => {
|
||||
views.push(LNode::Text(text.to_string_best()));
|
||||
}
|
||||
Node::Text(text) => {
|
||||
views.push(LNode::Text(text.value_string()));
|
||||
}
|
||||
|
||||
@@ -4,7 +4,10 @@ function patch(json) {
|
||||
const views = JSON.parse(json);
|
||||
for (const [id, patches] of views) {
|
||||
console.log("[HOT RELOAD]", id, patches);
|
||||
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_COMMENT),
|
||||
const walker = document.createTreeWalker(
|
||||
document.body,
|
||||
NodeFilter.SHOW_COMMENT,
|
||||
),
|
||||
open = `hot-reload|${id}|open`,
|
||||
close = `hot-reload|${id}|close`;
|
||||
let start, end;
|
||||
@@ -21,150 +24,200 @@ function patch(json) {
|
||||
}
|
||||
|
||||
for (const [start, end] of instances) {
|
||||
// build tree of current actual children
|
||||
const actualChildren = childrenFromRange(start.parentElement, start, end);
|
||||
const actions = [];
|
||||
|
||||
// build up the set of actions
|
||||
for (const patch of patches) {
|
||||
const actualChildren = childrenFromRange(
|
||||
start.parentElement,
|
||||
start,
|
||||
end,
|
||||
);
|
||||
const child = childAtPath(
|
||||
actualChildren.length > 1 ? { children: actualChildren } : actualChildren[0],
|
||||
patch.path
|
||||
actualChildren.length > 1
|
||||
? { children: actualChildren }
|
||||
: actualChildren[0],
|
||||
patch.path,
|
||||
);
|
||||
const action = patch.action;
|
||||
if (action == "ClearChildren") {
|
||||
actions.push(() => {
|
||||
console.log("[HOT RELOAD] > ClearChildren", child.node);
|
||||
console.log("[HOT RELOAD] > ClearChildren", child.node);
|
||||
if (child.node) {
|
||||
child.node.textContent = "";
|
||||
});
|
||||
} else if (action.ReplaceWith) {
|
||||
actions.push(() => {
|
||||
console.log("[HOT RELOAD] > ReplaceWith", child, action.ReplaceWith);
|
||||
const replacement = fromReplacementNode(action.ReplaceWith, actualChildren);
|
||||
if (child.node) {
|
||||
child.node.replaceWith(replacement);
|
||||
} else {
|
||||
const range = new Range();
|
||||
range.setStartAfter(child.start);
|
||||
range.setEndAfter(child.end);
|
||||
range.deleteContents();
|
||||
child.start.replaceWith(replacement);
|
||||
} else {
|
||||
for (const existingChild of child.children) {
|
||||
let parent = existingChild.node.parentElement;
|
||||
parent.removeChild(existingChild.node);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (action.ReplaceWith) {
|
||||
console.log(
|
||||
"[HOT RELOAD] > ReplaceWith",
|
||||
child,
|
||||
action.ReplaceWith,
|
||||
);
|
||||
const replacement = fromReplacementNode(
|
||||
action.ReplaceWith,
|
||||
actualChildren,
|
||||
);
|
||||
if (child.node) {
|
||||
child.node.replaceWith(replacement);
|
||||
} else {
|
||||
if (child.children) {
|
||||
child.children[0].node.parentElement.insertBefore(
|
||||
replacement,
|
||||
child.children[0].node,
|
||||
);
|
||||
for (const existingChild of child.children) {
|
||||
existingChild.node.parentElement.removeChild(
|
||||
existingChild.node,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (action.ChangeTagName) {
|
||||
const oldNode = child.node;
|
||||
actions.push(() => {
|
||||
console.log("[HOT RELOAD] > ChangeTagName", child.node, action.ChangeTagName);
|
||||
const newElement = document.createElement(action.ChangeTagName);
|
||||
for (const attr of oldNode.attributes) {
|
||||
newElement.setAttribute(attr.name, attr.value);
|
||||
}
|
||||
for (const childNode of child.node.childNodes) {
|
||||
newElement.appendChild(childNode);
|
||||
}
|
||||
console.log(
|
||||
"[HOT RELOAD] > ChangeTagName",
|
||||
child.node,
|
||||
action.ChangeTagName,
|
||||
);
|
||||
const newElement = document.createElement(action.ChangeTagName);
|
||||
for (const attr of oldNode.attributes) {
|
||||
newElement.setAttribute(attr.name, attr.value);
|
||||
}
|
||||
for (const childNode of child.node.childNodes) {
|
||||
newElement.appendChild(childNode);
|
||||
}
|
||||
|
||||
child.node.replaceWith(newElement);
|
||||
});
|
||||
child.node.replaceWith(newElement);
|
||||
} else if (action.RemoveAttribute) {
|
||||
actions.push(() => {
|
||||
console.log("[HOT RELOAD] > RemoveAttribute", child.node, action.RemoveAttribute);
|
||||
child.node.removeAttribute(action.RemoveAttribute);
|
||||
});
|
||||
console.log(
|
||||
"[HOT RELOAD] > RemoveAttribute",
|
||||
child.node,
|
||||
action.RemoveAttribute,
|
||||
);
|
||||
child.node.removeAttribute(action.RemoveAttribute);
|
||||
} else if (action.SetAttribute) {
|
||||
const [name, value] = action.SetAttribute;
|
||||
actions.push(() => {
|
||||
console.log("[HOT RELOAD] > SetAttribute", child.node, action.SetAttribute);
|
||||
child.node.setAttribute(name, value);
|
||||
});
|
||||
console.log(
|
||||
"[HOT RELOAD] > SetAttribute",
|
||||
child.node,
|
||||
action.SetAttribute,
|
||||
);
|
||||
child.node.setAttribute(name, value);
|
||||
} else if (action.SetText) {
|
||||
const node = child.node;
|
||||
actions.push(() => {
|
||||
console.log("[HOT RELOAD] > SetText", child.node, action.SetText);
|
||||
node.textContent = action.SetText;
|
||||
});
|
||||
console.log("[HOT RELOAD] > SetText", child.node, action.SetText);
|
||||
node.textContent = action.SetText;
|
||||
} else if (action.AppendChildren) {
|
||||
actions.push(() => {
|
||||
console.log("[HOT RELOAD] > AppendChildren", child.node, action.AppendChildren);
|
||||
const newChildren = fromReplacementNode(action.AppendChildren, actualChildren);
|
||||
child.node.append(newChildren);
|
||||
});
|
||||
console.log(
|
||||
"[HOT RELOAD] > AppendChildren",
|
||||
child.node,
|
||||
action.AppendChildren,
|
||||
);
|
||||
const newChildren = action.AppendChildren.map((x) =>
|
||||
fromReplacementNode(x, actualChildren),
|
||||
);
|
||||
child.node.append(...newChildren);
|
||||
} else if (action.RemoveChild) {
|
||||
actions.push(() => {
|
||||
console.log("[HOT RELOAD] > RemoveChild", child.node, child.children, action.RemoveChild);
|
||||
const toRemove = child.children[action.RemoveChild.at];
|
||||
let toRemoveNode = toRemove.node;
|
||||
if (!toRemoveNode) {
|
||||
const range = new Range();
|
||||
range.setStartBefore(toRemove.start);
|
||||
range.setEndAfter(toRemove.end);
|
||||
toRemoveNode = range.deleteContents();
|
||||
} else {
|
||||
toRemoveNode.parentNode.removeChild(toRemoveNode);
|
||||
}
|
||||
});
|
||||
console.log(
|
||||
"[HOT RELOAD] > RemoveChild",
|
||||
child.node,
|
||||
child.children,
|
||||
action.RemoveChild,
|
||||
);
|
||||
const toRemove = child.children[action.RemoveChild.at];
|
||||
let toRemoveNode = toRemove.node;
|
||||
if (!toRemoveNode) {
|
||||
const range = new Range();
|
||||
range.setStartBefore(toRemove.start);
|
||||
range.setEndAfter(toRemove.end);
|
||||
toRemoveNode = range.deleteContents();
|
||||
} else {
|
||||
toRemoveNode.parentNode.removeChild(toRemoveNode);
|
||||
}
|
||||
} else if (action.InsertChild) {
|
||||
const newChild = fromReplacementNode(action.InsertChild.child, actualChildren);
|
||||
const newChild = fromReplacementNode(
|
||||
action.InsertChild.child,
|
||||
actualChildren,
|
||||
);
|
||||
let children = [];
|
||||
if (child.children) {
|
||||
children = child.children;
|
||||
} else if (child.start && child.end) {
|
||||
children = childrenFromRange(child.node || child.start.parentElement, start, end);
|
||||
children = childrenFromRange(
|
||||
child.node || child.start.parentElement,
|
||||
start,
|
||||
end,
|
||||
);
|
||||
} else {
|
||||
console.warn("InsertChildAfter could not build children.");
|
||||
}
|
||||
const before = children[action.InsertChild.before];
|
||||
actions.push(() => {
|
||||
console.log("[HOT RELOAD] > InsertChild", child, child.node, action.InsertChild, " before ", before);
|
||||
if (!before && child.node) {
|
||||
child.node.appendChild(newChild);
|
||||
} else {
|
||||
let node = child.node || child.end.parentElement;
|
||||
const reference = before ? before.node || before.start : child.end;
|
||||
node.insertBefore(newChild, reference);
|
||||
}
|
||||
});
|
||||
const beforeNode = children[action.InsertChild.before];
|
||||
console.log(
|
||||
"[HOT RELOAD] > InsertChild",
|
||||
child,
|
||||
child.node,
|
||||
action.InsertChild,
|
||||
" before ",
|
||||
beforeNode,
|
||||
);
|
||||
if (beforeNode) {
|
||||
let node = beforeNode.node || beforeNode.start.previousSibling;
|
||||
node.parentElement.insertBefore(newChild, node);
|
||||
} else if (child.node) {
|
||||
child.node.appendChild(newChild);
|
||||
} else if (children) {
|
||||
let lastNode = children[children.length - 1];
|
||||
let afterNode = lastNode.node || lastNode.end.nextSibling;
|
||||
afterNode.after(newChild);
|
||||
}
|
||||
} else if (action.InsertChildAfter) {
|
||||
const newChild = fromReplacementNode(action.InsertChildAfter.child, actualChildren);
|
||||
const newChild = fromReplacementNode(
|
||||
action.InsertChildAfter.child,
|
||||
actualChildren,
|
||||
);
|
||||
let children = [];
|
||||
if (child.children) {
|
||||
children = child.children;
|
||||
} else if (child.start && child.end) {
|
||||
children = childrenFromRange(child.node || child.start.parentElement, start, end);
|
||||
children = childrenFromRange(
|
||||
child.node || child.start.parentElement,
|
||||
start,
|
||||
end,
|
||||
);
|
||||
} else {
|
||||
console.warn("InsertChildAfter could not build children.");
|
||||
}
|
||||
const after = children[action.InsertChildAfter.after];
|
||||
actions.push(() => {
|
||||
console.log(
|
||||
"[HOT RELOAD] > InsertChildAfter",
|
||||
child,
|
||||
child.node,
|
||||
action.InsertChildAfter,
|
||||
" after ",
|
||||
after
|
||||
);
|
||||
if (child.node && (!after || !(after.node || after.start).nextSibling)) {
|
||||
child.node.appendChild(newChild);
|
||||
console.log(
|
||||
"[HOT RELOAD] > InsertChildAfter",
|
||||
child,
|
||||
child.node,
|
||||
action.InsertChildAfter,
|
||||
" after ",
|
||||
after,
|
||||
);
|
||||
if (
|
||||
child.node &&
|
||||
(!after || !(after.node || after.start).nextSibling)
|
||||
) {
|
||||
child.node.appendChild(newChild);
|
||||
} else {
|
||||
const node = child.node || child.end;
|
||||
const parent =
|
||||
node.nodeType === Node.COMMENT_NODE ? node.parentNode : node;
|
||||
if (!after) {
|
||||
parent.appendChild(newChild);
|
||||
} else {
|
||||
const node = child.node || child.end;
|
||||
const parent = node.nodeType === Node.COMMENT_NODE ? node.parentNode : node;
|
||||
if (!after) {
|
||||
parent.appendChild(newChild);
|
||||
} else {
|
||||
parent.insertBefore(newChild, (after.node || after.start).nextSibling);
|
||||
}
|
||||
parent.insertBefore(
|
||||
newChild,
|
||||
(after.node || after.start).nextSibling,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.warn("[HOT RELOADING] Unmatched action", action);
|
||||
}
|
||||
}
|
||||
|
||||
// actually run the actions
|
||||
// the reason we delay them is so that children aren't moved before other children are found, etc.
|
||||
for (const action of actions) {
|
||||
action();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -191,8 +244,10 @@ function patch(json) {
|
||||
return element;
|
||||
} else {
|
||||
const child = childAtPath(
|
||||
actualChildren.length > 1 ? { children: actualChildren } : actualChildren[0],
|
||||
node.Path
|
||||
actualChildren.length > 1
|
||||
? { children: actualChildren }
|
||||
: actualChildren[0],
|
||||
node.Path,
|
||||
);
|
||||
if (child) {
|
||||
let childNode = child.node;
|
||||
@@ -215,7 +270,10 @@ function patch(json) {
|
||||
}
|
||||
return childNode;
|
||||
} else {
|
||||
console.warn("[HOT RELOADING] Could not find replacement node at ", node.Path);
|
||||
console.warn(
|
||||
"[HOT RELOADING] Could not find replacement node at ",
|
||||
node.Path,
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
@@ -227,13 +285,16 @@ function patch(json) {
|
||||
NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_COMMENT,
|
||||
{
|
||||
acceptNode(node) {
|
||||
if (node.parentNode == element && (!range || range.isPointInRange(node, 0))) {
|
||||
if (
|
||||
node.parentNode == element &&
|
||||
(!range || range.isPointInRange(node, 0))
|
||||
) {
|
||||
return NodeFilter.FILTER_ACCEPT;
|
||||
} else {
|
||||
return NodeFilter.FILTER_REJECT;
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
const actualChildren = [],
|
||||
elementCount = {};
|
||||
@@ -259,18 +320,22 @@ function patch(json) {
|
||||
node: walker.currentNode,
|
||||
});
|
||||
} else if (walker.currentNode.nodeType == Node.COMMENT_NODE) {
|
||||
if (walker.currentNode.textContent.trim().startsWith("hot-reload")) {
|
||||
if (walker.currentNode.textContent.trim().endsWith("-children|open")) {
|
||||
if (walker.currentNode.textContent.trim().startsWith("hot-reload|")) {
|
||||
if (walker.currentNode.textContent.trim().endsWith("|open")) {
|
||||
const startingName = walker.currentNode.textContent.trim();
|
||||
const componentName = startingName.replace("-children|open").replace("hot-reload|");
|
||||
const endingName = `hot-reload|${componentName}-children|close`;
|
||||
const componentName = startingName
|
||||
.replace("|open", "")
|
||||
.replace("hot-reload|", "");
|
||||
const endingName = `hot-reload|${componentName}|close`;
|
||||
let start = walker.currentNode;
|
||||
let depth = 1;
|
||||
|
||||
while (walker.nextNode()) {
|
||||
if (walker.currentNode.textContent.trim() == endingName) {
|
||||
depth--;
|
||||
} else if (walker.currentNode.textContent.trim() == startingName) {
|
||||
} else if (
|
||||
walker.currentNode.textContent.trim() == startingName
|
||||
) {
|
||||
depth++;
|
||||
}
|
||||
|
||||
@@ -283,7 +348,11 @@ function patch(json) {
|
||||
type: "fragment",
|
||||
start: start.nextSibling,
|
||||
end: end.previousSibling,
|
||||
children: childrenFromRange(start.parentElement, start.nextSibling, end.previousSibling),
|
||||
children: childrenFromRange(
|
||||
start.parentElement,
|
||||
start.nextSibling,
|
||||
end.previousSibling,
|
||||
),
|
||||
});
|
||||
}
|
||||
} else if (walker.currentNode.textContent.trim() == "<() />") {
|
||||
@@ -358,7 +427,10 @@ function patch(json) {
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.warn("[HOT RELOADING] Building children, encountered", walker.currentNode);
|
||||
console.warn(
|
||||
"[HOT RELOADING] Building children, encountered",
|
||||
walker.currentNode,
|
||||
);
|
||||
}
|
||||
}
|
||||
return actualChildren;
|
||||
@@ -374,7 +446,11 @@ function patch(json) {
|
||||
} else if (path == [0]) {
|
||||
return element;
|
||||
} else if (element.start && element.end) {
|
||||
const actualChildren = childrenFromRange(element.node || element.start.parentElement, element.start, element.end);
|
||||
const actualChildren = childrenFromRange(
|
||||
element.node || element.start.parentElement,
|
||||
element.start,
|
||||
element.end,
|
||||
);
|
||||
return childAtPath({ children: actualChildren }, path);
|
||||
} else {
|
||||
console.warn("[HOT RELOADING] Child at ", path, "not found in ", element);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "leptos_meta"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
authors = ["Greg Johnston"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/leptos-rs/leptos"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "reactive_graph"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
authors = ["Greg Johnston"]
|
||||
license = "MIT"
|
||||
readme = "../README.md"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "reactive_stores"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
authors = ["Greg Johnston"]
|
||||
license = "MIT"
|
||||
readme = "../README.md"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "reactive_stores_macro"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
authors = ["Greg Johnston"]
|
||||
license = "MIT"
|
||||
readme = "../README.md"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "leptos_router"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
authors = ["Greg Johnston", "Ben Wishovich"]
|
||||
license = "MIT"
|
||||
readme = "../README.md"
|
||||
|
||||
@@ -67,10 +67,32 @@ impl Url {
|
||||
}
|
||||
|
||||
pub fn hash(&self) -> &str {
|
||||
#[cfg(all(feature = "ssr", any(debug_assertions, leptos_debuginfo)))]
|
||||
{
|
||||
#[cfg(feature = "tracing")]
|
||||
tracing::warn!(
|
||||
"Reading hash on the server can lead to hydration errors."
|
||||
);
|
||||
#[cfg(not(feature = "tracing"))]
|
||||
eprintln!(
|
||||
"Reading hash on the server can lead to hydration errors."
|
||||
);
|
||||
}
|
||||
&self.hash
|
||||
}
|
||||
|
||||
pub fn hash_mut(&mut self) -> &mut String {
|
||||
#[cfg(all(feature = "ssr", any(debug_assertions, leptos_debuginfo)))]
|
||||
{
|
||||
#[cfg(feature = "tracing")]
|
||||
tracing::warn!(
|
||||
"Reading hash on the server can lead to hydration errors."
|
||||
);
|
||||
#[cfg(not(feature = "tracing"))]
|
||||
eprintln!(
|
||||
"Reading hash on the server can lead to hydration errors."
|
||||
);
|
||||
}
|
||||
&mut self.hash
|
||||
}
|
||||
|
||||
@@ -173,7 +195,7 @@ impl Location {
|
||||
let state = state.into();
|
||||
let pathname = Memo::new(move |_| url.with(|url| url.path.clone()));
|
||||
let search = Memo::new(move |_| url.with(|url| url.search.clone()));
|
||||
let hash = Memo::new(move |_| url.with(|url| url.hash.clone()));
|
||||
let hash = Memo::new(move |_| url.with(|url| url.hash().to_string()));
|
||||
let query =
|
||||
Memo::new(move |_| url.with(|url| url.search_params.clone()));
|
||||
Location {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "leptos_router_macro"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
authors = ["Greg Johnston", "Ben Wishovich"]
|
||||
license = "MIT"
|
||||
readme = "../README.md"
|
||||
|
||||
@@ -32,7 +32,7 @@ dashmap = { workspace = true, default-features = true }
|
||||
|
||||
## servers
|
||||
# actix
|
||||
actix-web = { optional = true, workspace = true, default-features = true }
|
||||
actix-web = { optional = true, workspace = true, default-features = false }
|
||||
actix-ws = { optional = true, workspace = true, default-features = true }
|
||||
|
||||
# axum
|
||||
@@ -108,7 +108,8 @@ axum-no-default = [
|
||||
"dep:tower-layer",
|
||||
]
|
||||
form-redirects = []
|
||||
actix = ["ssr", "dep:actix-web", "dep:actix-ws", "dep:send_wrapper"]
|
||||
actix-no-default = ["ssr", "dep:actix-web", "dep:actix-ws", "dep:send_wrapper"]
|
||||
actix = ["actix-web/default", "actix-no-default"]
|
||||
axum = ["axum/default", "axum-no-default", "axum/ws", "dep:tokio"]
|
||||
browser = [
|
||||
"dep:gloo-net",
|
||||
|
||||
@@ -120,7 +120,7 @@ pub mod request;
|
||||
/// Types and traits for HTTP responses.
|
||||
pub mod response;
|
||||
|
||||
#[cfg(feature = "actix")]
|
||||
#[cfg(feature = "actix-no-default")]
|
||||
#[doc(hidden)]
|
||||
pub use ::actix_web as actix_export;
|
||||
#[cfg(feature = "axum-no-default")]
|
||||
@@ -1118,7 +1118,7 @@ pub mod axum {
|
||||
}
|
||||
|
||||
/// Actix integration.
|
||||
#[cfg(feature = "actix")]
|
||||
#[cfg(feature = "actix-no-default")]
|
||||
pub mod actix {
|
||||
use crate::{
|
||||
error::FromServerFnError, middleware::BoxedService,
|
||||
|
||||
@@ -123,7 +123,7 @@ mod axum {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "actix")]
|
||||
#[cfg(feature = "actix-no-default")]
|
||||
mod actix {
|
||||
use crate::{
|
||||
error::ServerFnErrorErr,
|
||||
|
||||
@@ -4,7 +4,7 @@ use http::Method;
|
||||
use std::{borrow::Cow, future::Future};
|
||||
|
||||
/// Request types for Actix.
|
||||
#[cfg(feature = "actix")]
|
||||
#[cfg(feature = "actix-no-default")]
|
||||
pub mod actix;
|
||||
/// Request types for Axum.
|
||||
#[cfg(feature = "axum-no-default")]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/// Response types for Actix.
|
||||
#[cfg(feature = "actix")]
|
||||
#[cfg(feature = "actix-no-default")]
|
||||
pub mod actix;
|
||||
/// Response types for the browser.
|
||||
#[cfg(feature = "browser")]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tachys"
|
||||
version = "0.2.4"
|
||||
version = "0.2.5"
|
||||
authors = ["Greg Johnston"]
|
||||
license = "MIT"
|
||||
readme = "../README.md"
|
||||
|
||||
@@ -224,7 +224,7 @@ where
|
||||
extra_attrs,
|
||||
);
|
||||
if !T::EXISTS {
|
||||
buf.push_str("<!>");
|
||||
buf.push_str("<!--<() />-->");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ where
|
||||
extra_attrs,
|
||||
);
|
||||
if !T::EXISTS {
|
||||
buf.push_sync("<!>");
|
||||
buf.push_sync("<!--<() />-->");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ where
|
||||
extra_attrs,
|
||||
);
|
||||
if !T::EXISTS {
|
||||
buf.push_sync("<!>");
|
||||
buf.push_sync("<!--<() />-->");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user