Installing node-sass over a firewall
Tags: npm, node
Published: 2020-05-30 08:54:58

If you want to integrate node-sass to your project, the typical npm package script would do:

```
npm install node-sass
```

But since my network is protected by a firewall, I encountered an error:

```
Downloading binary from https://github.com/sass/node-sass/releases/download/v4.7
.2/win32-x64-48_binding.node
Cannot download "https://github.com/sass/node-sass/releases/download/v4.7.2/win3
2-x64-48_binding.node":
HTTP error 401 Unauthorized
```

There were several fixes over the net, but I ultimately chose one: using the npm-cache folder. Here are the steps:

Step 1: Download the binary file here.

Step 2: Save it to a directory on the project’s root folder.

Step 3: Make a powershell script to copy it over to the npm-cache folder used by `npm install` to reference already existing data when trying to download packages.
 
**npm-cache is located on the AppData folder. You can access it by running `cd %appdata%` on cmd.

**Take note that node-sass will always look for the path with this format:

```
npm-cache/node-sass/<version>/binary.node
```

Here is the powershell script I made for this task:

```
Write-Host "BEGIN..."

Write-Host "AppData directory is: " $env:APPDATA

$cacheSassPath = $env:APPDATA + '\npm-cache\node-sass\4.7.2\win32-x64-48_binding.node'

if( -Not (Test-Path -Path $cacheSassPath ) )
{
    Write-Host "Binary file not exists. Something to do here."

    $cacheSassPath = $env:APPDATA + '\npm-cache\node-sass'

	if( (Test-Path -Path $cacheSassPath ) )
	{
		<# Ensure target path has no content #>
		Remove-Item $cacheSassPath -Force -Recurse
	}

	<# Create cache node-sass folder #>
    New-Item -ItemType directory -Path $cacheSassPath
    Write-Host "cacheSassPath CREATED"
    
    <# Copy local sass binary (~Srt.Web\sass-binary\4.7.2) file to cache folder #>
    $sassBinaryPath = split-path -parent $MyInvocation.MyCommand.Definition
    $sassBinaryPath = $sassBinaryPath + "\sass-binary\4.7.2"

    Copy-Item -Path $sassBinaryPath -Recurse -Destination $cacheSassPath -Container

    Write-Host "node-sass binary file successfully copied!"
}
else
{
    Write-Host "Binary file already exists. Nothing to do here."
}

Write-Host "END..."
```

Step 4: Update the scripts section of package.json to execute the powershell script before the packages are installed. Note that we are using `preinstall` to accomplish this.

```
{
  "name": "my_app",
  "private": true,
  "version": "0.0.0",
  "scripts": {
    "preinstall": "@powershell -NoProfile -ExecutionPolicy Unrestricted -Command ./set-sass-binary.ps1"
  },
  "dependencies": {
    "@angular/animations": "^4.4.6",
    "@angular/cdk": "^2.0.0-beta.12",
    "@angular/common": "^4.4.6",
    "@angular/compiler": "^4.4.6",
    "@angular/compiler-cli": "^4.4.6",
    "@angular/core": "^4.4.6",
    "@angular/forms": "^4.4.6",
    "@angular/http": "^4.4.6"
  },
  "devDependencies": {
    "@types/bootstrap": "^3.3.36",
    "@types/jquery": "^3.2.15",
    "node-sass": "^4.7.2",
    "sass-loader": "^6.0.6"
  }
}
```

Step 5: Run `npm install`.

Since we used a `preinstall` script, every time `npm install` is triggered, it will first execute the powershell script to copy the local binary file to npm-cache. As it proceeds to node-sass installation, npm will now reference to the cached binary file rather than downloading it from the github site.

A big shout out to @dwij for helping me figure this out on [stackoverflow](https://stackoverflow.com/questions/47495527/powershell-setting-sass-binary-path/47495931#47495931).