wip: change assets handling to vite-rs

This commit is contained in:
Alexander Navarro 2025-04-21 20:14:07 -04:00
parent 14a4d9b2b3
commit f5e398c933
5 changed files with 66 additions and 24 deletions

View file

@ -5,8 +5,8 @@
<meta content="width=device-width, initial-scale=1.0" name="viewport"> <meta content="width=device-width, initial-scale=1.0" name="viewport">
<meta content="dark light" name="color-scheme"> <meta content="dark light" name="color-scheme">
<!-- if development --> <!-- if development -->
<script src="http://localhost:21012/@vite/client" type="module"></script> {{ load_vite_script() | safe }}
<link href="http://localhost:21012/frontend/assets/css/style.scss" rel="stylesheet"/> <link href="/assets/css/style.scss" rel="stylesheet"/>
<script src="/assets/js/index.ts" type="module"></script> <script src="/assets/js/index.ts" type="module"></script>
<script src="htmx.org" type="module"></script> <script src="htmx.org" type="module"></script>
<title> <title>

View file

@ -1,8 +1,8 @@
use axum::http::StatusCode; use axum::http::StatusCode;
use axum::{ use axum::{
extract::{Path, State}, extract::{Path, State},
http::{header, HeaderMap, HeaderValue}, http::{header, HeaderMap, HeaderValue}
response::Html, ,
routing::get, routing::get,
Router, Router,
}; };
@ -25,8 +25,7 @@ async fn handle_assets(
State(state): State<AppState>, State(state): State<AppState>,
Path(asset_path): Path<String>, Path(asset_path): Path<String>,
) -> Result<(HeaderMap, String)> { ) -> Result<(HeaderMap, String)> {
let full_path = format!("frontend/assets/{}", asset_path); let asset: ViteFile = state.assets.get_asset(&asset_path).ok_or(Error::HTTP(StatusCode::NOT_FOUND))?;
let asset: ViteFile = state.assets.get_asset(&full_path).ok_or(Error::HTTP(StatusCode::NOT_FOUND))?;
let mut headers = HeaderMap::new(); let mut headers = HeaderMap::new();
headers.insert(header::CONTENT_TYPE, HeaderValue::from_str(&asset.content_type).unwrap()); headers.insert(header::CONTENT_TYPE, HeaderValue::from_str(&asset.content_type).unwrap());
@ -47,21 +46,15 @@ async fn handler_home(
HxRequest(hx_request): HxRequest, HxRequest(hx_request): HxRequest,
mut tx: Tx, mut tx: Tx,
) -> ResultTemplate { ) -> ResultTemplate {
let template = state.assets.get_template("index.html").ok_or(Error::HTTP(StatusCode::NOT_FOUND))?;
let rows = sqlx::query_as::<_, ExampleRow>("select 'Postgres' as database, setting as version, current_database(), current_user, current_timestamp from pg_settings where name = 'server_version'") let rows = sqlx::query_as::<_, ExampleRow>("select 'Postgres' as database, setting as version, current_database(), current_user, current_timestamp from pg_settings where name = 'server_version'")
.fetch_all(&mut tx) .fetch_all(&mut tx)
.await?; .await?;
println!("{:?}", rows);
let content = if hx_request { let content = if hx_request {
template state.assets.render_template_block("index.html", "htmx", context!(rows => rows))?
.eval_to_state(context!(rows => rows))?
.render_block("htmx")?
} else { } else {
template.render(context!(rows => rows))? state.assets.render_template("index.html", context!(rows => rows))?
}; };
Ok(Html(content)) Ok(content)
} }

View file

@ -1,9 +1,16 @@
use minijinja::{path_loader, Environment, Template}; mod template_functions;
use crate::static_assets::template_functions::load_functions;
use crate::ResultTemplate;
use axum::response::Html;
use minijinja::{path_loader, Environment};
use minijinja_autoreload::AutoReloader; use minijinja_autoreload::AutoReloader;
use serde::Serialize;
use vite_rs::{ViteFile, ViteProcess}; use vite_rs::{ViteFile, ViteProcess};
#[derive(vite_rs::Embed)] #[derive(vite_rs::Embed)]
#[root = "."] #[root = "."]
#[dev_server_port = "3001"]
struct Static; struct Static;
pub struct Assets { pub struct Assets {
@ -24,18 +31,20 @@ impl Clone for Assets {
impl Assets { impl Assets {
pub fn new() -> Self { pub fn new() -> Self {
#[allow(unused_mut)] let mut templates = Environment::new(); let mut templates = Environment::new();
load_functions(&mut templates);
templates.set_loader(minijinja::path_loader("frontend/templates"));
let mut _guard = None; let mut _guard = None;
let mut _reloader = None; let mut _reloader = None;
// Load in dev mode // Load in dev mode
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
// templates.set_loader(minijinja::path_loader("frontend/templates"));
_guard = Static::start_dev_server(true); _guard = Static::start_dev_server(true);
_reloader = Some(AutoReloader::new(|notifier| { _reloader = Some(AutoReloader::new(|notifier| {
let template_path = "path/to/templates"; let template_path = "frontend/templates";
let mut env = Environment::new(); let mut env = Environment::new();
load_functions(&mut env);
env.set_loader(path_loader(template_path)); env.set_loader(path_loader(template_path));
notifier.watch_path(template_path, true); notifier.watch_path(template_path, true);
Ok(env) Ok(env)
@ -61,15 +70,36 @@ impl Assets {
Static::get(full_path.as_str()) Static::get(full_path.as_str())
} }
pub fn get_template(&self, path: &str) -> Option<Template> { pub fn render_template<S: Serialize>(&self, path: &str, ctx: S) -> ResultTemplate {
match &self._reloader { let env = match &self._reloader {
None => { None => {
self.templates.get_template(path).ok() &self.templates
} }
Some(reloader) => { Some(reloader) => {
reloader.acquire_env().unwrap().get_template(path).ok() &reloader.acquire_env()?
} }
} };
let result = env.get_template(path)?.render(ctx)?;
Ok(Html(result))
}
pub fn render_template_block<S: Serialize>(&self, path: &str, block: &str, ctx: S) -> ResultTemplate {
let env = match &self._reloader {
None => {
&self.templates
}
Some(reloader) => {
&reloader.acquire_env()?
}
};
let result = env.get_template(path)?
.eval_to_state(ctx)?
.render_block(block)?;
Ok(Html(result))
} }
} }

View file

@ -0,0 +1,16 @@
use minijinja::Environment;
fn load_vite_script() -> &'static str {
#[cfg(debug_assertions)]
{
r#"<script src="http://localhost:3001/@vite/client" type="module"></script>"#
}
#[cfg(not(debug_assertions))]
{
""
}
}
pub(super) fn load_functions(env: &mut Environment) {
env.add_function("load_vite_script", load_vite_script);
}

View file

@ -2,6 +2,9 @@ import {defineConfig} from "vite";
export default defineConfig({ export default defineConfig({
plugins: [], plugins: [],
server: {
port: 3001,
},
build: { build: {
rollupOptions: { rollupOptions: {
input: [ input: [