So, to outline what I want, in my script i want to have only one command. So, I want to be able to pass an argument into the code I am running like so :
"scripts": {
"compile:'variable'": "node-sass sass/variable.scss css/variable.css -w" }
Is there a way to do something like this in npm so that I can pass an argument into my command that I would run? In the command line I would like to compile in a simple way. I would, say if I wanted to compile a file called "home". So, I want to be able to type into the command line :
npm run compile:home
Then, this, I would want to get the following command taken through the package.json and the running the node-sass to compile it:
"node-sass scss/home.scss css/home.css -w"
If you have any questions feel free to comment.
Unfortunately, npm-scripts
has no built-in way to achieve your requirement in a way that runs successfully cross-platform.
However, a couple of ways to meet your requirement are as follows (...you probably want Solution B):
If you only have a few .scss
file to compile to .css
then the simplest solution would be to create a npm-script
for each file. For example:
"scripts": {
"compile:home": "node-sass sass/home.scss css/home.css -w",
"compile:quxx": "node-sass sass/quux.scss css/quxx.css -w"
}
This will allow you to run each script using the command syntax that you require, i.e.
$ npm run compile:home
$ npm run compile:quxx
However, this is probably not ideal, as I guess you have lots of .scss
files - hence your question about utilizing a variable in the script.
A solution that works cross-platform, (and enables you to define the filename as an argument via the CLI), is to write a nodejs utility script. The nodejs script can then be invoked via the scripts
section of your package.json
.
The following provides the necessary steps to achieve this:
Create a nodejs script as follows: Let's name the file sass-to-css.js
.
sass-to-css.js
const fs = require('fs');
const path = require('path');
const execSync = require('child_process').execSync;
// Error when no filename argument provided.
if (!process.argv[2]) {
console.log('\x1b[31mERR!\x1b[0m Trailing filename arg must be provided.');
process.exit(1);
}
const fileName = process.argv[2];
const srcPath = `${path.join('sass', fileName)}.scss`;
// Check source .scss file exists.
if (!fs.existsSync(srcPath)) {
console.log('\x1b[31mERR!\x1b[0m Path cannot be found: %s', srcPath);
process.exit(1);
}
// Path to node-sass executable in node_modules directory.
const executablePath = path.join('node_modules', '.bin', 'node-sass');
// Destimation path for resultant .css file.
const destPath = `${path.join('css', fileName)}.css`;
// The command to be invoked.
const cmd = `${executablePath} ${srcPath} ${destPath} -w`;
// Execute the command.
execSync(cmd, {
cwd: process.cwd()
});
Save sass-to-css.js
in the root of your projects directory, in the same folder where package.json
is stored. For example:
.
├── ...
├── node_modules
│ └── ...
├── package.json
├── sass
│ ├── home.scss
│ └── ...
└── sass-to-css.js <--
Then in the scripts
section of your package.json
add the following script:
"scripts": {
"compile": "node sass-to-css"
}
To invoke the script via your CLI you enter something like the following command(s):
$ npm run compile home
$ npm run compile foo
$ npm run compile bar
Note: the last argument provided is the filename, (without the file extension), of the .scss
file that you want to compile. Namely home
, foo
, bar
in the above example. A space must exist between the compile
part and the filename/argument.
The syntax to run the command is not exactly as you requested, but it's close !
Additional notes:
The pertinent parts of sass-to-css.js
are:
process.argv
to obtain the filename/argument entered via CLI..scss
) and destination (.css
) files are contructed using nodes path.join()
.child_process.execSync()
is utilized to execute the appropriate node-sass
command..scss
file exists using fs.existsSync(path)
. sass-to-css.js
currently utilizes Template literals (a feature of ES6). If your running an older version of nodejs that doesn't support this sytax then use the ES5 version of the script below instead:
ES5 version of sass-to-css.js
var fs = require('fs');
var path = require('path');
var execSync = require('child_process').execSync;
// Error when no filename argument provided.
if (!process.argv[2]) {
console.log('\x1b[31mERR!\x1b[0m Trailing filename arg must be provided.');
process.exit(1);
}
var fileName = process.argv[2];
var srcPath = path.join('sass', fileName) + '.scss';
// Check source .scss file exists.
if (!fs.existsSync(srcPath)) {
console.log('\x1b[31mERR!\x1b[0m Path cannot be found: %s', srcPath);
process.exit(1);
}
// Path to node-sass executable in node_modules directory.
var executablePath = path.join('node_modules', '.bin', 'node-sass');
// Destimation path for resultant .css file.
var destPath = path.join('css', fileName) + '.css';
// The command to be invoked.
var cmd = executablePath + ' ' + srcPath + ' ' + destPath + ' -w';
// Execute the command.
execSync(cmd, {
cwd: process.cwd()
});