1import lume from "lume/mod.ts"; 2import date from "lume/plugins/date.ts"; 3import toml from "lume/plugins/toml.ts"; 4 5// Images 6import picture from "lume/plugins/picture.ts"; 7import transformImages from "lume/plugins/transform_images.ts"; 8 9// URL Management 10import slugifyUrls from "lume/plugins/slugify_urls.ts"; 11import resolveUrls from "lume/plugins/resolve_urls.ts"; 12 13// File Generation 14import feed from "lume/plugins/feed.ts"; 15import metas from "lume/plugins/metas.ts"; 16import readingInfo from "lume/plugins/reading_info.ts"; 17import robots from "lume/plugins/robots.ts"; 18import sitemap from "lume/plugins/sitemap.ts"; 19import sourceMaps from "lume/plugins/source_maps.ts"; 20 21// Optimization 22import brotli from "lume/plugins/brotli.ts"; 23import gzip from "lume/plugins/gzip.ts"; 24import minifyHTML from "lume/plugins/minify_html.ts"; 25import svgo from "lume/plugins/svgo.ts"; 26 27// Markdown-it plugins 28import { BiDirectionalLinks } from "@nolebase/markdown-it-bi-directional-links"; 29import { default as mdItObsidianCallouts } from "markdown-it-obsidian-callouts"; 30 31// Additional external plugins 32import toc from "lume_markdown_plugins/toc.ts"; 33import slugify from "npm:@sindresorhus/slugify"; 34 35// CSS 36// // Base dependencies 37import tailwindcss from "lume/plugins/tailwindcss.ts"; 38// // Fonts 39import googleFonts from "lume/plugins/google_fonts.ts"; 40// // Optimization 41import lightningcss from "lume/plugins/lightningcss.ts"; 42 43// Custom Plugins 44import validateHTML from "./plugins/validateHTML.ts"; 45import openInEditor from "./plugins/openInEditor.ts"; 46import footnotes from "./plugins/footnotes.ts"; 47import checkAccessibility from "./plugins/checkAccessibility.ts"; 48 49// Disabled Plugins: 50// import nav from "lume/plugins/nav.ts"; 51// import og_images from "lume/plugins/og_images.ts"; 52// import pagefind from "lume/plugins/pagefind.ts"; 53// import purgecss from "lume/plugins/purgecss.ts"; 54// import relations from "lume/plugins/relations.ts"; 55// import sri from "lume/plugins/sri.ts"; 56 57// To Add: 58// https://deno.land/x/lume_shiki@0.0.16 59 60const site = lume({ 61 src: "./src", 62 location: new URL("https://pyrox.dev"), 63}, { 64 markdown: { 65 plugins: [ 66 [BiDirectionalLinks, { 67 dir: Deno.cwd() + "/src/", 68 stillRenderNoMatched: false, 69 }], 70 mdItObsidianCallouts, 71 footnotes, 72 ], 73 }, 74}); 75 76// Copy Static Files 77site.ignore("/static/mocha.css"); 78site.add(".css"); 79site.add("static/.well-known", ".well-known"); 80site.add(".woff2"); 81// Tailwind CSS 82site.use(tailwindcss()); 83 84// Fonts 85site.use( 86 googleFonts({ 87 subsets: ["latin", "latin-ext"], 88 folder: "/static/fonts/", 89 cssFile: "/static/fonts.css", 90 fonts: 91 "https://fonts.googleapis.com/css2?family=IBM+Plex+Serif:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900", 92 }), 93); 94 95site.use(picture()); 96site.use(transformImages()); 97site.add(".png"); 98// site.use(relations()); 99site.use(slugifyUrls()); 100site.use(svgo()); 101site.use(toml()); 102 103// Metadata 104site.use( 105 date({ 106 formats: { 107 SHORT_DATE: "yyyy-MM-dd", 108 POST_DATE: "dd MMM, yyyy", 109 }, 110 }), 111); 112site.use(metas()); 113site.use(readingInfo({ 114 // Number taken from: 115 // https://reader.ku.edu/sites/reader/files/2024-01/How%20many%20words%20do%20we%20read%20per%20minute%20(1).pdf 116 wordsPerMinute: 238, 117})); 118site.use(toc({ 119 slugify: (s: string) => slugify(s), 120})); 121 122// Ensure all URLs are to the final page links 123site.use(resolveUrls()); 124 125// RSS/JSON Feed Generation 126site.use( 127 feed({ 128 output: ["/blog.rss", "/blog.json"], 129 query: "category=blog", 130 info: { 131 title: "dish blog", 132 description: "dish's thoughts on many things", 133 published: new Date(), 134 lang: "en", 135 generator: true, 136 authorName: "dish", 137 authorUrl: "https://blog.pyrox.dev", 138 }, 139 items: { 140 title: "=title", 141 description: "=summary", 142 published: "=published", 143 updated: "=updated", 144 content: "$.e-content", 145 lang: "=lang", 146 image: "=banner", 147 authorName: "=author.name", 148 authorUrl: "=author.url", 149 }, 150 }), 151); 152 153// CSS postprocessing 154site.use(lightningcss({ 155 options: { 156 minify: true, 157 }, 158})); 159 160site.use(sitemap()); 161 162// Source Map Generation 163// Applies to CSS and JS 164site.use(sourceMaps()); 165 166site.use(checkAccessibility()); 167site.use(validateHTML()); 168 169site.data("production", Deno.env.get("PRODUCTION") == "true"); 170// This only applies in dev mode 171if (Deno.env.get("PRODUCTION") == "false") { 172 site.use(openInEditor()); 173 site.add("static/scripts/open-in-editor.js"); 174 site.add("static/scripts/highlight-accessibility.js"); 175} 176 177// This only applies in prod mode 178if (Deno.env.get("PRODUCTION") == "true") { 179 // Minify HTML 180 site.use(minifyHTML({ 181 options: { 182 do_not_minify_doctype: true, 183 keep_closing_tags: false, 184 keep_html_and_head_opening_tags: true, 185 keep_spaces_between_attributes: true, 186 ensure_spec_compliant_unquoted_attribute_values: true, 187 keep_comments: false, 188 }, 189 })); 190} 191 192// robots.txt generation 193site.use( 194 robots({ 195 disallow: [ 196 "AI2Bot", 197 "Amazonbot", 198 "Applebot-Extended", 199 "Bytespider", 200 "ChatGPT-User", 201 "ClaudeBot", 202 "Diffbot", 203 "DuckAssistBot", 204 "FacebookBot", 205 "GPTBot", 206 "Google-Extended", 207 "Meta-ExternalAgent", 208 "Meta-ExternalFetcher", 209 "OAI-SearchBot", 210 "Operator", 211 "PanguBot", 212 "PerplexityBot", 213 "SemrushBot", 214 "SemrushBot-OCOB", 215 "Timpibot", 216 "Webzio-Extended", 217 "YouBot", 218 "cohere-training-data-crawler", 219 "omgili", 220 "t3versions", 221 ], 222 }), 223); 224 225// Compress everything with Brotli/Gzip 226site.use( 227 brotli({ 228 quality: 11, 229 extensions: [ 230 ".html", 231 ".css", 232 ".js", 233 ".mjs", 234 ".svg", 235 ".json", 236 ".xml", 237 ".txt", 238 ".rss", 239 ".map", 240 ], 241 }), 242); 243site.use( 244 gzip({ 245 extensions: [ 246 ".html", 247 ".css", 248 ".js", 249 ".mjs", 250 ".svg", 251 ".json", 252 ".xml", 253 ".txt", 254 ".rss", 255 ".map", 256 ], 257 }), 258); 259 260// Open in Editor in Dev mode 261// Get current commit as a version number 262// Taken from https://github.com/pixeldesu/pixelde.su/blob/main/_config.ts 263const commitCmd = new Deno.Command("git", { args: ["rev-parse", "HEAD"] }); 264const { stdout } = await commitCmd.output(); 265const commitHash = new TextDecoder().decode(stdout); 266site.data("commit", commitHash); 267 268export default site;