Added JS hashes for better browser caching

master
Wynd 2025-06-25 13:44:08 +03:00
parent 630439bc48
commit fd33426219
14 changed files with 198 additions and 94 deletions

View File

@ -11,6 +11,7 @@ toml = "0.8"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
itertools = "0.14"
blake3 = "1.8"
[features]
default = ["bbs", "ddd", "kh3", "kh2", "kh1"]

View File

@ -0,0 +1,7 @@
import {
kindFilter,
showOnlyTracked,
track,
} from "./modules/common/mat-kind-filter.js";
Object.assign(window, { track });

View File

@ -1,13 +1,14 @@
use std::collections::HashMap;
use std::{collections::HashMap, sync::OnceLock};
use ability::Ability;
use askama::Template;
use blake3::Hash;
use command::Command;
use finisher::Finisher;
use itertools::Itertools;
use serde::Deserialize;
use crate::create_file;
use crate::{RuntimeModule, create_file, create_hashes};
mod ability;
mod command;
@ -17,6 +18,7 @@ mod melding;
const ABILITIES_PATH: &str = "./input/bbs/abilities.json";
const FINISHERS_PATH: &str = "./input/bbs/finish-commands.json";
const COMMANDS_PATH: &str = "./input/bbs/commands.json";
static JS_HASH: OnceLock<Hash> = OnceLock::new();
#[derive(Debug, Deserialize, PartialEq, Eq)]
enum Character {
@ -35,7 +37,10 @@ struct CommandsTemplate {
pub crystals: Vec<String>,
}
pub fn init() {
pub struct Module;
impl RuntimeModule for Module {
fn start_module() {
tracing::info!("Loading abilities data from {}", ABILITIES_PATH);
let abilities_str = std::fs::read_to_string(ABILITIES_PATH).unwrap();
let abilities = serde_json::from_str::<Vec<Ability>>(&abilities_str).unwrap();
@ -67,4 +72,9 @@ pub fn init() {
let melding_template = CommandsTemplate { commands, crystals };
create_file("./out/bbs", "melding", melding_template.render().unwrap()).unwrap();
}
fn get_js_hash() -> String {
JS_HASH.get_or_init(|| create_hashes("bbs")).to_string()
}
}

View File

@ -1,8 +1,10 @@
use std::path::PathBuf;
use std::sync::OnceLock;
use crate::create_file;
use crate::ddd::ability::AbilityType;
use crate::{RuntimeModule, create_file, create_hashes};
use askama::Template;
use blake3::Hash;
use board::Board;
mod ability;
@ -11,6 +13,7 @@ mod board_position;
mod route;
const ABILITIES_PATH: &str = "./input/ddd/abilities";
static JS_HASH: OnceLock<Hash> = OnceLock::new();
#[derive(Template)]
#[template(path = "pages/ddd/boards.html")]
@ -18,7 +21,10 @@ struct AbilitiesTemplate {
pub boards: Vec<Board>,
}
pub fn init() {
pub struct Module;
impl RuntimeModule for Module {
fn start_module() {
tracing::info!("Loading ability boards data from {}", ABILITIES_PATH);
let mut boards: Vec<Board> = vec![];
// Loading multiple files into one vector due to the size of each board
@ -42,7 +48,6 @@ pub fn init() {
board.init_stats();
board.init_ability_help();
// dbg!(&board);
boards.push(board);
}
boards.sort_by(|a, b| a.order.cmp(&b.order));
@ -51,4 +56,9 @@ pub fn init() {
let boards_template = AbilitiesTemplate { boards };
create_file("./out/ddd", "boards", boards_template.render().unwrap()).unwrap();
}
fn get_js_hash() -> String {
JS_HASH.get_or_init(|| create_hashes("ddd")).to_string()
}
}

View File

@ -1,14 +1,16 @@
use std::path::PathBuf;
use std::sync::OnceLock;
use askama::Template;
use blake3::Hash;
use crate::{common::materials::MaterialDrops, create_file};
use crate::{RuntimeModule, common::materials::MaterialDrops, create_file, create_hashes};
const MATERIAL_KINDS: &[&str] = &[
"lucid", "spirit", "power", "blaze", "frost", "thunder", "shiny", "bright", "mystery", "gale",
"mythril",
];
const DROPS_PATH: &str = "./input/kh1/drops";
static JS_HASH: OnceLock<Hash> = OnceLock::new();
#[derive(Template)]
#[template(path = "pages/kh1/drops.html")]
@ -16,7 +18,10 @@ struct DropsTemplate {
pub drops: Vec<MaterialDrops>,
}
pub fn init() {
pub struct Module;
impl RuntimeModule for Module {
fn start_module() {
tracing::info!("Loading enemy drops data from {}", DROPS_PATH);
let drops = MaterialDrops::import(DROPS_PATH);
@ -24,4 +29,9 @@ pub fn init() {
let drops_template = DropsTemplate { drops };
create_file("./out/kh1", "drops", drops_template.render().unwrap()).unwrap();
}
fn get_js_hash() -> String {
JS_HASH.get_or_init(|| create_hashes("kh1")).to_string()
}
}

View File

@ -1,8 +1,9 @@
use std::path::PathBuf;
use std::sync::OnceLock;
use askama::Template;
use blake3::Hash;
use crate::{common::materials::MaterialDrops, create_file};
use crate::{RuntimeModule, common::materials::MaterialDrops, create_file, create_hashes};
const MATERIAL_KINDS: &[&str] = &[
"blazing",
@ -19,6 +20,7 @@ const MATERIAL_KINDS: &[&str] = &[
"twilight",
];
const DROPS_PATH: &str = "./input/kh2/drops";
static JS_HASH: OnceLock<Hash> = OnceLock::new();
#[derive(Template)]
#[template(path = "pages/kh2/drops.html")]
@ -26,7 +28,10 @@ struct DropsTemplate {
pub drops: Vec<MaterialDrops>,
}
pub fn init() {
pub struct Module;
impl RuntimeModule for Module {
fn start_module() {
tracing::info!("Loading enemy drops data from {}", DROPS_PATH);
let drops = MaterialDrops::import(DROPS_PATH);
@ -34,4 +39,9 @@ pub fn init() {
let drops_template = DropsTemplate { drops };
create_file("./out/kh2", "drops", drops_template.render().unwrap()).unwrap();
}
fn get_js_hash() -> String {
JS_HASH.get_or_init(|| create_hashes("kh2")).to_string()
}
}

View File

@ -1,11 +1,15 @@
use std::sync::OnceLock;
use askama::Template;
use blake3::Hash;
use food::Recipes;
use crate::create_file;
use crate::{RuntimeModule, create_file, create_hashes};
mod food;
const RECIPES_PATH: &str = "./input/kh3/recipes.toml";
static JS_HASH: OnceLock<Hash> = OnceLock::new();
#[derive(Template)]
#[template(path = "pages/kh3/food-sim.html")]
@ -13,7 +17,10 @@ struct RecipesTemplate {
pub recipes: Recipes,
}
pub fn init() {
pub struct Module;
impl RuntimeModule for Module {
fn start_module() {
tracing::info!("Loading recipes data from {}", RECIPES_PATH);
let recipes_str = std::fs::read_to_string(RECIPES_PATH).unwrap();
let recipes = toml::from_str::<Recipes>(&recipes_str).unwrap();
@ -22,4 +29,9 @@ pub fn init() {
let food_template = RecipesTemplate { recipes };
create_file("./out/kh3", "food-sim", food_template.render().unwrap()).unwrap();
}
fn get_js_hash() -> String {
JS_HASH.get_or_init(|| create_hashes("kh3")).to_string()
}
}

View File

@ -1,6 +1,9 @@
#![allow(dead_code)]
use std::{fs, path::PathBuf};
use askama::Template;
use blake3::{Hash, Hasher};
use tracing_subscriber::EnvFilter;
mod common;
@ -22,6 +25,12 @@ mod kh3;
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub trait RuntimeModule {
fn start_module();
fn get_js_hash() -> String;
}
#[derive(Template)]
#[template(path = "pages/index.html")]
struct IndexTemplate {}
@ -43,19 +52,54 @@ fn main() {
.unwrap();
#[cfg(feature = "bbs")]
bbs::init();
start_module::<bbs::Module>();
#[cfg(feature = "ddd")]
ddd::init();
start_module::<ddd::Module>();
#[cfg(feature = "kh1")]
kh1::init();
start_module::<kh1::Module>();
#[cfg(feature = "kh2")]
kh2::init();
start_module::<kh2::Module>();
#[cfg(feature = "kh3")]
kh3::init();
start_module::<kh3::Module>();
}
fn start_module<M: RuntimeModule>() {
M::start_module();
}
fn create_hashes(module: &str) -> Hash {
let mut hasher = blake3::Hasher::new();
hash_file(format!("./public/scripts/{module}.js").into(), &mut hasher);
hash_files_in_dir("./public/scripts/modules/common".into(), &mut hasher);
hash_files_in_dir(
format!("./public/scripts/modules/{module}").into(),
&mut hasher,
);
hasher.finalize()
}
fn hash_files_in_dir(path: PathBuf, hasher: &mut Hasher) {
if let Ok(paths) = fs::read_dir(path) {
for path in paths.flatten() {
let path = path.path();
if path.metadata().is_ok_and(|p| p.is_dir()) {
hash_files_in_dir(path, hasher);
continue;
}
hash_file(path, hasher);
}
}
}
fn hash_file(path: PathBuf, hasher: &mut Hasher) {
if let Ok(file) = fs::read(path) {
hasher.update(&file);
}
}
fn create_file(dir: &str, file: &str, buf: String) -> std::io::Result<()> {

View File

@ -4,7 +4,7 @@
{% block head %}
<style> {% include "components/bbs/style.css" %}</style>
<script type="module" src="/public/scripts/bbs.js"></script>
<script type="module" src="/public/scripts/bbs.js?v={{Module::get_js_hash()}}"></script>
{% endblock %}
{% block content %}

View File

@ -5,15 +5,15 @@
{% block head %}
<style>{% include "components/kh2/style.css" %}</style>
<script type="module" src="/public/scripts/kh1.js?v={{Module::get_js_hash()}}"></script>
{% endblock %}
{% block content %}
{#
{% include "components/kh2/only-tracked-filter.html" %}
{% include "components/common/only-tracked-filter.html" %}
<br />
{% include "components/kh2/kind-filters.html" %}
{% include "components/common/kind-filters.html" %}
<br />
#}
{% for category in drops %}
{% call macros::drop("shard") %}
{% call macros::drop("stone") %}

View File

@ -5,13 +5,13 @@
{% block head %}
<style>{% include "components/kh2/style.css" %}</style>
<script type="module" src="/public/scripts/kh2.js"></script>
<script type="module" src="/public/scripts/kh2.js?v={{Module::get_js_hash()}}"></script>
{% endblock %}
{% block content %}
{% include "components/kh2/only-tracked-filter.html" %}
{% include "components/common/only-tracked-filter.html" %}
<br />
{% include "components/kh2/kind-filters.html" %}
{% include "components/common/kind-filters.html" %}
<br />
{% for category in drops %}

View File

@ -4,7 +4,7 @@
{% block head %}
<style>{% include "components/kh3/style.css" %}</style>
<script type="module" src="/public/scripts/kh3.js"></script>
<script type="module" src="/public/scripts/kh3.js?v={{Module::get_js_hash()}}"></script>
{% endblock %}
{% block content %}