diff --git a/AGENTS.md b/AGENTS.md index 90470ca..77f42d1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -54,3 +54,4 @@ Keep it stable. Prefer pointers to canonical sources over copied structure, file - Public examples and beginner APIs should use generated resources and `IntoEffect`, not raw ids or runtime opcodes. - Hemlate examples must use real hemplate syntax, not Vue/Handlebars sketches: `{+ expr +}` for escaped text, `{+= expr =+}` only for trusted/rendered HTML, `+attr="expr"` for dynamic attributes, and Rust-shaped `h-if`, `h-for`, `h-match`, `h-case` directives (`h-case="_"` is the default arm). - JS runtime changes must preserve root-scoped lookup and avoid selectors, VDOM, expressions, and per-node listeners. +- Axum apps should serve and load the shared runtime through hemx-axum helpers such as `runtime_js_path()` and `runtime_js()`, not hard-coded `/hemx.js` URLs or app-owned cache-busting strings. diff --git a/Cargo.lock b/Cargo.lock index 15224cf..1a37cb7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -105,6 +105,15 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bumpalo" version = "3.20.2" @@ -175,6 +184,25 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "cssparser" version = "0.34.0" @@ -209,6 +237,16 @@ dependencies = [ "syn", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -347,6 +385,16 @@ dependencies = [ "byteorder", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getopts" version = "0.2.24" @@ -473,6 +521,9 @@ dependencies = [ [[package]] name = "hemx-js" version = "0.1.0" +dependencies = [ + "sha2", +] [[package]] name = "hemx-kanban-example" @@ -1459,6 +1510,17 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "shlex" version = "1.3.0" @@ -1845,6 +1907,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + [[package]] name = "unicode-ident" version = "1.0.24" diff --git a/REQUIREMENTS.md b/REQUIREMENTS.md index 5605017..bec65bb 100644 --- a/REQUIREMENTS.md +++ b/REQUIREMENTS.md @@ -479,6 +479,9 @@ what a valid business email is. ### req: axum/004 004 Query-string demo endpoints may be migrated to typed handler params from `data-*` attributes or forms. `Query` remains available in normal Axum routes but is not the hemx happy path. +### req: axum/005 +005 hemx-axum exposes the shared JS runtime through a content-hashed script path and immutable runtime response headers. Applications load the hemx-owned path instead of hand-written cache-busting query strings; changing runtime bytes changes the exposed path automatically. + --- ## auth diff --git a/examples/kanban/src/lib.rs b/examples/kanban/src/lib.rs index 2fd29d9..e46ae9c 100644 --- a/examples/kanban/src/lib.rs +++ b/examples/kanban/src/lib.rs @@ -5,9 +5,9 @@ pub mod ui {} mod tests { use super::ui::{board, board_card}; use hemplate::Hemplate; - use scraper::{Html, Selector}; use hemx::IntoEffect; use hemx_test::inspect; + use scraper::{Html, Selector}; #[derive(Hemplate)] #[hemplate = "partials"] diff --git a/examples/kanban/src/main.rs b/examples/kanban/src/main.rs index 96d4332..b8aeccf 100644 --- a/examples/kanban/src/main.rs +++ b/examples/kanban/src/main.rs @@ -6,8 +6,8 @@ use futures_util::{stream, StreamExt}; use hemplate::Hemplate; use hemx::{Html, IntoEffect}; use hemx_axum::{ - interactions, runtime_js, sse, DispatchRegistry, DispatchRejection, EffectResponse, - InteractionRequest, PageRequest, + interactions, runtime_js, runtime_js_path, sse, DispatchRegistry, DispatchRejection, + EffectResponse, InteractionRequest, PageRequest, }; use hemx_kanban_example::ui::board::{self as board}; use hemx_kanban_example::ui::board_card as card_board; @@ -40,6 +40,7 @@ struct Card { #[derive(Hemplate)] struct AppShell { + runtime_src: &'static str, body: Html, } @@ -118,7 +119,7 @@ async fn main() { let app = Router::new() .route("/", get(home).post(interact)) .route("/events", get(events)) - .route("/hemx.js", get(runtime)) + .route(runtime_js_path(), get(runtime)) .with_state(state); let addr = SocketAddr::from(([127, 0, 0, 1], 3001)); @@ -288,7 +289,10 @@ fn page_html(board: &BoardState) -> Html { fn shell(body: Html) -> Html { // req: html_safety/001 req: html_safety/002 req: axum_integration/001 - hemx::page(&AppShell { body }) + hemx::page(&AppShell { + runtime_src: runtime_js_path(), + body, + }) } fn render_options() -> Html { diff --git a/examples/kanban/templates/app_shell.heml b/examples/kanban/templates/app_shell.heml index 93ef206..0b8940e 100644 --- a/examples/kanban/templates/app_shell.heml +++ b/examples/kanban/templates/app_shell.heml @@ -4,7 +4,7 @@ hemx Kanban - +