npm・Running a build

Run a build once (Sass → CSS)

npm isn't only a tool for fetching parts. Here we try its other face—running work—by converting Sass to CSS once, end to end. Covers npm scripts and --watch, with steps you can copy and run.

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.

npmHow to read package.jsonGlancing at package.json’s scripts field first makes this lesson go down easily

What 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 buildWith a build
The file you writestyle.cssstyle.scss
The file the browser readsstyle.css (the same one)style.css (produced by the conversion)
After you saveJust reloadConvert → 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.

TipsIs Sass still necessary?Is Sass still necessary?—what plain CSS gained

What you need

If Node.js is installed, nothing else. Check in the terminal.

node -v
npm -v

Version 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 them

1. 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-practice

2. Create package.json

npm init makes one. Adding -y answers yes to every question and creates it immediately.

npm init -y

There’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").

npmnpm's scary story—protecting yourself, learned from the Shai-Hulud incidentThe risk behind the convenience of ^, and why pinning matters

If 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=true

4. Prepare two files

Create the source .scss and the destination folder.

mkdir src css

Create 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.css

npx 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 build

Typing 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 watch

The 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

SymptomCause and fix
sass: command not foundAdd npx, or put it in scripts and use npm run
npm run build says Missing scriptNo such name in scripts. Check the spelling
No CSS file appearsThe output folder (css) doesn’t exist. mkdir css first
The conversion succeeds but the page doesn’t changeCheck your HTML’s link isn’t pointing at the .scss. The browser reads the .css
watch does nothingAre you saving from a different folder? Check you’re in the right place
TipsHow to work out why your CSS isn't applyingHow to narrow down “my CSS isn’t applying”

What this lets you read

What you did here has the same shape at any scale.

  • Frameworks like Reactnpm run build writes 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

  1. A build converts a format the browser can’t read into one it can
  2. Type npx sass ... directly, or write it in scripts and call it as npm run build
  3. --watch makes the conversion run the instant you save (Ctrl + C to stop)
  4. Install with --save-exact to pin the version (or set it once in .npmrc)
  5. Keep node_modules out of Git; always commit package.json and package-lock.json

Once you know what npm run build really is, you can run any project you find on GitHub with your own hands.

FAQ

What does building actually do?
It converts files written in a format the browser can't read into a format it can. In this article's Sass example, writing a .scss file out as a .css file is the build. "Save, convert, then the browser reads it"—that three-step shape is what characterises a project with a build.
What's the difference between npm run build and npx sass?
They do the same thing. npm run build simply calls the long command you wrote in package.json's scripts under a short name; what actually runs is the same npx sass .... The benefit of scripts is not retyping a long command, and everyone on the team running it the same way.
I get sass: command not found
A package you didn't install globally can't be called by name alone. Either call it as npx sass ..., or write it in package.json's scripts and run it with npm run. Inside scripts it works without npx.
What does --watch change?
The command doesn't exit; it keeps watching for saves. The conversion runs the instant you save a .scss file, so you never retype the command. Press Ctrl + C in the terminal to stop it.