0
0

Implemented ESM and optimizations

This commit is contained in:
Opnxng 2024-10-17 12:28:18 +08:00
parent f6fbea2cdf
commit 41303a3ebc
11 changed files with 1226 additions and 197 deletions

View File

@ -1,17 +1,33 @@
const { DateTime } = require("luxon"); // Import the necessary libraries and plugins using ESM syntax
//const CleanCSS = require("clean-css"); import fs from "node:fs/promises";
const { minify } = require("html-minifier-terser"); import { DateTime } from "luxon";
const markdownIt = require("markdown-it"); import { eleventyImageTransformPlugin } from "@11ty/eleventy-img";
const markdownItAttrs = require("markdown-it-attrs"); import { minify } from "html-minifier-terser";
const markdownItAnchor = require("markdown-it-anchor"); import PurgeCss from "eleventy-plugin-purgecss";
import CleanCSS from "clean-css";
import markdownIt from "markdown-it";
import markdownItAttrs from "markdown-it-attrs";
import markdownItAnchor from "markdown-it-anchor";
import markdownItBracketedSpans from "markdown-it-bracketed-spans";
module.exports = function (eleventyConfig) { export default function (eleventyConfig) {
//
// Configure Eleventy to not use .gitignore files
eleventyConfig.setUseGitIgnore(false); eleventyConfig.setUseGitIgnore(false);
// Set the directories for input, includes, data, and output
eleventyConfig.dir = {
input: "src",
includes: "_includes",
data: "_data",
output: "site",
};
// Set Markdown options
const mdOptions = { const mdOptions = {
html: true, html: true, // Allow HTML tags in Markdown files
breaks: true, breaks: true, // Convert line breaks to HTML <br> tags
linkify: true, linkify: true, // Automatically convert URLs into links
}; };
const markdownItAnchorOptions = { const markdownItAnchorOptions = {
@ -19,14 +35,18 @@ module.exports = function (eleventyConfig) {
permalink: true, permalink: true,
}; };
// Create a Markdown library with custom plugins
const markdownLib = markdownIt(mdOptions) const markdownLib = markdownIt(mdOptions)
.use(markdownItAnchor, markdownItAnchorOptions) .use(markdownItAnchor, markdownItAnchorOptions)
.use(markdownItAttrs) .use(markdownItAttrs)
.use(require("markdown-it-bracketed-spans")) .use(markdownItBracketedSpans) // Enable bracketed spans
.disable("code"); .disable("code");
// Set the Markdown library to use with Eleventy
eleventyConfig.setLibrary("md", markdownLib); eleventyConfig.setLibrary("md", markdownLib);
// Define the template formats that Eleventy will process
eleventyConfig.setTemplateFormats([ eleventyConfig.setTemplateFormats([
"md", "md",
"webmanifest", "webmanifest",
@ -46,6 +66,7 @@ module.exports = function (eleventyConfig) {
"pdf", "pdf",
]); ]);
// Register a filter to output a human-readable post date
eleventyConfig.addFilter("readablePostDate", (dateObj) => { eleventyConfig.addFilter("readablePostDate", (dateObj) => {
return DateTime.fromJSDate(dateObj, { return DateTime.fromJSDate(dateObj, {
zone: "Asia/Singapore", zone: "Asia/Singapore",
@ -54,6 +75,7 @@ module.exports = function (eleventyConfig) {
.toLocaleString({ day: "numeric", month: "short", year: "numeric" }); .toLocaleString({ day: "numeric", month: "short", year: "numeric" });
}); });
// Register a filter to output post date in ISO format
eleventyConfig.addFilter("postDate", (dateObj) => { eleventyConfig.addFilter("postDate", (dateObj) => {
return DateTime.fromJSDate(dateObj, { return DateTime.fromJSDate(dateObj, {
zone: "Asia/Singapore", zone: "Asia/Singapore",
@ -62,9 +84,29 @@ module.exports = function (eleventyConfig) {
.toISODate(); .toISODate();
}); });
eleventyConfig.addTransform("minifyHTML", function (content, outputPath) { // Register a filter to output post date in ISO format
eleventyConfig.addFilter("postDate", (dateObj) => {
return DateTime.fromJSDate(dateObj, { zone: "Asia/Hong_Kong" })
.setLocale("en-GB")
.toISODate();
});
// Add an image transform plugin with custom configuration
eleventyConfig.addPlugin(eleventyImageTransformPlugin, {
extensions: "html", // Process only HTML files
formats: ["jpg", "webp"],
widths: ["auto", 400, 800, 1600],
defaultAttributes: {
loading: "lazy",
sizes: "auto",
decoding: "async",
},
});
// Add a transform to minify HTML content
eleventyConfig.addTransform("minifyHTML", (content, outputPath) => {
// Only minify HTML files // Only minify HTML files
if (outputPath && outputPath.endsWith(".html")) { if (outputPath?.endsWith(".html")) {
return minify(content, { return minify(content, {
collapseWhitespace: true, // Collapses whitespace between tags collapseWhitespace: true, // Collapses whitespace between tags
removeComments: true, // Removes HTML comments removeComments: true, // Removes HTML comments
@ -76,16 +118,37 @@ module.exports = function (eleventyConfig) {
removeEmptyAttributes: true, // Removes empty attributes removeEmptyAttributes: true, // Removes empty attributes
minifyURLs: true, // Minifies URLs in attributes minifyURLs: true, // Minifies URLs in attributes
html5: true, // Enables HTML5 parsing html5: true, // Enables HTML5 parsing
// caseSensitive: true, // Treats tags and attributes as case-sensitive
// keepClosingSlash: true, // Keeps trailing slash on self-closing tags
// quoteCharacter: '"', // Specifies quote character for attributes
// processConditionalComments: true, // Processes conditional comments in IE
// trimCustomFragments: true, // Trims custom HTML fragments
}); });
} }
return content; return content; // Return the original content if not HTML
}); });
// CleanCSS
eleventyConfig.on("afterBuild", async () => {
const inputFiles = ["src/css/reset.css", "src/css/index.css"];
for (const inputFile of inputFiles) {
try {
const input = await fs.readFile(inputFile, "utf8");
const output = new CleanCSS().minify(input);
const outputFilePath = `site/css/${inputFile.split("/").pop()}`; // Adjust output path as necessary
await fs.writeFile(outputFilePath, output.styles);
console.log(
`eleventy-plugin-cleancss: Successfully minified ${inputFile} to ${outputFilePath}`,
);
} catch (err) {
console.error(
`eleventy-plugin-cleancss: Error minifying ${inputFile}: ${err}`,
);
}
}
});
// Purge unused CSS
eleventyConfig.addPlugin(PurgeCss, {
config: "./purgecss.config.cjs",
});
// Return effective configuration for Eleventy
return { return {
dir: { dir: {
input: "src", input: "src",
@ -93,9 +156,4 @@ module.exports = function (eleventyConfig) {
output: "site", output: "site",
}, },
}; };
}
eleventyConfig.addPassthroughCopy("/src/css");
return {
passthroughFileCopy: true,
};
};

View File

@ -18,15 +18,22 @@ docker run --rm --name=npm -u 1000 -v /path/to/website:/app -w /app node:lts-sli
# Install node modules # Install node modules
docker run --rm --name=npm -u 1000 -v /path/to/website:/app -w /app node:lts-slim npm install \ docker run --rm --name=npm -u 1000 -v /path/to/website:/app -w /app node:lts-slim npm install \
npm \ npm \
@11ty/eleventy \ @11ty/eleventy@latest \
@11ty/eleventy-img@latest \
luxon \ luxon \
html-minifier-terser \ html-minifier-terser \
clean-css \ clean-css \
eleventy-plugin-purgecss \
clean-css \
markdown-it-attrs \ markdown-it-attrs \
markdown-it-bracketed-spans \ markdown-it-bracketed-spans \
markdown-it-anchor markdown-it-anchor
``` ```
``` ```
# Test
docker run --rm --name=npm -u 1000 -p 8080:8080 -v /path/to/website:/app -w /app node:lts-slim npx @11ty/eleventy --serve --quiet
```
```
# Generate website # Generate website
docker run --rm --name=npm -u 1000 -v /path/to/website:/app -w /app --network none node:lts-slim npx eleventy docker run --rm --name=npm -u 1000 -v /path/to/website:/app -w /app --network none node:lts-slim npx eleventy
``` ```

1079
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,14 @@
{ {
"type": "module",
"dependencies": { "dependencies": {
"@11ty/eleventy": "^3.0.0", "@11ty/eleventy": "^3.0.0",
"@11ty/eleventy-img": "^5.0.0",
"clean-css": "^5.3.3", "clean-css": "^5.3.3",
"eleventy-plugin-purgecss": "^0.5.0",
"html-minifier-terser": "^7.2.0", "html-minifier-terser": "^7.2.0",
"luxon": "^2.5.2", "luxon": "^2.5.2",
"markdown-it-anchor": "^8.6.7", "markdown-it-anchor": "^8.6.7",
"markdown-it-attrs": "^4.1.6", "markdown-it-attrs": "^4.2.0",
"markdown-it-bracketed-spans": "^1.0.1", "markdown-it-bracketed-spans": "^1.0.1",
"npm": "^10.9.0" "npm": "^10.9.0"
} }

12
purgecss.config.cjs Normal file
View File

@ -0,0 +1,12 @@
module.exports = {
// Content files referencing CSS classes
content: ["./site/**/*.html"],
// CSS files to be purged in-place
css: ["./site/**/*.css"],
safelist: {
standard: ["body"], // Safelist the body selector
deep: [],
greedy: [],
},
};

View File

@ -2,22 +2,23 @@
<html> <html>
<head> <head>
<title>{{ title }}</title> <title>{{ title }}</title>
<meta charset="utf-8"> <meta charset="utf-8">
<html lang="en"> <html lang="en">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="description" content="Opnxng.com hosts public services that prioritize privacy."> <meta name="description" content="Opnxng.com hosts public services that prioritize privacy.">
<link rel="stylesheet" href="/css/index.css"> <link rel="stylesheet" href="/css/reset.css">
<link rel="icon" href="/css/favicons/favicon.ico" sizes="any" /> <link rel="stylesheet" href="/css/index.css">
<link rel="icon" href="/css/favicons/favicon.svg" type="image/svg+xml" /> <link rel="icon" href="/css/favicons/favicon.ico" sizes="any" />
<link rel="apple-touch-icon" href="/css/favicons/apple-touch-icon.png" /> <link rel="icon" href="/css/favicons/favicon.svg" type="image/svg+xml" />
<link rel="manifest" href="/css/favicons/manifest.webmanifest" /> <link rel="apple-touch-icon" href="/css/favicons/apple-touch-icon.png" />
<link rel="manifest" href="/css/favicons/manifest.webmanifest" />
</head> </head>
<body> <body>
<div class="wrapper"> <div class="wrapper">
{{ content | safe }} {{ content | safe }}
</div> </div>
</body> </body>
</html> </html>

View File

@ -1,4 +1,3 @@
@import url("reset.css");
/*----------------------------------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------------------------------*/
@font-face { @font-face {
font-family: "eb_garamond_initials"; font-family: "eb_garamond_initials";
@ -29,6 +28,7 @@
--secondary-background-color: #fafafa; --secondary-background-color: #fafafa;
--primary-color: #20599e; --primary-color: #20599e;
--secondary-color: #20599e; --secondary-color: #20599e;
--line: calc(var(--font-size) * var(--line-height));
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
:root { :root {
@ -138,23 +138,19 @@ button:focus {
background: var(--primary-background-color); background: var(--primary-background-color);
max-width: 26.5rem; max-width: 26.5rem;
margin: 0 auto; margin: 0 auto;
min-height: calc(100vh - (var(--font-size) * var(--line-height) * (2.6 + 1))); min-height: calc(100vh - (var(--line) * (2.6 + 1)));
text-align: center; text-align: center;
padding: calc(var(--font-size) * var(--line-height) * 2.6) padding: calc(var(--line) * 2.6) calc(var(--line) * 2.6) var(--line);
calc(var(--font-size) * var(--line-height) * 2.6)
calc(var(--font-size) * var(--line-height));
} }
@media (pointer: none), (pointer: coarse) { @media (pointer: none), (pointer: coarse) {
.wrapper { .wrapper {
padding: calc(var(--font-size) * var(--line-height) * 2.2) padding: calc(var(--line) * 2.2) calc(var(--font-size) * 1.8) 0;
calc(var(--font-size) * 1.8) 0;
} }
} }
@media (pointer: none), (pointer: coarse) and (min-width: 780px) { @media (pointer: none), (pointer: coarse) and (min-width: 780px) {
.wrapper { .wrapper {
max-width: 22rem; max-width: 22rem;
padding: calc(var(--font-size) * var(--line-height) * 4.6) padding: calc(var(--line) * 4.6) calc(var(--font-size) * 1.8) 0;
calc(var(--font-size) * 1.8) 0;
} }
} }
/*----------------------------------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------------------------------*/
@ -166,7 +162,7 @@ p + p {
} }
p.image + p { p.image + p {
text-indent: 0; text-indent: 0;
margin-top: calc(var(--font-size) * var(--line-height) * 1); margin-top: calc(var(--line) * 1);
} }
span.last { span.last {
white-space: nowrap; white-space: nowrap;
@ -202,13 +198,13 @@ a.links:visited {
} }
/*----------------------------------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------------------------------*/
img { img {
height: calc(var(--font-size) * var(--line-height) * 10); height: calc(var(--line) * 10);
width: auto; width: auto;
max-width: 100%; max-width: 100%;
display: block; display: block;
margin: 0 auto; margin: 0 auto;
object-fit: contain; object-fit: contain;
padding-bottom: calc(var(--font-size) * var(--line-height) * -1); padding-bottom: var(--line);
} }
/*----------------------------------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------------------------------*/
.sc { .sc {
@ -227,8 +223,8 @@ a.footer {
display: flex; display: flex;
justify-content: right; justify-content: right;
padding-right: calc(var(--font-size) * 1.067); padding-right: calc(var(--font-size) * 1.067);
margin-top: calc(var(--font-size) * var(--line-height)); margin-top: var(--line);
margin-bottom: calc(var(--font-size) * var(--line-height) * 3); margin-bottom: calc(var(--line) * 3);
} }
/*----------------------------------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------------------------------*/
.blog:first-child:first-letter { .blog:first-child:first-letter {
@ -241,8 +237,8 @@ a.footer {
} }
/*----------------------------------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------------------------------*/
table { table {
margin-top: calc(var(--font-size) * var(--line-height)); margin-top: var(--line);
margin-bottom: calc(var(--font-size) * var(--line-height) * -1); margin-bottom: calc(var(--line) * -1);
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
} }
@ -250,7 +246,7 @@ thead {
display: none; display: none;
} }
tr td { tr td {
padding-bottom: calc(var(--font-size) * var(--line-height)); padding-bottom: var(--line);
} }
td:nth-child(1) { td:nth-child(1) {
color: var(--primary-color); color: var(--primary-color);
@ -270,7 +266,7 @@ ul {
column-gap: calc(var(--font-size) * 3); column-gap: calc(var(--font-size) * 3);
list-style-type: none; list-style-type: none;
padding: 0; padding: 0;
margin: calc(var(--font-size) * var(--line-height)) 0; margin: var(--line) 0;
margin-left: calc(var(--font-size) * 1.42); margin-left: calc(var(--font-size) * 1.42);
} }
ul li { ul li {

View File

@ -1,48 +1,129 @@
/* http://meyerweb.com/eric/tools/css/reset/ /* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126 v2.0 | 20110126
License: none (public domain) License: none (public domain)
*/ */
html, body, div, span, applet, object, iframe, html,
h1, h2, h3, h4, h5, h6, p, blockquote, pre, body,
a, abbr, acronym, address, big, cite, code, div,
del, dfn, em, img, ins, kbd, q, s, samp, span,
small, strike, strong, sub, sup, tt, var, applet,
b, u, i, center, object,
dl, dt, dd, ol, ul, li, iframe,
fieldset, form, label, legend, h1,
table, caption, tbody, tfoot, thead, tr, th, td, h2,
article, aside, canvas, details, embed, h3,
figure, figcaption, footer, header, hgroup, h4,
menu, nav, output, ruby, section, summary, h5,
time, mark, audio, video { h6,
margin: 0; p,
padding: 0; blockquote,
border: 0; pre,
font-size: 100%; a,
font: inherit; abbr,
vertical-align: baseline; acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
} }
/* HTML5 display-role reset for older browsers */ /* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, article,
footer, header, hgroup, menu, nav, section { aside,
display: block; details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
display: block;
} }
body { body {
line-height: 1; line-height: 1;
} }
ol, ul { ol,
list-style: none; ul {
list-style: none;
} }
blockquote, q { blockquote,
quotes: none; q {
quotes: none;
} }
blockquote:before, blockquote:after, blockquote:before,
q:before, q:after { blockquote:after,
content: ''; q:before,
content: none; q:after {
content: "";
content: none;
} }
table { table {
border-collapse: collapse; border-collapse: collapse;
border-spacing: 0; border-spacing: 0;
} }

View File

Before

Width:  |  Height:  |  Size: 226 KiB

After

Width:  |  Height:  |  Size: 226 KiB

View File

Before

Width:  |  Height:  |  Size: 182 KiB

After

Width:  |  Height:  |  Size: 182 KiB