diff --git a/.eslintrc.js b/.eslintrc.js index 29e7717f..197e7300 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,4 +1,7 @@ module.exports = { root: true, extends: ["@webpack-contrib/eslint-config-webpack", "prettier"], + parserOptions: { + ecmaVersion: 2020, + }, }; diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index dd65274c..112a3b9b 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -55,7 +55,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] - node-version: [10.x, 12.x, 14.x] + node-version: [10.x, 12.x, 14.x, 16.x] webpack-version: [latest] runs-on: ${{ matrix.os }} diff --git a/README.md b/README.md index cbd296b2..7e32eb2a 100644 --- a/README.md +++ b/README.md @@ -196,7 +196,9 @@ module.exports = { Note that when using `sass` (`Dart Sass`), **synchronous compilation is twice as fast as asynchronous compilation** by default, due to the overhead of asynchronous callbacks. To avoid this overhead, you can use the [fibers](https://www.npmjs.com/package/fibers) package to call asynchronous importers from the synchronous code path. -We automatically inject the [`fibers`](https://github.com/laverdet/node-fibers) package (setup `sassOptions.fiber`) if is possible (i.e. you need install the [`fibers`](https://github.com/laverdet/node-fibers) package). +We automatically inject the [`fibers`](https://github.com/laverdet/node-fibers) package (setup `sassOptions.fiber`) for `Node.js` less v16.0.0 if is possible (i.e. you need install the [`fibers`](https://github.com/laverdet/node-fibers) package). + +> Fibers is not compatible with `Node.js` v16.0.0 or later ([see introduction to readme](https://github.com/laverdet/node-fibers)). **package.json** diff --git a/package-lock.json b/package-lock.json index c80c1da6..460a9cd2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,7 +5,7 @@ "requires": true, "packages": { "": { - "version": "11.0.1", + "version": "11.1.0", "license": "MIT", "dependencies": { "klona": "^2.0.4", @@ -37,7 +37,7 @@ "lint-staged": "^11.0.0", "material-components-web": "^8.0.0", "memfs": "^3.2.2", - "node-sass": "^5.0.0", + "node-sass": "^6.0.0", "node-sass-glob-importer": "^5.3.2", "npm-run-all": "^4.1.5", "prettier": "^2.3.0", @@ -13385,9 +13385,9 @@ "dev": true }, "node_modules/node-sass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-5.0.0.tgz", - "integrity": "sha512-opNgmlu83ZCF792U281Ry7tak9IbVC+AKnXGovcQ8LG8wFaJv6cLnRlc6DIHlmNxWEexB5bZxi9SZ9JyUuOYjw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-6.0.0.tgz", + "integrity": "sha512-GDzDmNgWNc9GNzTcSLTi6DU6mzSPupVJoStIi7cF3GjwSE9q1cVakbvAAVSt59vzUjV9JJoSZFKoo9krbjKd2g==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -13412,7 +13412,7 @@ "node-sass": "bin/node-sass" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/node-sass-glob-importer": { @@ -28724,9 +28724,9 @@ "dev": true }, "node-sass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-5.0.0.tgz", - "integrity": "sha512-opNgmlu83ZCF792U281Ry7tak9IbVC+AKnXGovcQ8LG8wFaJv6cLnRlc6DIHlmNxWEexB5bZxi9SZ9JyUuOYjw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-6.0.0.tgz", + "integrity": "sha512-GDzDmNgWNc9GNzTcSLTi6DU6mzSPupVJoStIi7cF3GjwSE9q1cVakbvAAVSt59vzUjV9JJoSZFKoo9krbjKd2g==", "dev": true, "requires": { "async-foreach": "^0.1.3", diff --git a/package.json b/package.json index 0eea7458..e2db9898 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "lint-staged": "^11.0.0", "material-components-web": "^8.0.0", "memfs": "^3.2.2", - "node-sass": "^5.0.0", + "node-sass": "^6.0.0", "node-sass-glob-importer": "^5.3.2", "npm-run-all": "^4.1.5", "prettier": "^2.3.0", diff --git a/src/utils.js b/src/utils.js index 55e7c980..bd5c2284 100644 --- a/src/utils.js +++ b/src/utils.js @@ -88,6 +88,12 @@ function proxyCustomImporters(importers, loaderContext) { ); } +function isSupportedFibers() { + const [nodeVersion] = process.versions.node.split("."); + + return Number(nodeVersion) < 16; +} + /** * Derives the sass options from the loader context and normalizes its values with sane defaults. * @@ -115,7 +121,7 @@ async function getSassOptions( const isDartSass = implementation.info.includes("dart-sass"); - if (isDartSass) { + if (isDartSass && isSupportedFibers()) { const shouldTryToResolveFibers = !options.fiber && options.fiber !== false; if (shouldTryToResolveFibers) { @@ -569,4 +575,5 @@ export { getWebpackImporter, getRenderFunctionFromSassImplementation, normalizeSourceMap, + isSupportedFibers, }; diff --git a/test/additionalData-option.test.js b/test/additionalData-option.test.js index 77b1b003..de712322 100644 --- a/test/additionalData-option.test.js +++ b/test/additionalData-option.test.js @@ -1,6 +1,7 @@ import nodeSass from "node-sass"; import dartSass from "sass"; -import Fiber from "fibers"; + +import { isSupportedFibers } from "../src/utils"; import { compile, @@ -13,13 +14,23 @@ import { getWarnings, } from "./helpers"; +let Fiber; const implementations = [nodeSass, dartSass]; const syntaxStyles = ["scss", "sass"]; describe("additionalData option", () => { + beforeAll(async () => { + if (isSupportedFibers()) { + const { default: fibers } = await import("fibers"); + Fiber = fibers; + } + }); + beforeEach(() => { - // The `sass` (`Dart Sass`) package modify the `Function` prototype, but the `jest` lose a prototype - Object.setPrototypeOf(Fiber, Function.prototype); + if (isSupportedFibers()) { + // The `sass` (`Dart Sass`) package modify the `Function` prototype, but the `jest` lose a prototype + Object.setPrototypeOf(Fiber, Function.prototype); + } }); implementations.forEach((implementation) => { diff --git a/test/implementation-option.test.js b/test/implementation-option.test.js index 7ac7712b..4d445616 100644 --- a/test/implementation-option.test.js +++ b/test/implementation-option.test.js @@ -1,6 +1,7 @@ import nodeSass from "node-sass"; import dartSass from "sass"; -import Fiber from "fibers"; + +import { isSupportedFibers } from "../src/utils"; import { compile, @@ -12,15 +13,24 @@ import { getWarnings, } from "./helpers"; -const implementations = [nodeSass, dartSass]; - jest.setTimeout(30000); +let Fiber; +const implementations = [nodeSass, dartSass]; + describe("implementation option", () => { + beforeAll(async () => { + if (isSupportedFibers()) { + const { default: fibers } = await import("fibers"); + Fiber = fibers; + } + }); + beforeEach(() => { - // The `sass` (`Dart Sass`) package modify the `Function` prototype, but the `jest` lose a prototype - Object.setPrototypeOf(Fiber, Function.prototype); - jest.clearAllMocks(); + if (isSupportedFibers()) { + // The `sass` (`Dart Sass`) package modify the `Function` prototype, but the `jest` lose a prototype + Object.setPrototypeOf(Fiber, Function.prototype); + } }); implementations.forEach((implementation) => { @@ -51,6 +61,9 @@ describe("implementation option", () => { expect(nodeSassSpy).toHaveBeenCalledTimes(0); expect(dartSassSpy).toHaveBeenCalledTimes(1); } + + nodeSassSpy.mockRestore(); + dartSassSpy.mockRestore(); }); }); @@ -72,6 +85,9 @@ describe("implementation option", () => { expect(nodeSassSpy).toHaveBeenCalledTimes(0); expect(dartSassSpy).toHaveBeenCalledTimes(1); + + nodeSassSpy.mockRestore(); + dartSassSpy.mockRestore(); }); it("should throw an error on an unknown sass implementation", async () => { diff --git a/test/loader.test.js b/test/loader.test.js index 000115b2..1997eb4e 100644 --- a/test/loader.test.js +++ b/test/loader.test.js @@ -2,9 +2,10 @@ import path from "path"; import nodeSass from "node-sass"; import dartSass from "sass"; -import Fiber from "fibers"; import del from "del"; +import { isSupportedFibers } from "../src/utils"; + import { compile, getCodeFromBundle, @@ -16,15 +17,25 @@ import { getWarnings, } from "./helpers"; +jest.setTimeout(60000); + +let Fiber; const implementations = [nodeSass, dartSass]; const syntaxStyles = ["scss", "sass"]; -jest.setTimeout(60000); - describe("loader", () => { + beforeAll(async () => { + if (isSupportedFibers()) { + const { default: fibers } = await import("fibers"); + Fiber = fibers; + } + }); + beforeEach(() => { - // The `sass` (`Dart Sass`) package modify the `Function` prototype, but the `jest` lose a prototype - Object.setPrototypeOf(Fiber, Function.prototype); + if (isSupportedFibers()) { + // The `sass` (`Dart Sass`) package modify the `Function` prototype, but the `jest` lose a prototype + Object.setPrototypeOf(Fiber, Function.prototype); + } }); implementations.forEach((implementation) => { @@ -420,7 +431,10 @@ describe("loader", () => { implementation: getImplementationByName(implementationName), }; const compiler = getCompiler(testId, { - loader: { options, resolve: { mainFields: ["custom-sass", "..."] } }, + loader: { + options, + resolve: { mainFields: ["custom-sass", "..."] }, + }, }); const stats = await compile(compiler); const codeFromBundle = getCodeFromBundle(stats, compiler); diff --git a/test/sassOptions-option.test.js b/test/sassOptions-option.test.js index 26b655b1..0460c6a9 100644 --- a/test/sassOptions-option.test.js +++ b/test/sassOptions-option.test.js @@ -4,7 +4,8 @@ import globImporter from "node-sass-glob-importer"; import semver from "semver"; import nodeSass from "node-sass"; import dartSass from "sass"; -import Fiber from "fibers"; + +import { isSupportedFibers } from "../src/utils"; import { compile, @@ -19,15 +20,25 @@ import { getCompiler, } from "./helpers"; +jest.setTimeout(30000); + +let Fiber; const implementations = [nodeSass, dartSass]; const syntaxStyles = ["scss", "sass"]; -jest.setTimeout(30000); - describe("sassOptions option", () => { + beforeAll(async () => { + if (isSupportedFibers()) { + const { default: fibers } = await import("fibers"); + Fiber = fibers; + } + }); + beforeEach(() => { - // The `sass` (`Dart Sass`) package modify the `Function` prototype, but the `jest` lose a prototype - Object.setPrototypeOf(Fiber, Function.prototype); + if (isSupportedFibers()) { + // The `sass` (`Dart Sass`) package modify the `Function` prototype, but the `jest` lose a prototype + Object.setPrototypeOf(Fiber, Function.prototype); + } }); implementations.forEach((implementation) => { @@ -371,7 +382,8 @@ describe("sassOptions option", () => { if ( implementationName === "dart-sass" && - semver.satisfies(process.version, ">= 10") + semver.satisfies(process.version, ">= 10") && + isSupportedFibers() ) { expect(dartSassSpy.mock.calls[0][0]).toHaveProperty("fiber"); } @@ -398,7 +410,8 @@ describe("sassOptions option", () => { if ( implementationName === "dart-sass" && - semver.satisfies(process.version, ">= 10") + semver.satisfies(process.version, ">= 10") && + isSupportedFibers() ) { expect(dartSassSpy.mock.calls[0][0]).toHaveProperty("fiber"); } diff --git a/test/sourceMap-options.test.js b/test/sourceMap-options.test.js index 435cf189..e89920fc 100644 --- a/test/sourceMap-options.test.js +++ b/test/sourceMap-options.test.js @@ -3,7 +3,8 @@ import path from "path"; import nodeSass from "node-sass"; import dartSass from "sass"; -import Fiber from "fibers"; + +import { isSupportedFibers } from "../src/utils"; import { compile, @@ -15,13 +16,23 @@ import { getWarnings, } from "./helpers"; +let Fiber; const implementations = [nodeSass, dartSass]; const syntaxStyles = ["scss", "sass"]; describe("sourceMap option", () => { + beforeAll(async () => { + if (isSupportedFibers()) { + const { default: fibers } = await import("fibers"); + Fiber = fibers; + } + }); + beforeEach(() => { - // The `sass` (`Dart Sass`) package modify the `Function` prototype, but the `jest` lose a prototype - Object.setPrototypeOf(Fiber, Function.prototype); + if (isSupportedFibers()) { + // The `sass` (`Dart Sass`) package modify the `Function` prototype, but the `jest` lose a prototype + Object.setPrototypeOf(Fiber, Function.prototype); + } }); implementations.forEach((implementation) => { diff --git a/test/validate-options.test.js b/test/validate-options.test.js index 5a4bba47..5e542d0b 100644 --- a/test/validate-options.test.js +++ b/test/validate-options.test.js @@ -1,4 +1,4 @@ -import Fiber from "fibers"; +import { isSupportedFibers } from "../src/utils"; import { getCompiler, @@ -7,10 +7,21 @@ import { getImplementationByName, } from "./helpers/index"; +let Fiber; + describe("validate options", () => { + beforeAll(async () => { + if (isSupportedFibers()) { + const { default: fibers } = await import("fibers"); + Fiber = fibers; + } + }); + beforeEach(() => { - // The `sass` (`Dart Sass`) package modify the `Function` prototype, but the `jest` lose a prototype - Object.setPrototypeOf(Fiber, Function.prototype); + if (isSupportedFibers()) { + // The `sass` (`Dart Sass`) package modify the `Function` prototype, but the `jest` lose a prototype + Object.setPrototypeOf(Fiber, Function.prototype); + } }); const tests = { diff --git a/test/webpackImporter-options.test.js b/test/webpackImporter-options.test.js index fda65ff1..7d783593 100644 --- a/test/webpackImporter-options.test.js +++ b/test/webpackImporter-options.test.js @@ -1,6 +1,7 @@ import nodeSass from "node-sass"; import dartSass from "sass"; -import Fiber from "fibers"; + +import { isSupportedFibers } from "../src/utils"; import { compile, @@ -13,13 +14,23 @@ import { getWarnings, } from "./helpers"; +let Fiber; const implementations = [nodeSass, dartSass]; const syntaxStyles = ["scss", "sass"]; describe("webpackImporter option", () => { + beforeAll(async () => { + if (isSupportedFibers()) { + const { default: fibers } = await import("fibers"); + Fiber = fibers; + } + }); + beforeEach(() => { - // The `sass` (`Dart Sass`) package modify the `Function` prototype, but the `jest` lose a prototype - Object.setPrototypeOf(Fiber, Function.prototype); + if (isSupportedFibers()) { + // The `sass` (`Dart Sass`) package modify the `Function` prototype, but the `jest` lose a prototype + Object.setPrototypeOf(Fiber, Function.prototype); + } }); implementations.forEach((implementation) => {