Luigi Cavalieri - Full-stack Developer

Testing SCSS Locally: How to Build a Simple Node-based Playground

Today I want to describe to you how to build a simple and flexible playground to test SCSS code locally — if you are a DIYer there are good chances you'll enjoy the post.

Testing SCSS Locally: How to Build a Simple Node-based Playground

There are a number of online services that let us run SCSS code on-the-fly, but at times none of them can replace the convenience offered by an offline playground. That's why today I want to describe to you how to build a simple and flexible playground to test SCSS code locally — if you are a DIYer there are good chances you'll enjoy the post.

The playground in question is a simple web server relying on Node.js. In particular we will build it using the Express.js framework and a few other packages. The playground will not only be able to run our SCSS, but also to automatically rerun it when we save changes and to refresh the browser's page without having to manually launch a reload.

If you never heard of Express.js don't worry, because I'll provide enough explanations to let you understand what the code does. However, even if your daily meal is front-end development, having a smattering on how to build a Node-based web server can be a game changer in your career. So I strongly encourage you to take some time to get familiar with the Express.js framework, if you haven't already.

First, Let's Create a package.json

Have you already created a new folder for our playground, by any chance? Not yet? Well, this is the right time to do it. I named mine scss-playground, but you can choose another name if you wish.

Now, with your shell application, navigate to the just created folder and launch the initialisation of the package.json file as shown below:

1cd path-to/scss-playground
2npm init

You can safely go through the creation of the package.json file by leaving unchanged the default values. At the end of the process, the generated package.json should have a content similar to this:

1{
2  "name": "scss-playground",
3  "version": "1.0.0",
4  "description": "",
5  "main": "index.js",
6  "scripts": {
7    "test": "echo \"Error: no test specified\" && exit 1"
8  },
9  "author": "",
10  "license": "ISC"
11}

Building the Playground

With a package.json at hand, the dependencies needed by our playground can be installed without any trouble. First however, I would like to tell you about the other three files required by our app, so please create the following files and folders in the same directory as our package.json:

1- index.js
2- package.json
3+ public
4  - index.html
5+ styles
6  - main.scss
  • index.js will contain all the JavaScript needed to create, deal with and launch our web server.
  • public/index.html is where you can write your markup, the one on which to apply the SCSS rules you want to test.
  • And finally, styles/main.scss is where to place your SCSS code.

The dependencies I was referring to can be installed with the following npm command:

1npm install express sass concurrently

As you can see, they are three:

  • express is the Node-based framework I chose to streamline the server-related code.
  • sass will be responsible to process your SCSS code and watch for changes to the main.scss file.
  • concurrently is an utility to run multiple shell commands in parallel.

About the install command, one might argue by saying that sass and concurrently are development dependencies and they should be installed as such — with the --save-dev option — and it would be a correct remark, since they are tools needed only during development. The reason why we are installing them as production dependencies is to keep things as simple as possible, after all our playground isn't an app thought to be released to the public.

For the same reason we are going to keep the code needed to create our web server as minimal as possible, so the following goes into the index.js file of our playground:

1const express = require( "express" );
2
3const port       = 3000;
4const publicPath = ( __dirname + "/public" );
5
6const app = express();
7
8app.use( "/", express.static( publicPath ) );
9
10app.listen( port, () => {
11  console.log( `Server running: http://localhost:${port}` );
12});

Without going into too much detail, the snippet above does the following:

  1. Creates an Express web server.
  2. Through the express.static() middleware, instructs the server to serve all the files in our public folder without any prior processing, as static files.
  3. Launches the web server on port 3000.

The next step to take is to update the scripts property of our package.json as follows:

1{
2  "name": "scss-playground",
3  "version": "1.0.0",
4  "description": "",
5  "scripts": {
6    "start": "node .",
7    "sass": "sass --watch styles/main.scss public/styles.css",
8    "dev": "concurrently 'npm start' 'npm run sass'"
9  },
10  "author": "",
11  "license": "ISC",
12  "dependencies": {
13    "concurrently": "^8.2.2",
14    "express": "^4.19.2",
15    "sass": "^1.77.1"
16  }
17}

To make everything more readable, I split the custom script we need into three separate ones:

  • start tells Node to execute our index.js.
  • sass transforms our main.scss file into a browser-friendly styles.css style-sheet that will be saved into our public folder. Also, the --watch option ensures that any changes to main.scss will automatically trigger an update of the public/styles.css style-sheet.
  • Finally, dev is the script we will use to give life to our playground. It uses the concurrently utility to run the start and sass scripts in parallel.

Running the First Test

Now our playground needs only some testing code. You can use the following code as the content of your public/index.html document:

1<!DOCTYPE html>
2<html lang="en">
3<head>
4  <meta charset="UTF-8">
5  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6  <title>SCSS Playground</title>
7  <link rel="stylesheet" href="styles.css" />
8</head>
9<body>
10  <p>Hello world!</p>
11</body>
12</html>

An important reminder: as highlighted in the snippet above, our index.html document must include a link to the styles.css file generated by sass, otherwise no styling will appear in the browser.

All right, let's proceed.

To run your first test you just need to include a SCSS snippet like the following, for instance, in your styles/main.scss file...

1$font-weight-semibold: 600;
2
3body {
4  font-weight: $font-weight-semibold;
5}

...and launch the dev script:

1npm run dev

It's that easy.

Right now however, if you try to make some changes to your main.scss and then you save them, you'll notice that the web page doesn't automatically refresh. This is because something is still missing, and that something is called LiveReload.

Live Refreshes on Saving Changes

LiveReload for Node.js is the tool without which our playground cannot automatically refresh the browser's page.

To integrate LiveReload into our playground, we first need to install the required packages:

1npm install livereload connect-livereload

And then write a few more lines of JavaScript into our index.js script. Namely, the instructions highlighted in the snippet below:

1const express           = require( "express" );
2const livereload        = require( "livereload" );
3const connectLivereload = require( "connect-livereload" );
4
5const port       = 3000;
6const publicPath = ( __dirname + "/public" );
7
8const app              = express();
9const livereloadServer = livereload.createServer();
10
11livereloadServer.watch( publicPath );
12
13app.use( connectLivereload() );
14app.use( "/", express.static( publicPath ) );
15
16app.listen( port, () => {
17  console.log( `Server running: http://localhost:${port}` );
18});

What we are doing with the new lines of code is this:

  1. First we create a LiveReload server.
  2. Then we instruct the LiveReload server to watch for any changes occurring in our public folder — remember that the styles.css style-sheet, resulting from the processing of main.scss, is saved to the public folder.
  3. And lastly, we ask our Express server to apply the connectLivereload() middleware, which makes all the browser-refresh-magic happen.

Just a closing note: for the live refreshes to take place, you need to restart the playground, by stopping the Express server (CTRL + C) and relaunching it with a new npm run dev.

Conclusion

As you will find out by using it, the playground, such as it is, can be used not just to test snippets of SCSS, but also entire style-sheets imported in the main.scss file. And the good news is that this is possible without having to sacrifice the live-refresh feature offered by LiveReload.

Now you just have to make your SCSS shine!