diff --git a/.github/workflows/alpine.yml b/.github/workflows/alpine.yml index f46d8772e..c918e3e69 100644 --- a/.github/workflows/alpine.yml +++ b/.github/workflows/alpine.yml @@ -15,26 +15,17 @@ jobs: fail-fast: false matrix: node: - - 12 - 14 - - 15 - - 16 - - include: - - node: 12 - python: python2 - - node: 14 - python: python3 - - node: 15 - python: python3 - - node: 16 - python: python3 + # Node 16+ are perma-red for the tests right now + # - 16 + # - 18 + # - 19 steps: - name: Install Alpine build tools - run: apk add --no-cache ${{ matrix.python }} make git gcc g++ + run: apk add --no-cache python3 make git gcc g++ - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: npm install --unsafe-perm @@ -44,7 +35,7 @@ jobs: - name: Run tests run: npm test - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 if: github.repository_owner == 'sass' && github.event_name != 'pull_request' with: name: ${{ matrix.node }} diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index ccd70311a..c66735b2b 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -26,7 +26,7 @@ jobs: if: github.repository_owner == 'sass' steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages run: npm install --unsafe-perm @@ -35,6 +35,6 @@ jobs: run: npm run coverage - name: Coveralls GitHub Action - uses: coverallsapp/github-action@v1.1.2 + uses: coverallsapp/github-action@1.1.3 with: github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/lint-js.yml b/.github/workflows/lint-js.yml index 21b60786b..2c6ba3b0a 100644 --- a/.github/workflows/lint-js.yml +++ b/.github/workflows/lint-js.yml @@ -25,9 +25,9 @@ jobs: SKIP_SASS_BINARY_DOWNLOAD_FOR_CI: true steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: actions/setup-node@v2.1.5 + - uses: actions/setup-node@v3 - name: Install packages run: npm install --unsafe-perm diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index f82ae516f..4d41f6567 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -14,35 +14,34 @@ jobs: fail-fast: false matrix: node: - - 12 - 14 - - 15 - 16 + - 18 include: - - node: 12 - gcc: "gcc-6" - gpp: "g++-6" - os: ubuntu-18.04 - node: 14 gcc: "gcc-6" gpp: "g++-6" os: ubuntu-18.04 - - node: 15 - gcc: "gcc-6" - gpp: "g++-6" - os: ubuntu-18.04 - node: 16 gcc: "gcc-8" gpp: "g++-8" os: ubuntu-18.04 + - node: 18 + gcc: "gcc-8" + gpp: "g++-8" + os: ubuntu-20.04 + - node: 19 + gcc: "gcc-8" + gpp: "g++-8" + os: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup Node.js environment - uses: actions/setup-node@v2.1.5 + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} @@ -61,7 +60,7 @@ jobs: - name: Run tests run: npm test - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 if: github.repository_owner == 'sass' && github.event_name != 'pull_request' with: name: ${{ matrix.node }} diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index cadeff24a..e03df1faa 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -14,16 +14,16 @@ jobs: fail-fast: false matrix: node: - - 12 - 14 - - 15 - 16 + - 18 + - 19 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup Node.js environment - uses: actions/setup-node@v2.1.5 + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} @@ -35,7 +35,7 @@ jobs: - name: Run tests run: npm test - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 if: github.repository_owner == 'sass' && github.event_name != 'pull_request' with: name: ${{ matrix.node }} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 2d4a8db89..0ee040ef0 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -8,47 +8,42 @@ on: jobs: build: - runs-on: ${{ matrix.os }} + runs-on: windows-2019 strategy: fail-fast: false matrix: node: - - 12 - 14 - - 15 - 16 + - 18 + - 19 - include: - - node: 12 - os: windows-2016 - - node: 14 - os: windows-2016 - - node: 15 - os: windows-2019 - - node: 16 - os: windows-2019 + architecture: + - x64 + - x86 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup Node.js environment - uses: actions/setup-node@v2.1.5 + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} + architecture: ${{ matrix.architecture }} - name: Install packages - run: npm install --unsafe-perm + run: npm install env: SKIP_SASS_BINARY_DOWNLOAD_FOR_CI: true - name: Run tests run: npm test - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 if: github.repository_owner == 'sass' && github.event_name != 'pull_request' with: - name: ${{ matrix.node }} + name: ${{ matrix.node }}-${{ matrix.architecture }} path: | vendor/**/binding.node build/Release/binding.pdb diff --git a/README.md b/README.md index f19667a70..f08caf777 100644 --- a/README.md +++ b/README.md @@ -13,15 +13,18 @@ Projects that still use it should move onto 1. We will stop building binaries for unsupported releases, testing for breakages in dependency compatibility, but we will not block installations for those that want to support themselves. 1. New node release require minor internal changes along with support from CI providers (AppVeyor, GitHub Actions). We will open a single issue for interested parties to subscribe to, and close additional issues. -Below is a quick guide for minimum and maximum support supported version of node-sass: +Below is a quick guide for minimum and maximum supported versions of node-sass: NodeJS | Supported node-sass version | Node Module --------|-----------------------------|------------ +Node 19 | 8.0+ | 111 +Node 18 | 8.0+ | 108 +Node 17 | 7.0+, <8.0 | 102 Node 16 | 6.0+ | 93 -Node 15 | 5.0+ | 88 +Node 15 | 5.0+, <7.0 | 88 Node 14 | 4.14+ | 83 Node 13 | 4.13+, <5.0 | 79 -Node 12 | 4.12+ | 72 +Node 12 | 4.12+, <8.0 | 72 Node 11 | 4.10+, <5.0 | 67 Node 10 | 4.9+, <6.0 | 64 Node 8 | 4.5.3+, <5.0 | 57 @@ -77,7 +80,7 @@ SyntaxError: Use of const in strict mode. ### Install from mirror in China ```shell -npm install -g mirror-config-china --registry=http://registry.npm.taobao.org +npm install -g mirror-config-china --registry=https://registry.npmmirror.com npm install node-sass ``` @@ -490,7 +493,7 @@ This functionality has been moved to [`node-sass-middleware`](https://github.com ### DocPad Plugin -[@10xLaCroixDrinker](https://github.com/10xLaCroixDrinker) wrote a [DocPad](http://docpad.org/) plugin that compiles `.scss` files using node-sass: +[@10xLaCroixDrinker](https://github.com/10xLaCroixDrinker) wrote a [DocPad](http://docpad.org/) plugin that compiles `.scss` files using node-sass: ### Duo.js extension @@ -595,12 +598,13 @@ When compiling a directory `--source-map` can either be a boolean value or a dir node-sass supports different configuration parameters to change settings related to the sass binary such as binary name, binary path or alternative download path. Following parameters are supported by node-sass: -Variable name | .npmrc parameter | Process argument | Value ------------------|------------------|--------------------|------ -SASS_BINARY_NAME | sass_binary_name | --sass-binary-name | path -SASS_BINARY_SITE | sass_binary_site | --sass-binary-site | URL -SASS_BINARY_PATH | sass_binary_path | --sass-binary-path | path -SASS_BINARY_DIR | sass_binary_dir | --sass-binary-dir | path +Variable name | .npmrc parameter | Process argument | Value +-------------------------|--------------------------|----------------------------|------ +SASS_BINARY_NAME | sass_binary_name | --sass-binary-name | path +SASS_BINARY_SITE | sass_binary_site | --sass-binary-site | URL +SASS_BINARY_PATH | sass_binary_path | --sass-binary-path | path +SASS_BINARY_DIR | sass_binary_dir | --sass-binary-dir | path +SASS_REJECT_UNAUTHORIZED | sass_reject_unauthorized | --sass-reject-unauthorized | value These parameters can be used as environment variable: @@ -614,6 +618,8 @@ As a process argument: * E.g. `npm install node-sass --sass-binary-site=http://example.com/` +If you are using self-signed certificates for your binary then `SASS_REJECT_UNAUTHORIZED` will override (rejectUnauthorized)[https://nodejs.org/docs/latest/api/tls.html#tls_tls_createserver_options_secureconnectionlistener]. + ## Post-install Build Install runs only two Mocha tests to see if your machine can use the pre-built [LibSass] which will save some time during install. If any tests fail it will build from source. diff --git a/appveyor.yml b/appveyor.yml index 540a5f61e..4a6837ddd 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -33,19 +33,20 @@ environment: SKIP_SASS_BINARY_DOWNLOAD_FOR_CI: true matrix: - - nodejs_version: 12 - GYP_MSVS_VERSION: 2017 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - nodejs_version: 14 GYP_MSVS_VERSION: 2017 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - - nodejs_version: 15 + - nodejs_version: 16 GYP_MSVS_VERSION: 2019 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - - nodejs_version: 16 + - nodejs_version: 18 + GYP_MSVS_VERSION: 2019 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + - nodejs_version: 19 GYP_MSVS_VERSION: 2019 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + install: # https://www.appveyor.com/docs/lang/nodejs-iojs/#installing-any-version-of-nodejs-or-iojs - ps: Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) $env:platform @@ -77,61 +78,3 @@ secure: IZIifH990iABY3PQUtkRscTU/NOyYYwptGB6B1y2b618vpphV/2KD/4IWJzSAYAi on: appveyor_repo_tag: true # deploy on tag push only - -- - branches: - except: - - release - - /v\d\.\d\.\d/ - - skip_branch_with_pr: true - skip_tags: true - - os: Visual Studio 2017 - - configuration: testing - - platform: - - x86 - - version: "{build}" - - build: off - - clone_folder: c:\projects\node_modules\node-sass - - init: - - cmd: >- - subst s: c:\projects - - ps: set-location -path s:\node_modules\node-sass - - cache: - - '%userprofile%\.node-gyp' - - '%AppData%\npm-cache' - - environment: - SKIP_SASS_BINARY_DOWNLOAD_FOR_CI: true - matrix: - - nodejs_version: 12 - GYP_MSVS_VERSION: 2017 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - - nodejs_version: 14 - GYP_MSVS_VERSION: 2017 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - - nodejs_version: 15 - GYP_MSVS_VERSION: 2019 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - - nodejs_version: 16 - GYP_MSVS_VERSION: 2019 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - - install: - # https://www.appveyor.com/docs/lang/nodejs-iojs/#installing-any-version-of-nodejs-or-iojs - - ps: Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) $env:platform - - node --version - - npm --version - - npm install - - test_script: - - ps: set-location -path c:\projects\node_modules\node-sass - - npm test diff --git a/lib/extensions.js b/lib/extensions.js index ce4b17a56..4622f5dc5 100644 --- a/lib/extensions.js +++ b/lib/extensions.js @@ -5,7 +5,7 @@ var eol = require('os').EOL, fs = require('fs'), path = require('path'), - trueCasePathSync = require('true-case-path'), + trueCasePathSync = require('true-case-path').trueCasePathSync, pkg = require('../package.json'), defaultBinaryDir = path.join(__dirname, '..', 'vendor'); @@ -81,6 +81,9 @@ function getHumanNodeVersion(abi) { case 83: return 'Node.js 14.x'; case 88: return 'Node.js 15.x'; case 93: return 'Node.js 16.x'; + case 102: return 'Node.js 17.x'; + case 108: return 'Node.js 18.x'; + case 111: return 'Node.js 19.x'; default: return false; } } diff --git a/package.json b/package.json index fa3e86528..7139aa80e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-sass", - "version": "6.0.1", + "version": "8.0.0", "libsass": "3.5.5", "description": "Wrapper around libsass", "license": "MIT", @@ -16,7 +16,7 @@ "url": "http://andrew.github.com" }, "engines": { - "node": ">=12" + "node": ">=14" }, "main": "lib/index.js", "nodeSassConfig": { @@ -54,24 +54,23 @@ ], "dependencies": { "async-foreach": "^0.1.3", - "chalk": "^1.1.1", + "chalk": "^4.1.2", "cross-spawn": "^7.0.3", "gaze": "^1.0.0", "get-stdin": "^4.0.1", "glob": "^7.0.3", "lodash": "^4.17.15", + "make-fetch-happen": "^10.0.4", "meow": "^9.0.0", - "nan": "^2.13.2", - "node-gyp": "^7.1.0", - "npmlog": "^4.0.0", - "request": "^2.88.0", - "sass-graph": "2.2.5", + "nan": "^2.17.0", + "node-gyp": "^8.4.1", + "sass-graph": "^4.0.1", "stdout-stream": "^1.4.0", - "true-case-path": "^1.0.2" + "true-case-path": "^2.2.1" }, "devDependencies": { - "eslint": "^7.10.0", - "fs-extra": "^0.30.0", + "eslint": "^8.0.0", + "fs-extra": "^10.0.0", "mocha": "^9.0.1", "nyc": "^15.1.0", "rimraf": "^3.0.2", diff --git a/scripts/install.js b/scripts/install.js index 2cef34f7d..42511b393 100644 --- a/scripts/install.js +++ b/scripts/install.js @@ -5,8 +5,7 @@ var fs = require('fs'), eol = require('os').EOL, path = require('path'), - request = require('request'), - log = require('npmlog'), + fetch = require('make-fetch-happen'), sass = require('../lib/extensions'), downloadOptions = require('./util/downloadoptions'); @@ -21,21 +20,8 @@ var fs = require('fs'), function download(url, dest, cb) { var reportError = function(err) { - var timeoutMessge; - - if (err.code === 'ETIMEDOUT') { - if (err.connect === true) { - // timeout is hit while your client is attempting to establish a connection to a remote machine - timeoutMessge = 'Timed out attemping to establish a remote connection'; - } else { - timeoutMessge = 'Timed out whilst downloading the prebuilt binary'; - // occurs any time the server is too slow to send back a part of the response - } - - } cb(['Cannot download "', url, '": ', eol, eol, typeof err.message === 'string' ? err.message : err, eol, eol, - timeoutMessge ? timeoutMessge + eol + eol : timeoutMessge, 'Hint: If github.com is not accessible in your location', eol, ' try setting a proxy via HTTP_PROXY, e.g. ', eol, eol, ' export HTTP_PROXY=http://example.com:1234',eol, eol, @@ -44,45 +30,24 @@ function download(url, dest, cb) { }; var successful = function(response) { - return response.statusCode >= 200 && response.statusCode < 300; + return response.status >= 200 && response.status < 300; }; console.log('Downloading binary from', url); try { - request(url, downloadOptions(), function(err, response, buffer) { - if (err) { - reportError(err); - } else if (!successful(response)) { - reportError(['HTTP error', response.statusCode, response.statusMessage].join(' ')); + fetch(url, downloadOptions()).then(function (response) { + return response.buffer(); + }).then(function (buffer) { + fs.createWriteStream(dest).on('error', cb).end(buffer, cb); + console.log('Download complete'); + }).catch(function(err) { + if(!successful(err)) { + reportError(['HTTP error', err.code, err.message].join(' ')); } else { - console.log('Download complete'); - - if (successful(response)) { - fs.createWriteStream(dest) - .on('error', cb) - .end(buffer, cb); - } else { - cb(); - } + reportError(err); } - }) - .on('response', function(response) { - var length = parseInt(response.headers['content-length'], 10); - var progress = log.newItem('', length); - - // The `progress` is true by default. However if it has not - // been explicitly set it's `undefined` which is considered - // as far as npm is concerned. - if (process.env.npm_config_progress === 'true') { - log.enableProgress(); - - response.on('data', function(chunk) { - progress.completeWork(chunk.length); - }) - .on('end', progress.finish); - } - }); + }); } catch (err) { cb(err); } diff --git a/scripts/util/downloadoptions.js b/scripts/util/downloadoptions.js index 23529716f..6add52a10 100644 --- a/scripts/util/downloadoptions.js +++ b/scripts/util/downloadoptions.js @@ -1,25 +1,20 @@ var proxy = require('./proxy'), - userAgent = require('./useragent'); + userAgent = require('./useragent'), + rejectUnauthorized = require('./rejectUnauthorized'); /** - * The options passed to request when downloading the bibary + * The options passed to make-fetch-happen when downloading the binary * - * There some nuance to how request handles options. Specifically - * we've been caught by their usage of `hasOwnProperty` rather than - * falsey checks. By moving the options generation into a util helper - * we can test for regressions. - * - * @return {Object} an options object for request + * @return {Object} an options object for make-fetch-happen * @api private */ module.exports = function() { var options = { - rejectUnauthorized: false, + strictSSL: rejectUnauthorized(), timeout: 60000, headers: { 'User-Agent': userAgent(), }, - encoding: null, }; var proxyConfig = proxy(); diff --git a/scripts/util/rejectUnauthorized.js b/scripts/util/rejectUnauthorized.js new file mode 100644 index 000000000..43d8373a6 --- /dev/null +++ b/scripts/util/rejectUnauthorized.js @@ -0,0 +1,46 @@ +var pkg = require('../../package.json'); + +/** + * Get the value of a CLI argument + * + * @param {String} name + * @param {Array} args + * @api private + */ +function getArgument(name, args) { + var flags = args || process.argv.slice(2), + index = flags.lastIndexOf(name); + + if (index === -1 || index + 1 >= flags.length) { + return null; + } + + return flags[index + 1]; +} + +/** + * Get the value of reject-unauthorized + * If environment variable SASS_REJECT_UNAUTHORIZED is non-zero, + * .npmrc variable sass_reject_unauthorized or + * process argument --sass-reject_unauthorized is provided, + * set rejectUnauthorized to true + * Else set to false by default + * + * @return {Boolean} The value of rejectUnauthorized + * @api private + */ +module.exports = function() { + var rejectUnauthorized = false; + + if (getArgument('--sass-reject-unauthorized')) { + rejectUnauthorized = getArgument('--sass-reject-unauthorized'); + } else if (process.env.SASS_REJECT_UNAUTHORIZED !== '0') { + rejectUnauthorized = true; + } else if (process.env.npm_config_sass_reject_unauthorized) { + rejectUnauthorized = process.env.npm_config_sass_reject_unauthorized; + } else if (pkg.nodeSassConfig && pkg.nodeSassConfig.rejectUnauthorized) { + rejectUnauthorized = pkg.nodeSassConfig.rejectUnauthorized; + } + + return rejectUnauthorized; +}; diff --git a/test/downloadoptions.js b/test/downloadoptions.js index de8963842..968213e3c 100644 --- a/test/downloadoptions.js +++ b/test/downloadoptions.js @@ -8,12 +8,11 @@ describe('util', function() { describe('without a proxy', function() { it('should look as we expect', function() { var expected = { - rejectUnauthorized: false, + strictSSL: true, timeout: 60000, headers: { 'User-Agent': ua(), }, - encoding: null, }; assert.deepStrictEqual(opts(), expected); @@ -33,13 +32,12 @@ describe('util', function() { it('should look as we expect', function() { var expected = { - rejectUnauthorized: false, + strictSSL: true, proxy: proxy, timeout: 60000, headers: { 'User-Agent': ua(), }, - encoding: null, }; assert.deepStrictEqual(opts(), expected); @@ -59,16 +57,73 @@ describe('util', function() { it('should look as we expect', function() { var expected = { - rejectUnauthorized: false, + strictSSL: true, timeout: 60000, headers: { 'User-Agent': ua(), }, - encoding: null, }; assert.deepStrictEqual(opts(), expected); }); }); + + describe('with SASS_REJECT_UNAUTHORIZED set to false', function() { + beforeEach(function() { + process.env.SASS_REJECT_UNAUTHORIZED = '0'; + }); + + it('should look as we expect', function() { + var expected = { + strictSSL: false, + timeout: 60000, + headers: { + 'User-Agent': ua(), + }, + }; + + assert.deepStrictEqual(opts(), expected); + }); + }); + + describe('with SASS_REJECT_UNAUTHORIZED set to true', function() { + beforeEach(function() { + process.env.SASS_REJECT_UNAUTHORIZED = '1'; + }); + + it('should look as we expect', function() { + var expected = { + strictSSL: true, + timeout: 60000, + headers: { + 'User-Agent': ua(), + }, + }; + + assert.deepStrictEqual(opts(), expected); + }); + }); + + describe('with npm_config_sass_reject_unauthorized set to true', function() { + beforeEach(function() { + process.env.npm_config_sass_reject_unauthorized = true; + }); + + it('should look as we expect', function() { + var expected = { + strictSSL: true, + timeout: 60000, + headers: { + 'User-Agent': ua(), + }, + }; + + assert.deepStrictEqual(opts(), expected); + }); + + afterEach(function() { + process.env.npm_config_sass_reject_unauthorized = undefined; + }); + }); }); });