7

I have a static site that compile Sass using node-sass.

Currently I'm using Grunt to watch the file, but I feel it's overkill because I can use their built-in CLI.

So I add this in my package.json:

// package.json
...
"scripts": {
  "sass": "node-sass -w input/dir -o output-dir/" 
}

The problem is, I need to require a Sass framework module (installed globally) in the --include-path. I can do this in Gruntfile:

// Gruntfile.js
sass: {
  options: {
    includePaths: require("the-framework").includePaths()
  },
  ...
},

So the first thing that come to my mind is to interpolate the string like:

// package.json
...
"scripts": {
  "sass": "node-sass -w input/dir -o output-dir/ --include-path " + require("the-framework").includePaths()
}

And as expected, it doesn't work. Well the script runs, but the interpolated variable is ignored.

Any solution or alternative? If possible, I would prefer not to create additional file just to store the variable.

Thanks

Louis
  • 146,715
  • 28
  • 274
  • 320
hrsetyono
  • 4,474
  • 13
  • 46
  • 80
  • SO editorial practices are such that answers must be posted as *answers*, not as edits to questions. Please post your answer as an actual answer. Thank you. – Louis Jan 22 '16 at 14:03

3 Answers3

7

I dont know is it a right way to do it, but I can explain how I will would solve this task.

You cant interpolate variables in package.json, cause it must be valid json. That you can is to write bash commands here.

1) You can write node command that will needed result. You should take care if includePaths() does not return string.

Node options:
  -e, --eval script     evaluate script
  -p, --print           evaluate script and print result

So it would be something like

node -e "console.log(require('the-framework').includePaths())"

Or shorter version with --print

node -p "require('the-framework').includePaths()"

2) Inline output of previous command into sass script. Take care of right escaping.

{
  "scripts": {
      "sass": "node-sass -w input/dir -o output-dir/ --include-path $(node -p \"require('the-framework').includePaths()\")"
  }
}

More info about executing bash command you can find here.

P.S. Windows version differs

{
  "scripts": {
      "sass": "FOR /f \"delims=\" %v IN ('node -p \"require('edje').includePaths()[0]\"') DO node-sass -w assets/sass -o assets/css --include-path \"%v\""
  }
}

More info you can find here.

Community
  • 1
  • 1
Alexey B.
  • 11,965
  • 2
  • 49
  • 73
  • Thanks for the reply. I think there's a mistake with the `$(...)`. I tried typing `node -p ...` in console and it successfully prints the path. But it doesn't work inside the `$(...)`. – hrsetyono Jan 22 '16 at 10:06
  • I cant check it, cause I havent running example, but i try it with command ``ls -$(node -p "'la'")`` and it work exactly as ``ls -la`` – Alexey B. Jan 22 '16 at 10:20
  • no it doesn't, I get `ls: invalid option -- $`. I'm on Windows 10, maybe that's the reason? – hrsetyono Jan 22 '16 at 10:22
  • Ooops, i think windows version can be different. Im used Cygwin at windows always – Alexey B. Jan 22 '16 at 10:28
  • I tried the `ls -$(...)` in Mac and it works. But I still need to make working code for windows – hrsetyono Jan 22 '16 at 10:36
  • Yes, that works. Here's my final code, you can edit your answer and I will accept it: `FOR /f \"delims=\" %v IN ('node -p \"require('edje').includePaths()[0]\"') DO node-sass -w assets/sass -o assets/css --include-path \"%v\"` – hrsetyono Jan 22 '16 at 14:06
0

You can something like this:

“scripts”: {
  “sass”: “node-sass --include-path scss scss/main.scss   public/css/main.css”
},
Alireza Davoodi
  • 749
  • 7
  • 20
  • The framework is a npm module and resides on the node installation directory, not within the project. I can get the path by using `require` but package.json doesn't allow string interpolation – hrsetyono Jan 18 '16 at 12:33
0

There are many ways you could solve this with npm scripts.

The first one that comes to my mind by looking at your specific need is, npm accepts extra parameters when calling a script. For example:

npm run sass -- path/to/the-framework

This will resolve to:

node-sass -w input/dir -o output-dir/ --include-path path/to/the-framework

Another way would be to move your code in a .js executable file (Node), let's call it watch-sass.js.

So your script will look like:

"sass": "node watch-sass.js"

And you would run:

npm run sass

This way you have much more freedom to do anything you want in your file.


Possibilities are infinite really, you could leverage the power of bash script instead of JS if you want, they can all read/write environment variables. But you don't necessarily need them. For instance you could just have a shell script that writes a package.json for you (or Python, or Ruby...), with all the variables already in place. But in the end I think it's just a matter of taste, use what you find simpler or more comfortable to use.

Simone
  • 20,302
  • 14
  • 79
  • 103
  • Thanks for the reply. I want to avoid hardcoding the path, also I'm trying to do this without creating additional file (if not possible, then I will use the `.js` executable). – hrsetyono Jan 22 '16 at 10:13
  • @DarcCode have you tried the first approach? I think it's possibly what you're looking for? – Simone Jan 22 '16 at 10:36
  • I don't want to type in `C::/ProgramFiles/.../...` everytime I want to run the script. Also the installation dir can be different between computer, so I need to use `require...` – hrsetyono Jan 22 '16 at 10:40
  • How about passing in a relative path? Also it's not hardcoded, so in a different computer one would type a different path – Simone Jan 22 '16 at 10:54