Processing sass with 11ty
Tags: 11ty, sass, eleventy, node
Published: 2019-10-14 04:23:32

---
title: Processing sass with 11ty
published: true
description: My custom way to process sass on projects built with Eleventy static site generator.
tags: 11ty, sass, eleventy, node
---
> Even though I've been using the solution described below with good success on POC and side projects, I believe it is not optimal in most situation. It's easier and probably more efficient to use the CLI as described here: {% post https://dev.to/jkc_codes/using-sass-with-eleventy-21le %} Anyhow, it's nice to know the options.

## My Eleventy (11ty) project
I recently discovered [11ty](https://www.11ty.io/) and used the [static site generator](https://dev.to/ruthreyer/what-are-static-site-generators-356p ) to build a business website. I like that 11ty allows working with different templates and mixing them too. In this site I used [Nunjucks](https://mozilla.github.io/nunjucks/), Markdown and [Sass](https://sass-lang.com/). Now, 11ty doesn't have Sass pre-processing built-in. So I had to find my own way.
## Turning scss into css
There are a few approches to solve this problem using [filters](https://www.11ty.io/docs/filters/) or [Gulp](https://www.hawksworx.com/blog/keeping-sass-simple-and-speedy-on-eleventy/). I had used the [Gulp](https://gulpjs.com/) way in another project, but for this one I wanted to do something else. So I wrote a [Node](https://nodejs.org/en/) script instead!
## The code
The neat thing about 11ty is that it's written in JavaScript. So you can run in `.eleventy.js` config file any executable code that you like as long as it's JavaScript. So here's the function that I use on my project to pre-process scss files.

*/config/sass-process.js*
```js
const sass = require('sass');
const fs = require('fs-extra');
const path = require('path');

module.exports = (scssPath, cssPath) => {
    //If cssPath directory doesn't exist...
    if(!fs.existsSync(path.dirname(cssPath))) {
        //Encapsulate rendered css from scssPath into result variable
        const result = sass.renderSync({file: scssPath});
        //Create cssPath directory recursively
        fs.mkdir(path.dirname(cssPath), {recursive: true})
        //Then write result css string to cssPath file
        .then(() => fs.writeFile(cssPath, result.css.toString()))
        .catch(error => console.error(error))
    }
    //Watch for changes to scssPath directory...
    fs.watch(path.dirname(scssPath), () => {
        console.log(`Watching ${path.dirname(scssPath)}...`);
        //Encapsulate rendered css from scssPath into watchResult variable
        const watchResult = sass.renderSync({file: scssPath});
        //Then write result css string to cssPath file
        fs.writeFile(cssPath, watchResult.css.toString())
        .catch(error => console.error(error))      
    });
}
```  
And then include that function in `.eleventy.js` file as so.

*.eleventy.js*
```js
const sass = require('./config/sass-process');

module.exports = config => {
    //Watching for modificaions in style directory
    sass('./style/index.scss', './docs/style/index.css');
}
```
## Refactoring this code to make it asynchronous
The solution above works fine for my need. Thing is that I'm using the synchronous method to render `sass`  `sass.renderSync()` and that code is blocking (very little, but still). There are mainstream solutions to render `css` from `sass` asynchronously like the [node-sass](https://github.com/sass/node-sass/blob/master/README.md) library with its asynchronous `render()` method witch I can turn into a `promise` like so.
```js
const sass = require('node-sass');
const cssResultFrom = file => {
    return new Promise((resolve, reject) => {
        sass.render({file: file}, (error, result) => {
            if(error) {
                reject(error);
            }
            resolve(result);
        });
    });
}
//Then to use it...
cssResultFrom(scssPath)
```
Instead of writing my own `Promise` wrapper, I could use a module that does it for me like the fairly new [node-sass-promise](https://github.com/samsoul007/node-sass-promise).
```js
//node-sass-promise method
const sass = require('node-sass-promise');
//And to use it...
sass.render({file: scssPath})
```
A little less flexible then writing my own wrapper, but less code to write! An exemple of code using `node-sass-promise` :
```js
const sass = require('node-sass-promise');
const fs = require('fs-extra');
const path = require('path');

module.exports = (scssPath, cssPath) => {
    //If cssPath directory doesn't exist...
    if(!fs.existsSync(path.dirname(cssPath))) {
        //Create cssPath directory recursively
        fs.mkdir(path.dirname(cssPath), {recursive: true})
        //Render css from sass
        .then(() => sass.render({file: scssPath}))
        //Then write result css string to cssPath file
        .then(result => fs.writeFile(cssPath, result.css.toString()))
        .catch(error => console.error(error))
    }
    //Watch for changes to scssPath directory...
    fs.watch(path.dirname(scssPath), () => {
        //Render css from sass...
        sass.render({file: scssPath})
        //Then write result css string to cssPath file
        .then(result => fs.writeFile(cssPath, result.css.toString()))
        .catch(error => console.error(error))
        console.log(`Watching ${path.dirname(scssPath)}...`);      
    });
}
```
## My stack
|Software|version|
|--------|-------|
|OS      |Linux Mint 18.2 Sonya|
|Node    |10.15.0|
|NPM     |6.8.0  |
|11ty    |0.8.3  |
## The end
Thanks for reading! :-)