Skip to main content

StaticSiteGenerator

Struct StaticSiteGenerator 

Source
pub struct StaticSiteGenerator { /* private fields */ }
Available on crate feature ssg only.
Expand description

Writes rendered pages and assets into an output directory.

§Examples

use molt::prelude::*;
use molt::{Document, ssg::StaticSiteGenerator};

let site = StaticSiteGenerator::new("dist");
site.clean(true)?;
site.generate(&Document::new(Some("pt-BR")), "index.html", &RenderOptions::pretty())?;

Implementations§

Source§

impl StaticSiteGenerator

Source

pub fn new(output_directory: impl Into<PathBuf>) -> Self

Creates a generator writing into output_directory.

Source

pub fn output_directory(&self) -> &Path

The directory pages are written into.

Source

pub fn generate( &self, document: &Document, path: &str, options: &RenderOptions, ) -> Result<(), SsgError>

Renders a document to path, relative to the output directory.

The page is written with Document::render_to, section by section, into a temporary file that is then renamed. The bytes match Document::render_with.

§Errors

Returns an error if the path escapes the output directory, or if the write fails.

Source

pub fn generate_multiple( &self, documents: &[(Document, String)], options: &RenderOptions, ) -> Result<(), SsgError>

Renders several documents.

With the parallel feature the pages are rendered concurrently — sound because the node tree is Send + Sync.

Every failure is reported, not just the first: a bulk build that names one of twelve broken pages is worse than useless.

§Errors

Returns an error naming every page that failed.

Source

pub fn generate_page( &self, page: &Node, path: &str, options: &RenderOptions, doctype: bool, ) -> Result<(), SsgError>

Renders a bare node to path, optionally prefixed by the doctype.

§Errors

Returns an error if the path is unsafe or the write fails.

Source

pub fn copy_asset( &self, from: impl AsRef<Path>, to: &str, ) -> Result<(), SsgError>

Copies a file into the output directory, replacing any existing destination.

§Errors

Returns an error if the destination is unsafe or the copy fails.

Source

pub fn copy_dir( &self, from: impl AsRef<Path>, to: &str, ) -> Result<usize, SsgError>

Copies a directory tree into the output directory, replacing files that already exist.

to names the destination directory under the output directory; "" or "." copies into the output directory itself. Returns how many files were copied. Every file goes through copy_asset, so each copy is atomic.

Symbolic links in from are not followed: a link to a file or a directory is skipped, because what it points at may lie outside the tree you meant to publish. The output directory is skipped too if it sits inside from, so copying . cannot copy the site into itself. Use copy_dir_where to leave out names such as .DS_Store.

§Errors

Returns an error if from cannot be read, if to is unsafe (see copy_asset), if a name under from is not valid UTF-8, or if a copy fails.

§Examples
use molt::ssg::StaticSiteGenerator;

let base = std::env::temp_dir().join(format!("molt-copy-dir-{}", std::process::id()));
std::fs::create_dir_all(base.join("static/img"))?;
std::fs::write(base.join("static/app.css"), "a{}")?;
std::fs::write(base.join("static/img/logo.svg"), "<svg/>")?;

let site = StaticSiteGenerator::new(base.join("dist"));
assert_eq!(site.copy_dir(base.join("static"), "assets")?, 2);
assert!(base.join("dist/assets/img/logo.svg").is_file());
Source

pub fn copy_dir_where( &self, from: impl AsRef<Path>, to: &str, keep: impl Fn(&OsStr) -> bool, ) -> Result<usize, SsgError>

As copy_dir, copying only the entries keep accepts.

keep sees each file or directory name (not the path). A directory it rejects is skipped with everything under it.

§Errors

The same as copy_dir.

§Examples
use molt::ssg::StaticSiteGenerator;

let base = std::env::temp_dir().join(format!("molt-copy-where-{}", std::process::id()));
std::fs::create_dir_all(base.join("static"))?;
std::fs::write(base.join("static/app.css"), "a{}")?;
std::fs::write(base.join("static/.DS_Store"), "junk")?;

let site = StaticSiteGenerator::new(base.join("dist"));
let copied = site.copy_dir_where(base.join("static"), "", |name| name != ".DS_Store")?;
assert_eq!(copied, 1);
assert!(!base.join("dist/.DS_Store").exists());
Source

pub fn copy_asset_hashed( &self, from: impl AsRef<Path>, dir: &str, ) -> Result<String, SsgError>

Copies a file into dir under a name that holds a hash of its content, and returns the URL to use for it.

site.css copied to "css" becomes css/site.<hash>.css and the result is "/css/site.<hash>.css", ready for stylesheet or script_src. The same bytes always give the same name and different bytes a different one, so a cache can keep the file for a year (Cache-Control: public, max-age=31536000, immutable) and a new build still reaches every visitor. dir of "" or "." is the output directory itself. The copy is atomic, like copy_asset, and writes the bytes that were hashed, so a file that changes mid-build cannot get the wrong name.

The hash is 64-bit FNV-1a, written out in full as 16 hex digits. It names content for a cache and is not a security measure: it is trivially forged. For a hash a browser checks, see Element::csp_hash.

§What it does not do

It renames one file and rewrites nothing. A module that imports another by relative path (import './motion.js') keeps asking for the old name, and so does a url(...) in a stylesheet. Either concatenate those scripts into one file before copying it, or copy the files they refer to first and write their returned URLs into the file you then copy. An earlier version of the file stays in the directory until clean. The file name should be URL-safe, because it is returned as it is.

§Errors

Returns an error if from cannot be read, its name is not valid UTF-8, or dir is unsafe (see copy_asset).

§Examples
use molt::prelude::*;
use molt::ssg::StaticSiteGenerator;

let base = std::env::temp_dir().join(format!("molt-hashed-{}", std::process::id()));
std::fs::create_dir_all(&base)?;
std::fs::write(base.join("site.css"), "body{color:red}")?;

let site = StaticSiteGenerator::new(base.join("dist"));
let url = site.copy_asset_hashed(base.join("site.css"), "css")?;
assert_eq!(url, "/css/site.c0e0533c847ec633.css");
assert_eq!(
    stylesheet(&url).render(),
    r#"<link href="/css/site.c0e0533c847ec633.css" rel="stylesheet">"#
);
assert!(base.join("dist/css/site.c0e0533c847ec633.css").is_file());
Source

pub fn clean(&self, create_directory: bool) -> Result<(), SsgError>

Removes the output directory, optionally recreating it empty.

Only a directory Molt can show is its own is emptied: one that does not exist, is empty, or holds the OUTPUT_MARKER file that writing a page or an asset leaves there. A relative path such as "dist" is resolved against the current directory of the process, so the same code run from another project would otherwise empty that project’s dist.

§Errors

Returns an error if the output directory is unsafe to delete — empty, a filesystem root, a top-level directory, the home directory, the working directory or one of its ancestors, or containing a .. component, because removing it recursively would delete whatever it points at. It also refuses a symbolic link, and a directory that has contents but no OUTPUT_MARKER; for one made before the marker existed, remove it by hand once or create the file.

§Examples
use molt::ssg::StaticSiteGenerator;

let base = std::env::temp_dir().join(format!("molt-clean-{}", std::process::id()));
let site = StaticSiteGenerator::new(base.join("dist"));
site.write_file("<p>old</p>", "old.html")?; // leaves the marker behind
site.clean(true)?;
assert!(!base.join("dist/old.html").exists());

// A directory the generator did not make is left alone.
std::fs::write(base.join("dist/keep.txt"), "mine")?;
std::fs::remove_file(base.join("dist").join(molt::ssg::OUTPUT_MARKER))?;
assert!(site.clean(true).is_err());
assert!(base.join("dist/keep.txt").exists());
Source

pub fn write_file(&self, content: &str, path: &str) -> Result<(), SsgError>

Writes UTF-8 content to path, creating parent directories.

The write is atomic: content goes to a temporary file in the same directory and is then renamed, so a reader never sees a half-written page.

§Errors

Returns an error if the path escapes the output directory or the write fails.

Trait Implementations§

Source§

impl Clone for StaticSiteGenerator

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for StaticSiteGenerator

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<S, T> Upcast<T> for S
where T: UpcastFrom<S> + ?Sized, S: ?Sized,

Source§

fn upcast(&self) -> &T
where Self: ErasableGeneric, T: Sized + ErasableGeneric<Repr = Self::Repr>,

Perform a zero-cost type-safe upcast to a wider ref type within the Wasm bindgen generics type system. Read more
Source§

fn upcast_into(self) -> T
where Self: Sized + ErasableGeneric, T: Sized + ErasableGeneric<Repr = Self::Repr>,

Perform a zero-cost type-safe upcast to a wider type within the Wasm bindgen generics type system. Read more