add content cache to generated pages

just so that we don't waste work regenerating them over and over again -w-
This commit is contained in:
liquidex 2024-11-23 21:21:28 +01:00
parent 9022fb4ce9
commit 42eaa326ab
4 changed files with 127 additions and 14 deletions

View file

@ -20,7 +20,10 @@ use crate::{
parse::parse_tree_with_diagnostics,
state::{report_diagnostics, Source},
tree::SemaRoots,
vfs::{self, Cd, Dir, DirEntry, DynDir, MemDir, Overlay, ToDynDir, VPath, VPathBuf},
vfs::{
self, Cd, ContentCache, Dir, DirEntry, DynDir, EditPath, ImageSize, MemDir, Overlay,
ToDynDir, VPath, VPathBuf,
},
};
use crate::state::{FileId, Treehouse};
@ -415,14 +418,10 @@ impl Dir for TreehouseDir {
} else {
path
};
let mut path = path.to_owned();
if path.extension() == Some("html") {
path.set_extension("");
}
self.sources
.parsed_trees
.get(&path)
.get(path)
.map(|parsed_tree| {
generate_tree_or_error(&self.sources, &self.dirs, &self.handlebars, parsed_tree)
.into()
@ -456,12 +455,67 @@ impl fmt::Debug for TreehouseDir {
}
}
struct HtmlCanonicalize<T> {
inner: T,
}
impl<T> HtmlCanonicalize<T> {
pub fn new(inner: T) -> Self {
Self { inner }
}
}
impl<T> Dir for HtmlCanonicalize<T>
where
T: Dir,
{
fn dir(&self, path: &VPath) -> Vec<DirEntry> {
self.inner.dir(path)
}
fn content(&self, path: &VPath) -> Option<Vec<u8>> {
let mut path = path.to_owned();
if path.extension() == Some("html") {
path.set_extension("");
}
self.inner.content(&path)
}
fn content_version(&self, path: &VPath) -> Option<String> {
self.inner.content_version(path)
}
fn image_size(&self, path: &VPath) -> Option<ImageSize> {
self.inner.image_size(path)
}
fn anchor(&self, path: &VPath) -> Option<VPathBuf> {
self.inner.anchor(path)
}
fn edit_path(&self, path: &VPath) -> Option<EditPath> {
self.inner.edit_path(path)
}
}
impl<T> fmt::Debug for HtmlCanonicalize<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "HtmlCanonicalize({:?})", self.inner)
}
}
pub fn target(dirs: Arc<Dirs>, sources: Arc<Sources>) -> DynDir {
let mut root = MemDir::new();
root.add(VPath::new("static"), dirs.static_.clone());
let dir_index = DirIndex::new(sources.parsed_trees.keys().map(|x| &**x));
let tree_view = TreehouseDir::new(dirs, sources, dir_index);
let tree_view = ContentCache::new(tree_view);
let tree_view = HtmlCanonicalize::new(tree_view);
Overlay::new(tree_view.to_dyn(), root.to_dyn()).to_dyn()
}

View file

@ -52,6 +52,7 @@ use std::{
mod anchored;
pub mod asynch;
mod cd;
mod content_cache;
mod content_version_cache;
mod edit;
mod empty;
@ -64,6 +65,7 @@ mod physical;
pub use anchored::*;
pub use cd::*;
pub use content_cache::*;
pub use content_version_cache::*;
pub use edit::*;
pub use empty::*;

View file

@ -0,0 +1,60 @@
use std::fmt::{self, Debug};
use dashmap::DashMap;
use super::{Dir, DirEntry, EditPath, ImageSize, VPath, VPathBuf};
pub struct ContentCache<T> {
inner: T,
cache: DashMap<VPathBuf, Option<Vec<u8>>>,
}
impl<T> ContentCache<T> {
pub fn new(inner: T) -> Self {
Self {
inner,
cache: DashMap::new(),
}
}
}
impl<T> Dir for ContentCache<T>
where
T: Dir,
{
fn dir(&self, path: &VPath) -> Vec<DirEntry> {
self.inner.dir(path)
}
fn content(&self, path: &VPath) -> Option<Vec<u8>> {
self.cache
.entry(path.to_owned())
.or_insert_with(|| self.inner.content(path))
.clone()
}
fn content_version(&self, path: &VPath) -> Option<String> {
self.inner.content_version(path)
}
fn image_size(&self, path: &VPath) -> Option<ImageSize> {
self.inner.image_size(path)
}
fn anchor(&self, path: &VPath) -> Option<VPathBuf> {
self.inner.anchor(path)
}
fn edit_path(&self, path: &VPath) -> Option<EditPath> {
self.inner.edit_path(path)
}
}
impl<T> fmt::Debug for ContentCache<T>
where
T: Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ContentCache({:?})", self.inner)
}
}

View file

@ -104,9 +104,7 @@ class LinkedBranch extends Branch {
async loadTreePromise(_initiator) {
try {
let response = await fetch(
`${TREEHOUSE_SITE}/${this.linkedTree}.html`
);
let response = await fetch(`${TREEHOUSE_SITE}/${this.linkedTree}`);
if (response.status == 404) {
throw `Hmm, seems like the tree "${this.linkedTree}" does not exist.`;
}
@ -127,7 +125,9 @@ class LinkedBranch extends Branch {
// No need to await for the import because we don't use the resulting module.
// Just fire and forger 💀
// and let them run in parallel.
let url = URL.createObjectURL(new Blob([script.textContent], { type: "text/javascript" }))
let url = URL.createObjectURL(
new Blob([script.textContent], { type: "text/javascript" }),
);
import(url);
}
} catch (error) {
@ -257,10 +257,7 @@ async function expandLinkedBranch() {
let currentlyHighlightedBranch = getCurrentlyHighlightedBranch();
if (currentlyHighlightedBranch.length > 0) {
let linkedBranch = document.getElementById(currentlyHighlightedBranch);
if (
linkedBranch.children.length > 0 &&
linkedBranch.children[0].tagName == "DETAILS"
) {
if (linkedBranch.children.length > 0 && linkedBranch.children[0].tagName == "DETAILS") {
expandDetailsRecursively(linkedBranch.children[0]);
}
}