Implemented ESM and optimizations
This commit is contained in:
parent
f6fbea2cdf
commit
5f8181b374
102
.eleventy.js
102
.eleventy.js
@ -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,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -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
1079
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -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
12
purgecss.config.cjs
Normal 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: [],
|
||||
},
|
||||
};
|
@ -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>
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 226 KiB After Width: | Height: | Size: 226 KiB |
Before Width: | Height: | Size: 182 KiB After Width: | Height: | Size: 182 KiB |
Loading…
Reference in New Issue
Block a user