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