Simple SCSS with 11ty
Published on 24 February 2020 at 19:32 by
Since migrating my blog to DEV, I've been looking at rebuilding my website as a simple signpost to my various activities on the web, and with this I've been looking into static site generators, and focusing mostly on 11ty.
I've been looking through philhawksworth/eleventyone which for the most part gives a nice overview of the workings of 11ty. But one thing it didn't include was SCSS preprocessing. Instead, Phil opted for standard css preprocessing.
One thing I'm good at is searching the internet, but try as I might for almost 5 long minutes, I couldn't find a good solution out there for this. Phil created a gulp-powered SCSS preprocessor, but I didn't really want to add gulp into the mix. He wrote about how as you add in SCSS your complexity increases but I don't think this has to be the case. I carried on looking, and I found someone who was preprocessing SCSS and writing it to a file. I didn't want to generate files before I generate files either, that xzibits¹ too much recursion for my liking.
After looking at everything I'd seen so far, and deciding to do some thinking of my own, I came up with a way that you can easily add SCSS preprocessing to an 11ty project.
The Solution
As I understand it, by having a file with a .11ty.js
suffix, you're able to introduce some functionality into an endpoint, the path of which you can define in the permalink
field of the data()
method in the class you return. You can then define the output of that endpoint by returning a string from the render()
methods of that class.
Well, once you realise this, it's quite simple really. Assuming we have a directory structure like so, with the scss files within the includes directory and a JavaScript file within the css directory.
site/
site/_includes/
site/_includes/scss/
site/_includes/scss/main.scss
site/css/
site/css/style.11ty.js
site/index.md
All we need to do is use a scss-to-css module (in this case node-sass-promise
), render the scss files into css, and then for good measure, clean it before we send it out.
const path = require('path')
const sass = require('node-sass-promise')
const CleanCSS = require('clean-css')
const inputFile = path.join(__dirname, '../_includes/scss/main.scss')
const outputFile = path.join(__dirname, '../css/style.css')
const comment = `/* This is an example comment */`
module.exports = class {
data() {
return {
permalink: 'css/style.css',
eleventyExcludeFromCollections: true
}
}
async render() {
const { css } = await sass.render({ file: inputFile })
const output = new CleanCSS({}).minify(css.toString()).styles
return `${comment}\n\n${output}`
}
}
Now, I'm notorious for adding comments to the beginning of every source file. I'm old school, and also, I feel old. But when I work with a file that doesn't have a banner comment I don't feel right. With this in mind, I've also added the ability to place a header comment in while removing all other chaff from the scss and placing the clean, processed css afterwards.
This all results in the endpoint css/style.css
being generated via the render()
method and outputting something like this:
/* This is an example comment */
*{margin:0;padding:0}body{padding:1rem;}h1{font-size:3rem;}
So to summarise, you create a file site/css/style.11ty.js
in which you read from an input file ../_includes/scss/main.scss
, run it through some npm packages (sass, clean-css etc) and then return it as a string so that the 11ty generator can store it somewhere useful.
On the subject of banner comments, I much prefer fancier versions that a simple line of text, such as catsofinternet.org...
_ __ _ _ _
| | / _(_) | | | |
___ __ _| |_ ___ ___ | |_ _ _ __ | |_ ___ _ __ _ __ ___| |_ ___ _ __ __ _
/ __/ _` | __/ __|/ _ \| _| | '_ \| __/ _ \ '__| '_ \ / _ \ __| / _ \| '__/ _` |
| (_| (_| | |_\__ \ (_) | | | | | | | || __/ | | | | | __/ |_ | (_) | | | (_| |
\___\__,_|\__|___/\___/|_| |_|_| |_|\__\___|_| |_| |_|\___|\__(_)___/|_| \__, |
__/ |
|___/
Or internetdogs.com...
.-. / /
`-'. .-.---/---.-. ).--.. .-. .-.---/---
/ )/ ) / ./.-'_/ )/ )./.-'_ /
_.(__. '/ ( / (__.'/ '/ ( (__.' /
. `- `-
/
.-../ .-._..-. . .-. .-._.. .-. .-.
( / ( )( ) / \ .-.( ( ) )/ ) )
`-'-..`-' `-/-'/ ._)`-' `---'`-' '/ / (
-._/ / `-'
Or httprefs.org...
__ __ ______ ______ ____ ____ ___ _____ _____ ___ ____ ____
| | || || || \| \ / _]| |/ ___/ / \ | \ / |
| | || || || o ) D ) / [_ | __( \_ | || D )| __|
| _ ||_| |_||_| |_|| _/| / | _]| |_ \__ | | O || / | | |
| | | | | | | | | | \ | [_ | _] / \ | __ | || \ | |_ |
| | | | | | | | | | . \| || | \ || || || . \| |
|__|__| |__| |__| |__| |__|\_||_____||__| \___||__| \___/ |__|\_||___,_|
But I mean, that's not really important is it? If you do like banner comments like this, the patorjk taag site is super useful and has been for many years.
Check it out.
¹ xzibit joke not typo