Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 60 additions & 6 deletions .eleventy.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
const fs = require("node:fs");
const path = require("node:path");
const browserslist = require("browserslist");

const {
bundle,
bundleAsync,
browserslistToTargets,
composeVisitors,
} = require("lightningcss");
Expand All @@ -21,7 +22,7 @@ try {
try {
const browserslistrc = path.resolve(
__dirname,
fs.realpathSync(".browserslistrc")
fs.realpathSync(".browserslistrc"),
);

fs.readFile(browserslistrc, "utf8", (_err, data) => {
Expand Down Expand Up @@ -49,9 +50,10 @@ module.exports = (eleventyConfig, options) => {
nesting: true,
customMedia: true,
minify: true,
sourceMap: false,
sourceMap: true,
visitors: [],
customAtRules: {},
debug: false,
};

const {
Expand All @@ -62,6 +64,7 @@ module.exports = (eleventyConfig, options) => {
sourceMap,
visitors,
customAtRules,
debug,
} = {
...defaults,
...options,
Expand All @@ -74,8 +77,17 @@ module.exports = (eleventyConfig, options) => {
eleventyConfig.addExtension("css", {
outputFileExtension: "css",
compile: async function (_inputContent, inputPath) {
// log to find the content
let parsed = path.parse(inputPath);

// if the file starts with the `importPrefix`do do anything with it.
if (parsed.name.startsWith(importPrefix)) {
// if debug declare dependencies in the log
if (debug) {
console.log(
`[11ty-lightningCSS] ${parsed.dir}${parsed.base} was marked as dependency`,
);
}
return;
}

Expand All @@ -99,9 +111,12 @@ module.exports = (eleventyConfig, options) => {

let targets = browserslistToTargets(browserslist(browserslistTargets));

return async () => {
let { code } = await bundle({
//create the folder if it doesnt exit

return async (data) => {
let { code, map } = await bundleAsync({
filename: inputPath,
// code: Buffer.from(_inputContent),
minify,
sourceMap,
targets,
Expand All @@ -111,9 +126,48 @@ module.exports = (eleventyConfig, options) => {
},
customAtRules,
visitor: composeVisitors(visitors),
resolver: {
read(filePath) {
// Read the file content
let content = fs.readFileSync(filePath, "utf8");

// Apply a transformation: Replace a placeholder with a value
content = removeYaml(content);
// Return the transformed content
return content;
},
resolve(specifier, from) {
return path.resolve(path.dirname(from), specifier);
},
},
});
return code;

let mapComment = "";

const link = path.parse(data.page.outputPath);

if (sourceMap) {
const sourceMapLocation = `./${link.name}.map`;

// Get the directory name from the sourcemap location
let url = fs.mkdirSync(link.dir, {
recursive: true,
});

// Ensure the directory exists
fs.writeFileSync(data.page.outputPath.replace(".css", ".map"), map);

//write the comment in the css to set the source map
mapComment = `/*# sourceMappingURL=${sourceMapLocation} */`;
}

return code + "\n" + mapComment;
};
},
});
};
/*remove yaml front matter from a string*/
function removeYaml(content) {
const yamlFrontmatterRegex = /^---\s*[\s\S]*?\s*---\s*/;
return content.replace(yamlFrontmatterRegex, "");
}
27 changes: 18 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,16 @@ Then, write your CSS using any organization pattern you like as long as it lives

### Base options

| Option | Type | Default |
| ------------- | ------- | ------- |
| importPrefix | string | '\_' |
| nesting | boolean | true |
| customMedia | boolean | true |
| minify | boolean | true |
| sourceMap | boolean | false |
| visitors | array | [] |
| customAtRules | object | {} |
| Option | Type | Default | Use |
| ------------- | ------- | ------- | ------------------------------------------------------------------------------------------------------- |
| importPrefix | string | '\_' | file starting with this prefix will have not output (they can still be used with `@import` for example) |
| nesting | boolean | true | allows for CSS nesting |
| customMedia | boolean | true | allows for custom media queries |
| minify | boolean | true | render a minified version |
| sourceMap | boolean | false | generate a source map file |
| visitors | array | [] | add visitors (read the documentation from lightningCSS) |
| customAtRules | object | {} | custom `@something` (read the documentation from lightningCSS) |
| debug | boolean | false | show more information in eleventy console |

### Bundling Import Prefix

Expand Down Expand Up @@ -139,3 +140,11 @@ module.exports = (eleventyConfig) => {
## How does it work?

This plugin uses Eleventy's `addTemplateFormats` and `addExtension` features to essentiallly recognize CSS as a first-class templating language, and add custom processing. Since it makes CSS into a templating language, changes are applied during local development hot-reloading without a delay or requiring a manual browser refresh.

## Source map and permalink

Your CSS file can start with a front matter than eleventy will use, which can be pretty useful to set a permalink for a css file.

We added a custom resolver to the bundle to remove all the frontmatter before it gets out.

A source map will be added for each the file, unless the `options.sourcemap` is set to false.
36 changes: 36 additions & 0 deletions css/style-with-permalink.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
permalink: "/css/thisisworking/permalink.css"
---

@import "imports/_reset.css" layer(reset);
@import "./_partial.css";

body {
container: body / inline-size;
font-family: system-ui;

& p {
font-size: 1.25rem;
color: hsl(from dodgerblue h s calc(l - 30%));
}

* + * {
margin-top: 1em;
}
}

body:has(p) {
--paragraphs: true;
}

@container body (inline-size > 500px) {
p {
background-color: hsl(130 80% 90%);
}

@container style(--paragraphs: true) {
p:first-of-type {
font-weight: bold;
}
}
}
Loading