Skip to content

Instantly share code, notes, and snippets.

@pascalduez
Last active September 28, 2023 12:43
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pascalduez/247e564da1d388ac6fb2db72490a7a3a to your computer and use it in GitHub Desktop.
Save pascalduez/247e564da1d388ac6fb2db72490a7a3a to your computer and use it in GitHub Desktop.
Eleventy stylesheets

Eleventy stylesheets

Listing and comparing the different stylesheet preprocessing approachs in Eleventy (11ty)

We use PostCSS here, but could be Sass, or both, or anything else

Include

.
├── .eleventy.js
├── package.json
├── postcss.config.js
├── _includes
│   ├── base.njk
│   └── index.css
└── index.md

package.json

"scripts": {
  "serve": "NODE_ENV=development eleventy --serve",
  "build": "NODE_ENV=production eleventy",
},
"devDependencies": {
  "@11ty/eleventy": "^0.10.0",
  "cssnano": "^4.1.10",
  "postcss": "^7.0.27",
  "postcss-load-config": "^2.1.0",
  "postcss-preset-env": "^6.7.0",
}

postcss.config.js

module.exports = ({ env }) => ({
  plugins: {
    'postcss-preset-env': {},
    ...(env === 'production' && { cssnano: {} }),
  },
});

.eleventy.js

const postcss = require('postcss');
const postcssrc = require('postcss-load-config');

module.exports = config => {
  config.addNunjucksAsyncFilter('postcss', async (content, callback) => {
    let { plugins, options } = await postcssrc();
    let result = await postcss(plugins).process(content, options);
    callback(null, result.css);
  });
};

_includes/base.njk

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    {% set css %}
      {% include "index.css" %}
    {% endset %}
    <style>
      {{ css | postcss | safe }}
    </style>
  </head>
  <body>
    {{ content | safe }}
  </body>
</html>

index.md

---
layout: base
---

<h1>11ty stylesheets</h1>

Cons

  • No fit for a large CSS codebase
  • Triggers a full website build on every css change
  • CSS processing get re-run for every output html file
  • Triggers a full page reload

Pros

  • No extra dependencies / builders etc.
  • No extra HTTP request
  • Might be handy for critical path CSS inlining

JS template

.
├── .eleventy.js
├── _includes
│   └── base.njk
├── index.md
├── main.11ty.js
├── package.json
├── postcss.config.js
└── styles
    └── index.css

package.json

"scripts": {
  "serve": "NODE_ENV=development eleventy --serve",
  "build": "NODE_ENV=production eleventy",
},
"devDependencies": {
  "@11ty/eleventy": "^0.10.0",
  "cssnano": "^4.1.10",
  "postcss": "^7.0.27",
  "postcss-load-config": "^2.1.0",
  "postcss-preset-env": "^6.7.0",
}

postcss.config.js

module.exports = ({ env }) => ({
  plugins: {
    'postcss-preset-env': {},
    ...(env === 'production' && { cssnano: {} }),
  },
});

.eleventy.js

module.exports = config => {
  config.addWatchTarget('styles/');
};

_includes/base.njk

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="/styles/main.css" />
  </head>
  <body>
    {{ content | safe }}
  </body>
</html>

main.11ty.js

const { readFile } = require('fs').promises;
const postcssrc = require('postcss-load-config');
const postcss = require('postcss');

exports.data = () => ({
  permalink: 'styles/main.css',
  eleventyExcludeFromCollections: true,
});

exports.render = async () => {
  let { plugins, options } = await postcssrc();
  let content = await readFile('styles/index.css');
  let result = await postcss(plugins).process(content, options);

  return result.css;
};

index.md

---
layout: base
---

<h1>11ty stylesheets</h1>

Cons

  • Triggers a full website build on every css change
  • Might triggers a full page reload (depending on setup)

Pros

  • No extra dependencies / builders etc.
  • Fit for a large CSS codebase
  • CSS processing gets run only once
  • Extensible

External build

.
├── .eleventy.js
├── _includes
│   └── base.njk
├── index.md
├── package.json
├── postcss.config.js
└── styles
    └── index.css

package.json

"scripts": {
  "build:css": "postcss styles/index.css -o _site/styles/main.css --verbose",
  "11ty:serve": "eleventy --serve",
  "11ty:pack": "eleventy",
  "serve": "NODE_ENV=development run-p 11ty:serve 'build:css --watch'",
  "build": "NODE_ENV=production run-p 11ty:pack build:css"
},
"devDependencies": {
  "@11ty/eleventy": "^0.10.0",
  "cssnano": "^4.1.10",
  "npm-run-all": "^4.1.5",
  "postcss": "^7.0.27",
  "postcss-cli": "^7.1.0",
  "postcss-load-config": "^2.1.0",
  "postcss-preset-env": "^6.7.0"
}

postcss.config.js

module.exports = ({ env }) => ({
  plugins: {
    'postcss-preset-env': {},
    ...(env === 'production' && { cssnano: {} }),
  },
});

.eleventy.js

module.exports = config => {
  config.setBrowserSyncConfig({
    files: ['_site/styles'],
  });
};

_includes/base.njk

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="/styles/main.css" />
  </head>
  <body>
    {{ content | safe }}
  </body>
</html>

index.md

---
layout: base
---

<h1>11ty stylesheets</h1>

Cons

  • Adds a few building dependencies (postcss-cli, npm-run-all)

Pros

  • Extensible
  • CSS processing gets run only once
  • Fit for a large CSS codebase
  • Don't triggers a full website build on every css change
  • True hot reload
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment