Compare commits

...

2 commits

Author SHA1 Message Date
2c52af4b9d ♻️ (statics): Renombra StaticResource a StaticFile
Clarifica la distinción entre un fichero estático individual
(`StaticFile`) y el contenedor de varios ficheros (`StaticResources`).
2026-06-01 22:02:23 +02:00
b1ce79c78f ♻️ Migra soporte HTTP de actix-web a axum en maud 2026-06-01 02:14:07 +02:00
8 changed files with 310 additions and 1379 deletions

1572
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -11,30 +11,25 @@
</div> </div>
## 🧭 Sobre PageTop ## Sobre PageTop
[PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la web [PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la web
clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles y clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles y
configurables, basadas en HTML, CSS y JavaScript. configurables, basadas en HTML, CSS y JavaScript.
## Descripción general
## 🗺️ Descripción general
Este *crate* permite incluir archivos estáticos en el ejecutable de las aplicaciones PageTop para Este *crate* permite incluir archivos estáticos en el ejecutable de las aplicaciones PageTop para
servirlos de forma eficiente vía web, con detección de cambios que optimizan el tiempo de servirlos de forma eficiente vía web, con detección de cambios que optimizan el tiempo de
compilación. compilación.
## Créditos
## 📚 Créditos Para ello, adapta el código de [static-files](https://crates.io/crates/static_files) (versión
[0.2.5](https://github.com/static-files-rs/static-files/tree/v0.2.5)) desarrollado por
Para ello, adapta el código de los *crates* [static-files](https://crates.io/crates/static_files) [Alexander Korolev](https://crates.io/users/kilork), bajo licencia MIT/Apache 2.0. La implementación
(versión [0.2.5](https://github.com/static-files-rs/static-files/tree/v0.2.5)) y se integra en PageTop para evitar que cada proyecto tenga que declarar `static-files` manualmente
[actix-web-static-files](https://crates.io/crates/actix_web_static_files) (versión como dependencia en su `Cargo.toml`.
[4.0.1](https://github.com/kilork/actix-web-static-files/tree/v4.0.1)), desarrollados ambos por
[Alexander Korolev](https://crates.io/users/kilork).
Estas implementaciones se integran en PageTop para evitar que cada proyecto tenga que declarar
`static-files` manualmente como dependencia en su `Cargo.toml`.
## 🚧 Advertencia ## 🚧 Advertencia

View file

@ -26,14 +26,11 @@ compilación.
## Créditos ## Créditos
Para ello, adapta el código de los *crates* [static-files](https://crates.io/crates/static_files) Para ello, adapta el código de [static-files](https://crates.io/crates/static_files) (versión
(versión [0.2.5](https://github.com/static-files-rs/static-files/tree/v0.2.5)) y [0.2.5](https://github.com/static-files-rs/static-files/tree/v0.2.5)) desarrollado por
[actix-web-static-files](https://crates.io/crates/actix_web_static_files) (versión [Alexander Korolev](https://crates.io/users/kilork), bajo licencia MIT/Apache 2.0. La implementación
[4.0.1](https://github.com/kilork/actix-web-static-files/tree/v4.0.1)), desarrollados ambos por se integra en PageTop para evitar que cada proyecto tenga que declarar `static-files` manualmente
[Alexander Korolev](https://crates.io/users/kilork). como dependencia en su `Cargo.toml`.
Estas implementaciones se integran en PageTop para evitar que cada proyecto tenga que declarar
`static-files` manualmente como dependencia en su `Cargo.toml`.
*/ */
#![doc(test(no_crate_inject))] #![doc(test(no_crate_inject))]
@ -44,7 +41,7 @@ Estas implementaciones se integran en PageTop para evitar que cada proyecto teng
/// Resource definition and single module based generation. /// Resource definition and single module based generation.
pub mod resource; pub mod resource;
pub use resource::Resource as StaticResource; pub use resource::Resource as StaticFile;
mod resource_dir; mod resource_dir;
pub use resource_dir::{ResourceDir, resource_dir}; pub use resource_dir::{ResourceDir, resource_dir};

View file

@ -93,9 +93,9 @@ pub fn generate_resources<P: AsRef<Path>, G: AsRef<Path>>(
/// ```rust /// ```rust
/// use std::collections::HashMap; /// use std::collections::HashMap;
/// ///
/// use pagetop_statics::StaticResource; /// use pagetop_statics::StaticFile;
/// ///
/// fn generate_mapping() -> HashMap<&'static str, StaticResource> { /// fn generate_mapping() -> HashMap<&'static str, StaticFile> {
/// include!(concat!(env!("OUT_DIR"), "/generated_mapping.rs")) /// include!(concat!(env!("OUT_DIR"), "/generated_mapping.rs"))
/// } /// }
/// ///
@ -221,7 +221,7 @@ pub(crate) fn generate_function_header<F: Write>(
) -> io::Result<()> { ) -> io::Result<()> {
writeln!( writeln!(
f, f,
"#[allow(clippy::unreadable_literal)] pub fn {fn_name}() -> ::std::collections::HashMap<&'static str, ::{crate_name}::StaticResource> {{", "#[allow(clippy::unreadable_literal)] pub fn {fn_name}() -> ::std::collections::HashMap<&'static str, ::{crate_name}::StaticFile> {{",
) )
} }

View file

@ -116,7 +116,7 @@ where
writeln!( writeln!(
module_file, module_file,
" "
use ::{crate_name}::StaticResource; use ::{crate_name}::StaticFile;
use ::std::collections::HashMap;" use ::std::collections::HashMap;"
)?; )?;
@ -177,7 +177,7 @@ fn create_set_module_file(module_dir: &Path, module_index: usize) -> io::Result<
"#[allow(clippy::wildcard_imports)] "#[allow(clippy::wildcard_imports)]
use super::*; use super::*;
#[allow(clippy::unreadable_literal)] #[allow(clippy::unreadable_literal)]
pub(crate) fn generate({DEFAULT_VARIABLE_NAME}: &mut HashMap<&'static str, StaticResource>) {{", pub(crate) fn generate({DEFAULT_VARIABLE_NAME}: &mut HashMap<&'static str, StaticFile>) {{",
)?; )?;
Ok(set_module) Ok(set_module)

View file

@ -270,46 +270,14 @@ impl<T: Default> Default for PreEscaped<T> {
/// ``` /// ```
pub const DOCTYPE: PreEscaped<&'static str> = PreEscaped("<!DOCTYPE html>"); pub const DOCTYPE: PreEscaped<&'static str> = PreEscaped("<!DOCTYPE html>");
mod actix_support { mod axum_support {
extern crate alloc; use super::PreEscaped;
use axum::response::{Html, IntoResponse, Response};
use core::{ /// Convierte un bloque de [`Markup`](super::Markup) en una respuesta HTTP HTML 200.
pin::Pin, impl IntoResponse for PreEscaped<String> {
task::{Context, Poll}, fn into_response(self) -> Response {
}; Html(self.0).into_response()
use crate::html::PreEscaped;
use actix_web::{
body::{BodySize, MessageBody},
http::header,
web::Bytes,
HttpRequest, HttpResponse, Responder,
};
use alloc::string::String;
impl MessageBody for PreEscaped<String> {
type Error = <String as MessageBody>::Error;
fn size(&self) -> BodySize {
self.0.size()
}
fn poll_next(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Bytes, Self::Error>>> {
Pin::new(&mut self.0).poll_next(cx)
}
}
impl Responder for PreEscaped<String> {
type Body = String;
fn respond_to(self, _req: &HttpRequest) -> HttpResponse<Self::Body> {
HttpResponse::Ok()
.content_type(header::ContentType::html())
.message_body(self.0)
.unwrap()
} }
} }
} }
@ -318,7 +286,7 @@ mod actix_support {
pub mod html_private { pub mod html_private {
extern crate alloc; extern crate alloc;
use super::{display, Render}; use super::{Render, display};
use alloc::string::String; use alloc::string::String;
use core::fmt::Display; use core::fmt::Display;

View file

@ -134,26 +134,26 @@ pub const PAGETOP_VERSION: &str = env!("CARGO_PKG_VERSION");
pub use pagetop_macros::{AutoDefault, builder_fn, html, main, test}; pub use pagetop_macros::{AutoDefault, builder_fn, html, main, test};
pub use pagetop_statics::{StaticResource, resource}; pub use pagetop_statics::{StaticFile, resource};
pub use getter_methods::Getters; pub use getter_methods::Getters;
/// Contenedor para un conjunto de recursos embebidos. /// Contenedor para un conjunto de recursos embebidos.
#[derive(AutoDefault)] #[derive(AutoDefault)]
pub struct StaticResources { pub struct StaticResources {
bundle: HashMap<&'static str, StaticResource>, bundle: HashMap<&'static str, StaticFile>,
} }
impl StaticResources { impl StaticResources {
/// Crea un contenedor para un conjunto de recursos generado por `build.rs` (consultar /// Crea un contenedor para un conjunto de recursos generado por `build.rs` (consultar
/// [`pagetop_build`](https://docs.rs/pagetop-build)). /// [`pagetop_build`](https://docs.rs/pagetop-build)).
pub fn new(bundle: HashMap<&'static str, StaticResource>) -> Self { pub fn new(bundle: HashMap<&'static str, StaticFile>) -> Self {
Self { bundle } Self { bundle }
} }
} }
impl Deref for StaticResources { impl Deref for StaticResources {
type Target = HashMap<&'static str, StaticResource>; type Target = HashMap<&'static str, StaticFile>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.bundle &self.bundle

View file

@ -5,6 +5,8 @@
//! el módulo `http` para tipos de bajo nivel como `StatusCode`, `HeaderName` o `Method`. También //! el módulo `http` para tipos de bajo nivel como `StatusCode`, `HeaderName` o `Method`. También
//! ofrece utilidades para servir archivos estáticos, [`ServeDir`] y [`ServeEmbedded`]. //! ofrece utilidades para servir archivos estáticos, [`ServeDir`] y [`ServeEmbedded`].
use crate::StaticFile;
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::Infallible; use std::convert::Infallible;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
@ -25,10 +27,6 @@ pub use axum::response::{IntoResponse, Response};
// Operaciones HTTP para registrar rutas. // Operaciones HTTP para registrar rutas.
pub use axum::routing::{delete, get, patch, post, put}; pub use axum::routing::{delete, get, patch, post, put};
// Servicios para archivos estáticos (disco y embebidos).
pub use pagetop_statics::StaticResource;
pub use tower_http::services::ServeDir;
// **< HttpRequest >******************************************************************************** // **< HttpRequest >********************************************************************************
/// Representa una petición HTTP. /// Representa una petición HTTP.
@ -91,6 +89,11 @@ impl<S: Send + Sync> FromRequestParts<S> for HttpRequest {
} }
} }
// **< ServeDir >***********************************************************************************
// Servicio para archivos estáticos en disco.
pub use tower_http::services::ServeDir;
// **< ServeEmbedded >****************************************************************************** // **< ServeEmbedded >******************************************************************************
/// Servicio para archivos estáticos embebidos en el binario. /// Servicio para archivos estáticos embebidos en el binario.
@ -104,12 +107,12 @@ impl<S: Send + Sync> FromRequestParts<S> for HttpRequest {
/// recursos con un [`Arc`](std::sync::Arc) para evitar copias innecesarias. /// recursos con un [`Arc`](std::sync::Arc) para evitar copias innecesarias.
#[derive(Clone)] #[derive(Clone)]
pub struct ServeEmbedded { pub struct ServeEmbedded {
files: std::sync::Arc<HashMap<&'static str, StaticResource>>, files: std::sync::Arc<HashMap<&'static str, StaticFile>>,
} }
impl ServeEmbedded { impl ServeEmbedded {
/// Crea un nuevo servicio a partir del mapa de recursos embebidos generado por `build.rs`. /// Crea un nuevo servicio a partir del mapa de recursos embebidos generado por `build.rs`.
pub fn new(files: HashMap<&'static str, StaticResource>) -> Self { pub fn new(files: HashMap<&'static str, StaticFile>) -> Self {
Self { Self {
files: std::sync::Arc::new(files), files: std::sync::Arc::new(files),
} }