Search code examples
expresssassnode-sass

How to migrate from node-sass to sass (dart sass) in an express app


With LibSass deprecated, I see that I should replace the node-sass library with sass. In an express app, previously, you would use the node-sass-middleware and node-sass like so:

const express = require('express');
const sassMiddleware = require('node-sass-middleware');
const path = require('path');
const app = express();
app.use(sassMiddleware({
    /* Options */
    src: __dirname,
    dest: path.join(__dirname, 'public'),
    debug: true,
    outputStyle: 'compressed',
    prefix:  '/prefix'  href="prefix/style.css"/>
}));

app.use('/public', express.static(path.join(__dirname, 'public')));

The only indication I found about how to use the sass module with express is this article. This method does not use a middleware but instead runs the sass module via a script (configured inside the packages.json file). Here is the relevant part of the article:

"scripts": {
    "start": "node .",
    "dev": "nodemon . & npm run scss",
    "scss": "sass --watch src/scss/main.scss public/styles/main.css"
},

But my confidence in this article is low. For starters, it seems to be compiling sass only in development (the "start" script does not use the "scss" script). Also, this method does not use a middleware.

So, I guess I have 2 questions:

  1. is there a way to use a middleware (like the old node-sass-middleware) to use the sass module with express? (It would be easier to update my code and I'm lazy...)
  2. If not, is the example in the article the correct way to use sass with express?

Solution

  • I didn't want to rely on remembering to run a script manually (I would definitely forget to do it) and combining scripts with "&" (or even "&&") like in the article was not working so well for me.

    I wanted to use code to launch the script, so what I did is just compile my CSS synchronously when the server starts.

    Here is my code:

    app.js

    
    const express = require('express');
    const path = require('path');
    const { compileCss } = require('./compileCss');
    
    const app = express();
    const sassOptions = {
      src: path.join(__dirname, 'public'),
      dest: path.join(__dirname, 'public')
    };
    compileCss(sassOptions);
    
    app.use('/public', express.static(path.join(__dirname, 'public')));
    # ... rest of app.js code
    

    compileCss.js

    const sass = require('sass');
    const { readdirSync , writeFileSync} = require('fs');
    const path = require('path');
    
    
    const compileCss = ({src, dest, ext=[".sass", ".scss"]}) => {
    
        const srcFiles = readdirSync(src, {withFileTypes: true}).filter(dirent => dirent.isFile() && ext.includes(path.extname(dirent.name)));
        for(const file of srcFiles) {
            const srcFilePath = path.join(src, file.name);
            const baseName = path.basename(file.name, path.extname(file.name));
            const cssName = baseName + '.css';
            const destFilePath = path.join(dest, cssName);
            const result = sass.compile(srcFilePath);
            writeFileSync(destFilePath, result.css, 'utf-8');
        }
    
    }
    
    module.exports = { compileCss }