From 0c987f2923177de88714d4295c0fdafde017aff1 Mon Sep 17 00:00:00 2001 From: Manuel Cillero Date: Sat, 16 Aug 2025 12:15:16 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Mejora=20la?= =?UTF-8?q?=20integraci=C3=B3n=20de=20archivos=20est=C3=A1ticos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Elimina el uso de `include_files!` y sustituye `include_files_service!` por alternativas más completas ofreciadas por `static_files_service!`. --- helpers/pagetop-build/README.md | 26 +++---- helpers/pagetop-build/src/lib.rs | 26 +++---- src/core/extension/all.rs | 8 +-- src/global.rs | 16 +++-- src/html/assets/favicon.rs | 3 +- src/html/assets/javascript.rs | 3 +- src/html/assets/stylesheet.rs | 3 +- src/lib.rs | 3 +- src/prelude.rs | 3 +- src/service.rs | 119 +++++++++++++++++++++++++++++++ 10 files changed, 156 insertions(+), 54 deletions(-) diff --git a/helpers/pagetop-build/README.md b/helpers/pagetop-build/README.md index 5af492b..80d6bba 100644 --- a/helpers/pagetop-build/README.md +++ b/helpers/pagetop-build/README.md @@ -83,41 +83,33 @@ Este código compila el archivo `main.scss` de la carpeta `static` del proyecto, llamado `main_styles` que contiene el archivo `styles.min.css` obtenido. -# 📦 Módulos generados +# 📦 Archivos generados Cada conjunto de recursos [`StaticFilesBundle`] genera un archivo en el directorio estándar [OUT_DIR](https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts) -donde se incluyen los recursos necesarios para compilar el proyecto. Por ejemplo, para -`with_name("guides")` se crea un archivo llamado `guides.rs`. +donde se incluye el código necesario para compilar el proyecto. Por ejemplo, para +`with_name("guides")` se genera un archivo llamado `guides.rs`. -No hay ningún problema en generar más de un conjunto de recursos para cada proyecto. +No hay ningún problema en generar más de un conjunto de recursos para cada proyecto siempre que se +usen nombres diferentes. -Normalmente no habrá que acceder a estos módulos; bastará con incluirlos en el proyecto con -[`include_files!`](https://docs.rs/pagetop/latest/pagetop/macro.include_files.html), y luego con -[`include_files_service!`](https://docs.rs/pagetop/latest/pagetop/macro.include_files_service.html) -configurar un servicio web para servir los recursos desde la ruta indicada: +Normalmente no habrá que acceder a estos módulos; sólo declarar el nombre del conjunto de recursos +en [`static_files_service!`](https://docs.rs/pagetop/latest/pagetop/macro.static_files_service.html) +para configurar un servicio web que sirva los archivos desde la ruta indicada. Por ejemplo: ```rust,ignore use pagetop::prelude::*; -include_files!(guides); - pub struct MyExtension; impl Extension for MyExtension { // Servicio web que publica los recursos de `guides` en `/ruta/a/guides`. fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { - include_files_service!(scfg, guides => "/ruta/a/guides"); + static_files_service!(scfg, guides => "/ruta/a/guides"); } } ``` -También se puede asignar el conjunto de recursos a una variable global; p.ej. `GUIDES`: - -```rust,ignore -include_files!(GUIDES => guides); -``` - # 🚧 Advertencia diff --git a/helpers/pagetop-build/src/lib.rs b/helpers/pagetop-build/src/lib.rs index 09dec42..c6e7236 100644 --- a/helpers/pagetop-build/src/lib.rs +++ b/helpers/pagetop-build/src/lib.rs @@ -84,40 +84,32 @@ Este código compila el archivo `main.scss` de la carpeta `static` del proyecto, llamado `main_styles` que contiene el archivo `styles.min.css` obtenido. -# 📦 Módulos generados +# 📦 Archivos generados Cada conjunto de recursos [`StaticFilesBundle`] genera un archivo en el directorio estándar [OUT_DIR](https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts) -donde se incluyen los recursos necesarios para compilar el proyecto. Por ejemplo, para -`with_name("guides")` se crea un archivo llamado `guides.rs`. +donde se incluye el código necesario para compilar el proyecto. Por ejemplo, para +`with_name("guides")` se genera un archivo llamado `guides.rs`. -No hay ningún problema en generar más de un conjunto de recursos para cada proyecto. +No hay ningún problema en generar más de un conjunto de recursos para cada proyecto siempre que se +usen nombres diferentes. -Normalmente no habrá que acceder a estos módulos; bastará con incluirlos en el proyecto con -[`include_files!`](https://docs.rs/pagetop/latest/pagetop/macro.include_files.html), y luego con -[`include_files_service!`](https://docs.rs/pagetop/latest/pagetop/macro.include_files_service.html) -configurar un servicio web para servir los recursos desde la ruta indicada: +Normalmente no habrá que acceder a estos módulos; sólo declarar el nombre del conjunto de recursos +en [`static_files_service!`](https://docs.rs/pagetop/latest/pagetop/macro.static_files_service.html) +para configurar un servicio web que sirva los archivos desde la ruta indicada. Por ejemplo: ```rust,ignore use pagetop::prelude::*; -include_files!(guides); - pub struct MyExtension; impl Extension for MyExtension { // Servicio web que publica los recursos de `guides` en `/ruta/a/guides`. fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { - include_files_service!(scfg, guides => "/ruta/a/guides"); + static_files_service!(scfg, guides => "/ruta/a/guides"); } } ``` - -También se puede asignar el conjunto de recursos a una variable global; p.ej. `GUIDES`: - -```rust,ignore -include_files!(GUIDES => guides); -``` */ #![doc( diff --git a/src/core/extension/all.rs b/src/core/extension/all.rs index 93b5c4b..a243778 100644 --- a/src/core/extension/all.rs +++ b/src/core/extension/all.rs @@ -1,7 +1,7 @@ use crate::core::action::add_action; use crate::core::extension::ExtensionRef; use crate::core::theme::all::THEMES; -use crate::{global, include_files, include_files_service, service, trace}; +use crate::{global, service, static_files_service, trace}; use parking_lot::RwLock; @@ -125,8 +125,6 @@ pub fn initialize_extensions() { // CONFIGURA LOS SERVICIOS ************************************************************************* -include_files!(assets); - pub fn configure_services(scfg: &mut service::web::ServiceConfig) { // Sólo compila durante el desarrollo, para evitar errores 400 en la traza de eventos. #[cfg(debug_assertions)] @@ -140,7 +138,5 @@ pub fn configure_services(scfg: &mut service::web::ServiceConfig) { extension.configure_service(scfg); } - include_files_service!( - scfg, assets => "/", [&global::SETTINGS.dev.pagetop_project_dir, "static"] - ); + static_files_service!(scfg, [&global::SETTINGS.dev.pagetop_static_dir, assets] => "/"); } diff --git a/src/global.rs b/src/global.rs index ea659b8..8a03589 100644 --- a/src/global.rs +++ b/src/global.rs @@ -13,7 +13,7 @@ include_config!(SETTINGS: Settings => [ "app.startup_banner" => "Slant", // [dev] - "dev.pagetop_project_dir" => "", + "dev.pagetop_static_dir" => "", // [log] "log.enabled" => true, @@ -68,11 +68,15 @@ pub struct App { #[derive(Debug, Deserialize)] /// Sección `[Dev]` de la configuración. Forma parte de [`Settings`]. pub struct Dev { - /// Los archivos estáticos requeridos por `PageTop` se integran por defecto en el binario - /// ejecutable. Sin embargo, durante el desarrollo puede resultar útil servirlos desde su propio - /// directorio para evitar recompilar cada vez que se modifican. En ese caso, este ajuste debe - /// indicar la ruta absoluta al directorio raíz del proyecto. - pub pagetop_project_dir: String, + /// Directorio desde el que servir los archivos estáticos de `PageTop`. + /// + /// Por defecto, los archivos se integran en el binario de la aplicación. Si aquí se indica una + /// ruta válida, ya sea absoluta o relativa al directorio del proyecto o del binario en + /// ejecución, se servirán desde el sistema de ficheros en su lugar. Esto es especialmente útil + /// en desarrollo, ya que evita recompilar el proyecto por cambios en estos archivos. + /// + /// Si la cadena está vacía, se ignora este ajuste. + pub pagetop_static_dir: String, } #[derive(Debug, Deserialize)] diff --git a/src/html/assets/favicon.rs b/src/html/assets/favicon.rs index 2af0173..1a8b29e 100644 --- a/src/html/assets/favicon.rs +++ b/src/html/assets/favicon.rs @@ -12,8 +12,7 @@ use crate::AutoDefault; /// /// > **Nota** /// > Los archivos de los iconos deben estar disponibles en el servidor web de la aplicación. Pueden -/// > incluirse en el proyecto utilizando [`include_files!`](crate::include_files) y servirse con -/// > [`include_files_service!`](crate::include_files_service). +/// > servirse usando [`static_files_service!`](crate::static_files_service). /// /// # Ejemplo /// diff --git a/src/html/assets/javascript.rs b/src/html/assets/javascript.rs index 604e85a..db5754e 100644 --- a/src/html/assets/javascript.rs +++ b/src/html/assets/javascript.rs @@ -30,8 +30,7 @@ enum Source { /// /// > **Nota** /// > Los archivos de los *scripts* deben estar disponibles en el servidor web de la aplicación. -/// > Pueden incluirse en el proyecto utilizando [`include_files!`](crate::include_files) y servirse -/// > con [`include_files_service!`](crate::include_files_service). +/// > Pueden servirse usando [`static_files_service!`](crate::static_files_service). /// /// # Ejemplo /// diff --git a/src/html/assets/stylesheet.rs b/src/html/assets/stylesheet.rs index 72a79a1..bb60b01 100644 --- a/src/html/assets/stylesheet.rs +++ b/src/html/assets/stylesheet.rs @@ -55,8 +55,7 @@ impl TargetMedia { /// /// > **Nota** /// > Las hojas de estilo CSS deben estar disponibles en el servidor web de la aplicación. Pueden -/// > incluirse en el proyecto utilizando [`include_files!`](crate::include_files) y servirse con -/// > [`include_files_service!`](crate::include_files_service). +/// > servirse usando [`static_files_service!`](crate::static_files_service). /// /// # Ejemplo /// diff --git a/src/lib.rs b/src/lib.rs index d50a448..90ea462 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -103,7 +103,8 @@ pub use pagetop_macros::{builder_fn, html, main, test, AutoDefault}; pub use pagetop_statics::{resource, StaticResource}; -/// Conjunto de recursos asociados a `$STATIC` en [`include_files!`](crate::include_files). +/// Contenedor para un conjunto de recursos embebidos. +#[derive(AutoDefault)] pub struct StaticResources { bundle: HashMap<&'static str, StaticResource>, } diff --git a/src/prelude.rs b/src/prelude.rs index 6bacaf3..9072dec 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -15,7 +15,8 @@ pub use crate::include_config; // crate::locale pub use crate::include_locales; // crate::service -pub use crate::{include_files, include_files_service}; +#[allow(deprecated)] +pub use crate::{include_files, include_files_service, static_files_service}; // crate::core::action pub use crate::actions_boxed; diff --git a/src/service.rs b/src/service.rs index 47f1420..288e1eb 100644 --- a/src/service.rs +++ b/src/service.rs @@ -15,6 +15,9 @@ pub use pagetop_statics::ResourceFiles; #[doc(hidden)] pub use actix_web::test; +/// **Obsoleto desde la versión 0.3.0**: usar [`static_files_service!`](crate::static_files_service) +/// en su lugar. +/// /// Incluye en código un conjunto de recursos previamente preparado con `build.rs`. /// /// # Formas de uso @@ -39,6 +42,7 @@ pub use actix_web::test; /// /// include_files!(STATIC_ASSETS => assets); /// ``` +#[deprecated(since = "0.3.0", note = "Use `static_files_service!` instead")] #[macro_export] macro_rules! include_files { // Forma 1: incluye un conjunto de recursos por nombre. @@ -63,6 +67,9 @@ macro_rules! include_files { }; } +/// **Obsoleto desde la versión 0.3.0**: usar [`static_files_service!`](crate::static_files_service) +/// en su lugar. +/// /// Configura un servicio web para publicar los recursos embebidos con [`include_files!`]. /// /// El código expandido de la macro decide durante el arranque de la aplicación si debe servir los @@ -104,6 +111,7 @@ macro_rules! include_files { /// // También desde el directorio actual de ejecución. /// include_files_service!(cfg, assets => "/public", ["", "static"]); /// ``` +#[deprecated(since = "0.3.0", note = "Use `static_files_service!` instead")] #[macro_export] macro_rules! include_files_service { ( $scfg:ident, $bundle:ident => $route:expr $(, [$root:expr, $relative:expr])? ) => {{ @@ -137,3 +145,114 @@ macro_rules! include_files_service { } }}; } + +/// Configura un servicio web para publicar archivos estáticos. +/// +/// La macro ofrece tres modos para configurar el servicio: +/// +/// - **Sistema de ficheros o embebido** (`[$path, $bundle]`): trata de servir los archivos desde +/// `$path`; y si es una cadena vacía, no existe o no es un directorio, entonces usará el conjunto +/// de recursos `$bundle` integrado en el binario. +/// - **Sólo embebido** (`[$bundle]`): sirve siempre desde el conjunto de recursos `$bundle` +/// integrado en el binario. +/// - **Sólo sistema de ficheros** (`$path`): sin usar corchetes, sirve únicamente desde el sistema +/// de ficheros si existe; en otro caso no registra el servicio. +/// +/// # Argumentos +/// +/// * `$scfg` – Instancia de [`ServiceConfig`](crate::service::web::ServiceConfig) donde aplicar la +/// configuración. +/// * `$path` – Ruta al directorio local con los archivos estáticos. +/// * `$bundle` – Nombre del conjunto de recursos que esta macro integra en el binario. +/// * `$route` – Ruta URL base desde la que se servirán los archivos. +/// +/// # Ejemplos +/// +/// ```rust,ignore +/// use pagetop::prelude::*; +/// +/// pub struct MyExtension; +/// +/// impl Extension for MyExtension { +/// fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { +/// // Forma 1) Sistema de ficheros o embebido. +/// static_files_service!(scfg, ["/var/www/static", assets] => "/public"); +/// +/// // Forma 2) Siempre embebido. +/// static_files_service!(scfg, [assets] => "/public"); +/// +/// // Forma 3) Sólo sistema de ficheros (no requiere `assets`). +/// static_files_service!(scfg, "/var/www/static" => "/public"); +/// } +/// } +/// ``` +#[macro_export] +macro_rules! static_files_service { + // Forma 1: primero intenta servir desde el sistema de ficheros; si falla, sirve embebido. + ( $scfg:ident, [$path:expr, $bundle:ident] => $route:expr $(,)? ) => {{ + let span = $crate::trace::debug_span!( + "Configuring static files (file system or embedded)", + mode = "fs_or_embedded", + route = $route, + ); + let _ = span.in_scope(|| { + let mut serve_embedded: bool = true; + if !::std::path::Path::new(&$path).as_os_str().is_empty() { + if let Ok(absolute) = $crate::util::resolve_absolute_dir($path) { + $scfg.service($crate::service::ActixFiles::new($route, absolute)); + serve_embedded = false; + } + } + if serve_embedded { + $crate::util::paste! { + mod [] { + include!(concat!(env!("OUT_DIR"), "/", stringify!($bundle), ".rs")); + } + $scfg.service($crate::service::ResourceFiles::new( + $route, + []::$bundle(), + )); + } + } + }); + }}; + // Forma 2: sirve siempre embebido. + ( $scfg:ident, [$bundle:ident] => $route:expr $(,)? ) => {{ + let span = $crate::trace::debug_span!( + "Configuring static files (using embedded only)", + mode = "embedded", + route = $route, + ); + let _ = span.in_scope(|| { + $crate::util::paste! { + mod [] { + include!(concat!(env!("OUT_DIR"), "/", stringify!($bundle), ".rs")); + } + $scfg.service($crate::service::ResourceFiles::new( + $route, + []::$bundle(), + )); + } + }); + }}; + // Forma 3: intenta servir desde el sistema de ficheros. + ( $scfg:ident, $path:expr => $route:expr $(,)? ) => {{ + let span = $crate::trace::debug_span!( + "Configuring static files (file system only)", + mode = "fs", + route = $route, + ); + let _ = span.in_scope(|| match $crate::util::resolve_absolute_dir($path) { + Ok(absolute) => { + $scfg.service($crate::service::ActixFiles::new($route, absolute)); + } + Err(e) => { + $crate::trace::warn!( + "Static dir not found or invalid for route `{}`: {:?} ({e})", + $route, + $path, + ); + } + }); + }}; +}