So far we’ve looked at npm as a tool for fetching parts. In this lesson we try its other face—a tool for running work—using “convert Sass to CSS” as the subject. Once this clicks, you can read what any project out there is doing when it says npm run build.
scripts field first makes this lesson go down easilyWhat is a build?
Converting something written in a format the browser can’t read into a format it can.
In this example, browsers don’t understand a .scss file. So it has to be written out as .css. That writing-out is the build.
| Without a build | With a build | |
|---|---|---|
| The file you write | style.css | style.scss |
| The file the browser reads | style.css (the same one) | style.css (produced by the conversion) |
| After you save | Just reload | Convert → reload |
“I saved it and nothing changed” gains one more possible cause—that’s the price of adding a build. Which is why this article goes all the way to --watch, which automates that extra step.
What you need
If Node.js is installed, nothing else. Check in the terminal.
node -v
npm -vVersion numbers from both means you’re set. If not, start with installing Node.js.
npmWhat is npm? What does npm install actually do?The relationship between Node.js and npm, and installing them1. Make a practice folder
Create an empty folder anywhere and move into it in the terminal. Opening the folder in VSCode and using its built-in terminal (⌃ + backtick) is the easiest route.
mkdir sass-practice
cd sass-practice2. Create package.json
npm init makes one. Adding -y answers yes to every question and creates it immediately.
npm init -yThere’s now a package.json in the folder. That’s this project’s manual.
3. Install sass
Install the tool that runs the conversion. It’s only used while developing, so add -D (put it in devDependencies).
npm install -D --save-exact sass--save-exact means “record the version exactly, without a ^.” With it, package.json gets "sass": "1.83.0" (without it, "^1.83.0").
^, and why pinning mattersIf typing --save-exact every time is tiresome, create a file called .npmrc in the folder with one line, and versions are pinned from then on.
save-exact=true4. Prepare two files
Create the source .scss and the destination folder.
mkdir src cssCreate src/style.scss with some distinctly Sass-flavoured code.
$main-color: #ff8a3d;
.card {
padding: 16px;
border: 2px solid $main-color;
&__title {
color: $main-color;
font-size: 20px;
}
&:hover {
background: #fff3ea;
}
}$main-color is a variable, and &__title is class-name joining (the form that produces .card__title). We’ll compare how these expand after conversion.
5. Run the conversion
First type the command directly.
npx sass src/style.scss css/style.cssnpx is the tool for calling a command from a package you installed. Without it you get sass: command not found (that package only exists inside this folder, so the name alone can’t be found).
If it worked, css/style.css now exists. Open it.
.card {
padding: 16px;
border: 2px solid #ff8a3d;
}
.card__title {
color: #ff8a3d;
font-size: 20px;
}
.card:hover {
background: #fff3ea;
}The variable was replaced by its actual value, and &__title expanded into the flat class name .card__title. That’s what Sass is really doing. The browser reads only this file.
6. Register it in scripts for a shorter call
Typing that long command every time isn’t realistic, so give it a name in package.json’s scripts.
{
"scripts": {
"build": "sass src/style.scss css/style.css",
"watch": "sass --watch src/style.scss css/style.css"
},
"devDependencies": {
"sass": "1.83.0"
}
}Now the call is short.
npm run buildTyping just npm run lists every task the project can run. Handy when you want to know what a project you’ve never touched can do.
7. Automate it with --watch
Run the other script you registered.
npm run watchThe command doesn’t finish—it waits. In that state, edit and save src/style.scss and the conversion runs the moment you save. You’ll see the log scroll in the terminal.
That automates the middle of “save → convert → reload,” so it costs about as many keystrokes as having no build at all. Press Ctrl + C in the terminal to stop.
8. Don’t put node_modules in Git
Installing creates a huge node_modules folder. It can be restored from package.json, so it isn’t managed in Git. Create a .gitignore and note it.
node_modules/Conversely, always put package.json and package-lock.json in Git. With those two, another machine can restore the same state with just npm install.
Where people get stuck
| Symptom | Cause and fix |
|---|---|
sass: command not found | Add npx, or put it in scripts and use npm run |
npm run build says Missing script | No such name in scripts. Check the spelling |
| No CSS file appears | The output folder (css) doesn’t exist. mkdir css first |
| The conversion succeeds but the page doesn’t change | Check your HTML’s link isn’t pointing at the .scss. The browser reads the .css |
| watch does nothing | Are you saving from a different folder? Check you’re in the right place |
What this lets you read
What you did here has the same shape at any scale.
- Frameworks like React—
npm run buildwrites them out into something the browser can read - Tailwind—collecting only the classes you used and writing out CSS is also a build
- Image compression, TypeScript conversion—all “source file → conversion → the file you ship”
Which means you can look at a project you’ve never seen, read package.json’s scripts, and know roughly what will happen. That’s the main thing to take away.
Summary of this lesson
- A build converts a format the browser can’t read into one it can
- Type
npx sass ...directly, or write it inscriptsand call it asnpm run build --watchmakes the conversion run the instant you save (Ctrl + Cto stop)- Install with
--save-exactto pin the version (or set it once in.npmrc) - Keep
node_modulesout of Git; always commitpackage.jsonandpackage-lock.json
Once you know what npm run build really is, you can run any project you find on GitHub with your own hands.