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