0
0

Implemented ESM and optimizations

This commit is contained in:
Opnxng 2024-10-17 12:28:18 +08:00
parent f6fbea2cdf
commit 5f8181b374
11 changed files with 1219 additions and 198 deletions

View File

@ -1,17 +1,33 @@
const { DateTime } = require("luxon");
//const CleanCSS = require("clean-css");
const { minify } = require("html-minifier-terser");
const markdownIt = require("markdown-it");
const markdownItAttrs = require("markdown-it-attrs");
const markdownItAnchor = require("markdown-it-anchor");
// Import the necessary libraries and plugins using ESM syntax
import fs from "node:fs/promises";
import { DateTime } from "luxon";
import { eleventyImageTransformPlugin } from "@11ty/eleventy-img";
import { minify } from "html-minifier-terser";
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);
// Set the directories for input, includes, data, and output
eleventyConfig.dir = {
input: "src",
includes: "_includes",
data: "_data",
output: "site",
};
// Set Markdown options
const mdOptions = {
html: true,
breaks: true,
linkify: true,
html: true, // Allow HTML tags in Markdown files
breaks: true, // Convert line breaks to HTML <br> tags
linkify: true, // Automatically convert URLs into links
};
const markdownItAnchorOptions = {
@ -19,14 +35,17 @@ module.exports = function (eleventyConfig) {
permalink: true,
};
// Create a Markdown library with custom plugins
const markdownLib = markdownIt(mdOptions)
.use(markdownItAnchor, markdownItAnchorOptions)
.use(markdownItAttrs)
.use(require("markdown-it-bracketed-spans"))
.use(markdownItBracketedSpans) // Enable bracketed spans
.disable("code");
// Set the Markdown library to use with Eleventy
eleventyConfig.setLibrary("md", markdownLib);
// Define the template formats that Eleventy will process
eleventyConfig.setTemplateFormats([
"md",
"webmanifest",
@ -46,6 +65,7 @@ module.exports = function (eleventyConfig) {
"pdf",
]);
// Register a filter to output a human-readable post date
eleventyConfig.addFilter("readablePostDate", (dateObj) => {
return DateTime.fromJSDate(dateObj, {
zone: "Asia/Singapore",
@ -54,6 +74,7 @@ module.exports = function (eleventyConfig) {
.toLocaleString({ day: "numeric", month: "short", year: "numeric" });
});
// Register a filter to output post date in ISO format
eleventyConfig.addFilter("postDate", (dateObj) => {
return DateTime.fromJSDate(dateObj, {
zone: "Asia/Singapore",
@ -62,30 +83,64 @@ module.exports = function (eleventyConfig) {
.toISODate();
});
eleventyConfig.addTransform("minifyHTML", function (content, outputPath) {
// 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: "eager",
sizes: "auto",
decoding: "async",
},
});
// Add a transform to minify HTML content
eleventyConfig.addTransform("minifyHTML", (content, outputPath) => {
// Only minify HTML files
if (outputPath && outputPath.endsWith(".html")) {
if (outputPath?.endsWith(".html")) {
return minify(content, {
collapseWhitespace: true, // Collapses whitespace between tags
removeComments: true, // Removes HTML comments
minifyCSS: true, // Minifies inline CSS
minifyJS: true, // Minifies inline JavaScript
removeAttributeQuotes: true, // Removes quotes around attributes when possible
removeOptionalTags: true, // Removes optional HTML tags (<html>, <head>, <body>)
removeOptionalTags: false, // Removes optional HTML tags (<html>, <head>, <body>)
collapseBooleanAttributes: true, // Converts boolean attributes to HTML5 style
removeEmptyAttributes: true, // Removes empty attributes
minifyURLs: true, // Minifies URLs in attributes
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 {
dir: {
input: "src",
@ -93,9 +148,4 @@ module.exports = function (eleventyConfig) {
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
docker run --rm --name=npm -u 1000 -v /path/to/website:/app -w /app node:lts-slim npm install \
npm \
@11ty/eleventy \
@11ty/eleventy@latest \
@11ty/eleventy-img@latest \
luxon \
html-minifier-terser \
clean-css \
eleventy-plugin-purgecss \
clean-css \
markdown-it-attrs \
markdown-it-bracketed-spans \
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
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": {
"@11ty/eleventy": "^3.0.0",
"@11ty/eleventy-img": "^5.0.0",
"clean-css": "^5.3.3",
"eleventy-plugin-purgecss": "^0.5.0",
"html-minifier-terser": "^7.2.0",
"luxon": "^2.5.2",
"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",
"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: [], // Safelist the body selector with "body"
deep: [],
greedy: [],
},
};

View File

@ -2,22 +2,23 @@
<html>
<head>
<title>{{ title }}</title>
<meta charset="utf-8">
<html lang="en">
<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.">
<link rel="stylesheet" href="/css/index.css">
<link rel="icon" href="/css/favicons/favicon.ico" sizes="any" />
<link rel="icon" href="/css/favicons/favicon.svg" type="image/svg+xml" />
<link rel="apple-touch-icon" href="/css/favicons/apple-touch-icon.png" />
<link rel="manifest" href="/css/favicons/manifest.webmanifest" />
<title>{{ title }}</title>
<meta charset="utf-8">
<html lang="en">
<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.">
<link rel="stylesheet" href="/css/reset.css">
<link rel="stylesheet" href="/css/index.css">
<link rel="icon" href="/css/favicons/favicon.ico" sizes="any" />
<link rel="icon" href="/css/favicons/favicon.svg" type="image/svg+xml" />
<link rel="apple-touch-icon" href="/css/favicons/apple-touch-icon.png" />
<link rel="manifest" href="/css/favicons/manifest.webmanifest" />
</head>
<body>
<div class="wrapper">
{{ content | safe }}
</div>
<div class="wrapper">
{{ content | safe }}
</div>
</body>
</html>

View File

@ -1,4 +1,3 @@
@import url("reset.css");
/*----------------------------------------------------------------------------------------------------*/
@font-face {
font-family: "eb_garamond_initials";
@ -29,6 +28,7 @@
--secondary-background-color: #fafafa;
--primary-color: #20599e;
--secondary-color: #20599e;
--line: calc(var(--font-size) * var(--line-height));
}
@media (prefers-color-scheme: dark) {
:root {
@ -138,23 +138,19 @@ button:focus {
background: var(--primary-background-color);
max-width: 26.5rem;
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;
padding: calc(var(--font-size) * var(--line-height) * 2.6)
calc(var(--font-size) * var(--line-height) * 2.6)
calc(var(--font-size) * var(--line-height));
padding: calc(var(--line) * 2.6) calc(var(--line) * 2.6) var(--line);
}
@media (pointer: none), (pointer: coarse) {
.wrapper {
padding: calc(var(--font-size) * var(--line-height) * 2.2)
calc(var(--font-size) * 1.8) 0;
padding: calc(var(--line) * 2.2) calc(var(--font-size) * 1.8) 0;
}
}
@media (pointer: none), (pointer: coarse) and (min-width: 780px) {
.wrapper {
max-width: 22rem;
padding: calc(var(--font-size) * var(--line-height) * 4.6)
calc(var(--font-size) * 1.8) 0;
padding: calc(var(--line) * 4.6) calc(var(--font-size) * 1.8) 0;
}
}
/*----------------------------------------------------------------------------------------------------*/
@ -166,7 +162,7 @@ p + p {
}
p.image + p {
text-indent: 0;
margin-top: calc(var(--font-size) * var(--line-height) * 1);
margin-top: calc(var(--line) * 1);
}
span.last {
white-space: nowrap;
@ -202,13 +198,13 @@ a.links:visited {
}
/*----------------------------------------------------------------------------------------------------*/
img {
height: calc(var(--font-size) * var(--line-height) * 10);
height: calc(var(--line) * 10);
width: auto;
max-width: 100%;
display: block;
margin: 0 auto;
object-fit: contain;
padding-bottom: calc(var(--font-size) * var(--line-height) * -1);
padding-bottom: var(--line);
}
/*----------------------------------------------------------------------------------------------------*/
.sc {
@ -227,8 +223,8 @@ a.footer {
display: flex;
justify-content: right;
padding-right: calc(var(--font-size) * 1.067);
margin-top: calc(var(--font-size) * var(--line-height));
margin-bottom: calc(var(--font-size) * var(--line-height) * 3);
margin-top: var(--line);
margin-bottom: calc(var(--line) * 3);
}
/*----------------------------------------------------------------------------------------------------*/
.blog:first-child:first-letter {
@ -241,8 +237,8 @@ a.footer {
}
/*----------------------------------------------------------------------------------------------------*/
table {
margin-top: calc(var(--font-size) * var(--line-height));
margin-bottom: calc(var(--font-size) * var(--line-height) * -1);
margin-top: var(--line);
margin-bottom: calc(var(--line) * -1);
width: 100%;
border-collapse: collapse;
}
@ -250,7 +246,7 @@ thead {
display: none;
}
tr td {
padding-bottom: calc(var(--font-size) * var(--line-height));
padding-bottom: var(--line);
}
td:nth-child(1) {
color: var(--primary-color);
@ -270,7 +266,7 @@ ul {
column-gap: calc(var(--font-size) * 3);
list-style-type: none;
padding: 0;
margin: calc(var(--font-size) * var(--line-height)) 0;
margin: var(--line) 0;
margin-left: calc(var(--font-size) * 1.42);
}
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
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, 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;
html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
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 */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
display: block;
}
body {
line-height: 1;
line-height: 1;
}
ol, ul {
list-style: none;
ol,
ul {
list-style: none;
}
blockquote, q {
quotes: none;
blockquote,
q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
blockquote:before,
blockquote:after,
q:before,
q:after {
content: "";
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
border-collapse: collapse;
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