Rust library to generate static websites
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

nit: article

+76 -76
+3 -3
website/content/docs/images.md
··· 64 64 let image = ctx.assets.add_image_with_options( 65 65 "path/to/image.jpg", 66 66 ImageOptions { 67 - width: Some(800), 68 - height: None, 69 - format: Some(ImageFormat::Png), 67 + width: Some(800), 68 + height: None, 69 + format: Some(ImageFormat::Png), 70 70 }, 71 71 )?; 72 72
+73 -73
website/content/news/2026-in-the-cursed-lands.md
··· 7 7 8 8 **How dusty are these shelves!** And yet, new books have found themselves nestled among the ancient tomes, ready to be discovered by those brave enough to explore these cursed lands. 9 9 10 - Last summer we were very happy to introduce to you Maudit, a Rust library to generate static websites, then at version 0.1, but already quite mighty. This time we're back to talk about what we've been up to recently and what's coming this year. 10 + Last summer, we were very happy to introduce Maudit to you, a Rust library to generate static websites, then at version 0.1, but already quite mighty. This time we're back to talk about what we've been up to recently and what's coming this year. 11 11 12 12 > Interested in trying out Maudit? Follow our [Quick Start](/docs/quick-start/) guide. 13 13 14 14 ## Image processing 15 15 16 - [Maudit 0.4.0](https://github.com/bruits/maudit/blob/main/crates/maudit/CHANGELOG.md#040) added support for image processing, allowing you to easily resize, convert and optimize images for your website at build-time. 16 + [Maudit 0.4.0](https://github.com/bruits/maudit/blob/main/crates/maudit/CHANGELOG.md#040) added support for image processing, allowing you to easily resize, convert, and optimize images for your website at build time. 17 17 18 18 ```rs 19 19 use maud::html; ··· 27 27 let image = ctx.assets.add_image_with_options( 28 28 "path/to/image.jpg", 29 29 ImageOptions { 30 - width: Some(800), 31 - height: None, 32 - format: Some(ImageFormat::Png), 30 + width: Some(800), 31 + height: None, 32 + format: Some(ImageFormat::Png), 33 33 }, 34 34 )?; 35 35 ··· 42 42 43 43 See [our section on image processing](https://maudit.org/docs/images/#processing-images) for more information on how to use images in Maudit. 44 44 45 - ### Placeholders generation 45 + ### Placeholder generation 46 46 47 47 Maudit also includes the ability to easily create low-quality image placeholders (LQIP) for your images using [ThumbHash](https://evanw.github.io/thumbhash/). 48 48 ··· 66 66 67 67 ## Customizable Markdown rendering 68 68 69 - [Maudit 0.5.0](https://github.com/bruits/maudit/blob/main/crates/maudit/CHANGELOG.md#050) added support for components and shortcodes in Markdown files. These features allows you to completely customize how your Markdown files are rendered and enhance them with cool new possibilities. 69 + [Maudit 0.5.0](https://github.com/bruits/maudit/blob/main/crates/maudit/CHANGELOG.md#050) added support for components and shortcodes in Markdown files. These features allow you to completely customize how your Markdown files are rendered and enhance them with new possibilities. 70 70 71 71 ### Shortcodes 72 72 73 - Embedding a Youtube video typically requires one to copy this long, ugly, iframe tag and configure the different attributes to make sure it renders properly, it'd be nice to have something more friendly, a code that would be short, you will. 73 + Embedding a YouTube video typically means copying a long, ugly iframe tag and configuring several attributes to ensure proper rendering. It'd be nice to have something friendlier, a code that would be short, you will. 74 74 75 75 ```md 76 76 Here's my cool video: ··· 103 103 104 104 ### Components 105 105 106 - Sometimes, you want to be able to keep writing normal, spec-compliant, Markdown, but still be able to add a bit of spice to it. For this Maudit supports components, allowing you to use custom code when rendering normal Markdown elements. 106 + Sometimes, you want to keep writing normal, spec-compliant Markdown, but still be able to add a bit of spice to it. For this, Maudit supports components, allowing you to use custom code when rendering normal Markdown elements. 107 107 108 108 For instance, you may want to add an anchor icon to every heading, without needing to use a `{{ heading }}` shortcode. 109 109 ··· 113 113 struct CustomHeading; 114 114 115 115 impl HeadingComponent for CustomHeading { 116 - fn render_start(&self, level: u8, id: Option<&str>, _classes: &[&str]) -> String { 117 - let id_attr = id.map(|i| format!(" id=\"{}\"", i)).unwrap_or_default(); 118 - let href = id.map(|i| format!("#{}", i)).unwrap_or_default(); 119 - format!( 120 - "<div><a href=\"{href}\"><span aria-hidden=\"true\">{}</span></a><h{level}{id_attr}>", include_str("icons/anchor.svg") 121 - ) 122 - } 116 + fn render_start(&self, level: u8, id: Option<&str>, _classes: &[&str]) -> String { 117 + let id_attr = id.map(|i| format!(" id=\"{}\"", i)).unwrap_or_default(); 118 + let href = id.map(|i| format!("#{}", i)).unwrap_or_default(); 119 + format!( 120 + "<div><a href=\"{href}\"><span aria-hidden=\"true\">{}</span></a><h{level}{id_attr}>", include_str("icons/anchor.svg") 121 + ) 122 + } 123 123 124 - fn render_end(&self, level: u8) -> String { 125 - format!("</h{level}></div>") 126 - } 124 + fn render_end(&self, level: u8) -> String { 125 + format!("</h{level}></div>") 126 + } 127 127 } 128 128 ``` 129 129 130 130 ```rs 131 131 content_sources![ 132 - "blog" => glob_markdown_with_options::<BlogPost>("content/blog/**/*.md", MarkdownOptions { 133 - components: MarkdownComponents::new().heading(CustomHeading), 134 - ..Default::default() 135 - }), 132 + "blog" => glob_markdown_with_options::<BlogPost>("content/blog/**/*.md", MarkdownOptions { 133 + components: MarkdownComponents::new().heading(CustomHeading), 134 + ..Default::default() 135 + }), 136 136 ], 137 137 ``` 138 138 ··· 140 140 141 141 ## Improved error handling 142 142 143 - [Maudit 0.6.0](https://github.com/bruits/maudit/releases/tag/maudit-v0.6.0) and [0.6.6](https://github.com/bruits/maudit/releases/tag/maudit-v0.6.6) made it much easier to handle errors inside of pages by making all of the assets (which are quite prone to errors, filesystem and all) methods return Result instead of panicking. 143 + [Maudit 0.6.0](https://github.com/bruits/maudit/releases/tag/maudit-v0.6.0) and [0.6.6](https://github.com/bruits/maudit/releases/tag/maudit-v0.6.6) made it much easier to handle errors within pages by making all asset methods (which are prone to filesystem errors) return `Result` instead of panicking. 144 144 145 - Additionally, pages themselves can now optionally return `Result` and will bubble up their errors up the chain up to [the entrypoint](/docs/entrypoint/) when using the `?` operator. Maudit implements `Into<RenderResult>` for `Result<T: Into<RenderResult>, E: Error>`, as such using `?` and returning `Result` require no signature changes inside your pages. 145 + Additionally, pages themselves can now optionally return `Result` and will bubble their errors up the chain to [the entrypoint](/docs/entrypoint/) when using the `?` operator. Maudit implements `Into<RenderResult>` for `Result<T: Into<RenderResult>, E: Error>`, and as such, using `?` and returning `Result` requires no signature changes inside your pages. 146 146 147 147 ```rs 148 148 use maudit::route::prelude::*; ··· 152 152 pub struct Example; 153 153 154 154 impl Route for Example { 155 - fn render(&self, ctx: &mut PageContext) -> impl Into<RenderResult> { 156 - // Use the ? operator to bubble up asset-related errors 157 - let logo = ctx.assets.add_image("images/logo.png")?; 155 + fn render(&self, ctx: &mut PageContext) -> impl Into<RenderResult> { 156 + // Use the ? operator to bubble up asset-related errors 157 + let logo = ctx.assets.add_image("images/logo.png")?; 158 158 159 - // Wrap your return value with Ok() 160 - Ok(html! { 161 - (logo) 162 - p { "My cool logo!" } 163 - }) 164 - } 159 + // Wrap your return value with Ok() 160 + Ok(html! { 161 + (logo) 162 + p { "My cool logo!" } 163 + }) 164 + } 165 165 } 166 166 ``` 167 167 168 - Or, you can just `unwrap()` everything, that's ok! Check our section on [handling errors](/docs/routing/#handling-errors) if you'd like to learn more. 168 + Or you can just `unwrap()` everything, that's ok! Check our section on [handling errors](/docs/routing/#handling-errors) if you'd like to learn more. 169 169 170 170 ## Support for internationalization 171 171 172 - [Maudit 0.7.0](https://github.com/bruits/maudit/releases/tag/maudit-v0.7.0) added support for internationalizating routes. For instance, you may want to have a `/about` in English, but `/a-propos` and `/om-oss` in French and Swedish respectively. 172 + [Maudit 0.7.0](https://github.com/bruits/maudit/releases/tag/maudit-v0.7.0) added support for internationalizing routes. For instance, you may want to have `/about` in English, but `/a-propos` and `/om-oss` in French and Swedish respectively. 173 173 174 - This is possible to do right now in Maudit: You can duplicate your `About` struct twice, register the two new routes, rewrite the `render` implementation twice.. but that's a bit cumbersome, so Maudit now allows you to generate all these pages using a single struct: 174 + This is already possible in Maudit: You can duplicate your `About` struct twice, register the two new routes, rewrite the `render` implementation twice… but that's a bit cumbersome, so Maudit now allows you to generate all these pages using a single struct: 175 175 176 176 ```rust 177 177 use maudit::route::prelude::*; ··· 183 183 pub struct Contact; 184 184 185 185 impl Route for Contact { 186 - fn render(&self, ctx: &mut PageContext) -> impl Into<RenderResult> { 187 - match &ctx.variant { 188 - Some(language) => match language.as_str() { 189 - "sv" => "Kontakta oss.", 190 - "de" => "Kontaktieren Sie uns.", 191 - _ => unreachable!(), 192 - }, 193 - _ => "Contact us.", 194 - } 186 + fn render(&self, ctx: &mut PageContext) -> impl Into<RenderResult> { 187 + match &ctx.variant { 188 + Some(language) => match language.as_str() { 189 + "sv" => "Kontakta oss.", 190 + "de" => "Kontaktieren Sie uns.", 191 + _ => unreachable!(), 192 + }, 193 + _ => "Contact us.", 195 194 } 195 + } 196 196 } 197 197 ``` 198 198 199 - The ergonomics are still a bit iffy, but this nonetheless already makes it much easier to localize your website. To learn more about internationalization [visit our documentation](/docs/routing/#internationalization-i18n). 199 + The ergonomics are still a bit iffy, but this nonetheless already makes it much easier to localize your website. To learn more about internationalization, [visit our documentation](/docs/routing/#internationalization-i18n). 200 200 201 201 ## Built-in sitemap generation 202 202 ··· 208 208 use maudit::{BuildOptions, SitemapOptions, content_sources, coronate, routes}; 209 209 210 210 fn main() { 211 - coronate( 212 - routes![], 213 - content_sources![], 214 - BuildOptions { 215 - base_url: Some("https://example.com".into()), 216 - sitemap: SitemapOptions { 217 - enabled: true, 218 - ..Default::default() 219 - }, 220 - ..Default::default() 221 - }, 222 - ); 211 + coronate( 212 + routes![], 213 + content_sources![], 214 + BuildOptions { 215 + base_url: Some("https://example.com".into()), 216 + sitemap: SitemapOptions { 217 + enabled: true, 218 + ..Default::default() 219 + }, 220 + ..Default::default() 221 + }, 222 + ); 223 223 } 224 224 ``` 225 225 226 - With this, building your website will now result in a `sitemap.xml` file being generated inside your `dist` folder which includes all the pages of your website. Maudit will also automatically handle separating your sitemap in multiple files if you have over the recommended amount of maximum 50000 pages per sitemap. 226 + With this, building your website will now result in a `sitemap.xml` file being generated inside your `dist` folder, which includes all the pages of your website. Maudit will also automatically handle separating your sitemap into multiple files if you have over the recommended maximum of 50,000 pages per sitemap. 227 227 228 - For more information on sitemap generation in Maudit, check [our Sitemap documentation](/docs/sitemap/). 228 + For more information on sitemap generation in Maudit, check [our sitemap documentation](/docs/sitemap/). 229 229 230 230 ## Automatic prefetching 231 231 232 - A common complaint about MPAs (Multi-Page Applications) is that navigating between page is slow, especially compared to the app-like experience of SPAs (Single-Page Applications). 232 + A common complaint about MPAs (Multi-Page Applications) is that navigating between pages is slow, especially compared to the app-like experience of SPAs (Single-Page Applications). 233 233 234 - The solution to this problem is to prefetch pages before the user navigate to them, like SPAs typically do, allowing near-instant navigations in most cases. 234 + The solution to this problem is to prefetch pages before the user navigates to them, like SPAs typically do, allowing near-instant navigations in most cases. 235 235 236 - Since [Maudit 0.10.0](https://github.com/bruits/maudit/releases/tag/maudit-v0.10.0), Maudit will by default prefetch links on clickdown, improving page loads by around 80ms on average, with other prefetching strategies available such as prefetching on hover. 236 + Since [Maudit 0.10.0](https://github.com/bruits/maudit/releases/tag/maudit-v0.10.0), Maudit will by default prefetch links on mousedown, improving page loads by around 80 ms on average, with other prefetching strategies available such as prefetching on hover. 237 237 238 238 <video autoplay controls loop> 239 239 <source src="/prefetch.mp4" type="video/mp4"> ··· 253 253 pub struct Redirect; 254 254 255 255 impl Route for Redirect { 256 - fn render(&self, ctx: &mut PageContext) -> impl Into<RenderResult> { 257 - redirect("https://example.com") 256 + fn render(&self, ctx: &mut PageContext) -> impl Into<RenderResult> { 257 + redirect("https://example.com") 258 258 259 - // Use a page's url method to generate type safe links: 260 - // redirect(&OtherPage.url(None)) 261 - } 259 + // Use a page's url method to generate type-safe links: 260 + // redirect(&OtherPage.url(None)) 261 + } 262 262 } 263 263 ``` 264 264 265 - Simple enough. The return value of this function can be directly used in your pages, making it nice and easy to redirect to new content. To learn more about internationalization [redirect yourself to our documentation](/docs/routing/#redirects). 265 + Simple enough. The return value of this function can be directly used in your pages, making it nice and easy to redirect to new content. To learn more about redirects, [redirect yourself to our documentation](/docs/routing/#redirects). 266 266 267 267 ## The future 268 268 269 - Maudit is mightier than before, but there's still so many twisted paths we'd like to follow. Including, but not limited to: 269 + Maudit is mightier than before, but there are still so many twisted paths we'd like to follow. Including, but not limited to: 270 270 271 271 - Ability to generate variants of pages, outside of the localization system. 272 - - Support for generating PWAs automatically 273 - - Built-in font support (w/ subsetting) 272 + - Support for generating PWAs automatically. 273 + - Built-in font support (w/ subsetting). 274 274 - ... and more! 275 275 276 276 For now, we go back into hiding. See you soon!