Last active
January 11, 2025 19:57
-
-
Save Nooshu/edfc2e382bc249e92ab238779357c93e to your computer and use it in GitHub Desktop.
ESM manipulation file I use on my 11ty v3.0.0 blog for manipulating my CSS.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import dotenv from "dotenv"; | |
import CleanCSS from 'clean-css'; | |
import fs from 'fs'; | |
import crypto from 'crypto'; | |
import path from 'path'; | |
dotenv.config(); | |
// create a single instance of the CleanCSS function | |
// to be used in file loops. Add additional optimisation settings in here. | |
const cleanCSS = new CleanCSS({ | |
level: { | |
2: { | |
removeDuplicateRules: true // turns on removing duplicate rules | |
} | |
} | |
}); | |
export function manipulateCSS(eleventyConfig) { | |
eleventyConfig.addShortcode("customCSS", async function(cssPath) { | |
// output the file with no fingerprinting if on the dev environment | |
// (allows auto-reload when the CSS is modified) | |
if (process.env.ELEVENTY_ENV === 'development') { | |
return `<link rel="stylesheet" href="${cssPath}">`; | |
} | |
// Using path.join for better cross-platform compatibility | |
const inputFile = path.join('./public', cssPath); | |
const outputDirectory = path.join('./_site', 'css'); | |
const cacheDirectory = path.join('./.cache', 'css'); | |
try { | |
// Check if input file exists first | |
if (!fs.existsSync(inputFile)) { | |
console.error(`Input CSS file not found: ${inputFile}`); | |
return ''; | |
} | |
// Ensure both cache and output directories exist | |
for (const dir of [cacheDirectory, outputDirectory]) { | |
if (!fs.existsSync(dir)) { | |
fs.mkdirSync(dir, { recursive: true }); | |
} | |
} | |
// Read the input CSS file | |
const inputCSS = await fs.promises.readFile(inputFile, 'utf8'); | |
// Initialises a new hashing instance | |
const hash = crypto.createHash('sha256') | |
// Feed CSS data into the hash function | |
.update(inputCSS) | |
// Specify the hash should be returned as a hexadecimal string | |
.digest('hex') | |
// Only take the first 10 characters of the hash | |
.slice(0, 10); | |
// Generate our CSS Cache name | |
const cacheKey = `${hash}-${cssPath.replace(/[\/\\]/g, '-')}`; | |
// This is where the file will be written | |
const cachePath = path.join(cacheDirectory, cacheKey); | |
// store our manipulated CSS in this variable | |
let processedCSS; | |
// check we have a cache directory | |
if (fs.existsSync(cachePath)) { | |
// read the cached CSS file | |
processedCSS = await fs.promises.readFile(cachePath, 'utf8'); | |
} else { | |
// Use the memoized cleanCSS instance to minify the CSS | |
processedCSS = cleanCSS.minify(inputCSS).styles; | |
await fs.promises.writeFile(cachePath, processedCSS); | |
} | |
// Split the input file path into its components (directory, filename, extension) | |
const parsedPath = path.parse(inputFile); | |
// Use path.join for output paths | |
const finalFilename = path.join(outputDirectory, `${parsedPath.name}-${hash}${parsedPath.ext}`); | |
// Write the minified CSS to the final output location with the hash in the filename | |
await fs.promises.writeFile(finalFilename, processedCSS); | |
// path manipulation for final URL | |
const hashedPath = finalFilename.replace(path.join('./_site'), '').replace(/\\/g, '/'); | |
// return our final link element with minified and fingerprinted CSS. | |
return `<link rel="stylesheet" href="${hashedPath}">`; | |
} catch (err) { | |
console.error("Error processing CSS:", err); | |
return ""; | |
} | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment