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;