diff --git a/lib/normalizeOptions.js b/lib/normalizeOptions.js index 1e59a6d2..7d030fe0 100644 --- a/lib/normalizeOptions.js +++ b/lib/normalizeOptions.js @@ -85,7 +85,16 @@ function normalizeOptions(loaderContext, content, webpackImporter) { options.importer = options.importer ? proxyCustomImporters(options.importer, resourcePath) : []; - options.importer.push(webpackImporter); + + if (options.resolver === false) { + // disable webpack resolved in favor built-in node-sass/sass resolver + } else if (typeof options.resolver === 'function') { + options.importer = options.importer.concat( + proxyCustomImporters(options.resolver, resourcePath) + ); + } else { + options.importer.push(webpackImporter); + } // `node-sass` uses `includePaths` to resolve `@import` paths. Append the currently processed file. options.includePaths = options.includePaths || []; diff --git a/package-lock.json b/package-lock.json index 143db1f1..8a8fa7c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3680,8 +3680,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -3702,14 +3701,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3724,20 +3721,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -3854,8 +3848,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -3867,7 +3860,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3882,7 +3874,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -3890,14 +3881,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -3916,7 +3905,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -3997,8 +3985,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -4010,7 +3997,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -4096,8 +4082,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -4133,7 +4118,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4153,7 +4137,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -4197,14 +4180,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, diff --git a/test/index.test.js b/test/index.test.js index 2d3ea956..75ef81d3 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -13,6 +13,7 @@ const dartSass = require('sass'); const mockRequire = require('mock-require'); const customImporter = require('./tools/customImporter.js'); +const customResolver = require('./tools/customResolver.js'); const customFunctions = require('./tools/customFunctions.js'); const pathToSassLoader = require.resolve('../lib/loader.js'); @@ -185,6 +186,19 @@ implementations.forEach((implementation) => { importer: customImporter, })); }); + describe('custom resolver', () => { + it('should use custom resolver', () => + execTest('custom-resolver', { + resolver: customResolver, + })); + }); + describe('no resolver', () => { + it('should use custom resolver', () => + execTest('no-resolver', { + resolver: false, + includePaths: [path.join(__dirname, 'node_modules', 'scss')], + })); + }); describe('custom functions', () => { it('should expose custom functions', () => execTest('custom-functions', { diff --git a/test/node_modules/scss/unresolvable.scss b/test/node_modules/scss/unresolvable.scss new file mode 100644 index 00000000..860e9506 --- /dev/null +++ b/test/node_modules/scss/unresolvable.scss @@ -0,0 +1,3 @@ +.unresolvable { + background-color: blue; +} diff --git a/test/sass/custom-resolver.sass b/test/sass/custom-resolver.sass new file mode 100644 index 00000000..843c5506 --- /dev/null +++ b/test/sass/custom-resolver.sass @@ -0,0 +1 @@ +@import import-with-custom-resolver diff --git a/test/sass/no-resolver.sass b/test/sass/no-resolver.sass new file mode 100644 index 00000000..6fbd9109 --- /dev/null +++ b/test/sass/no-resolver.sass @@ -0,0 +1 @@ +@import unresolvable diff --git a/test/scss/custom-resolver.scss b/test/scss/custom-resolver.scss new file mode 100644 index 00000000..29cb2ab0 --- /dev/null +++ b/test/scss/custom-resolver.scss @@ -0,0 +1 @@ +@import 'import-with-custom-resolver'; diff --git a/test/scss/no-resolver.scss b/test/scss/no-resolver.scss new file mode 100644 index 00000000..8925983f --- /dev/null +++ b/test/scss/no-resolver.scss @@ -0,0 +1 @@ +@import 'unresolvable'; diff --git a/test/tools/createSpec.js b/test/tools/createSpec.js index b23fd8ef..461b4f04 100644 --- a/test/tools/createSpec.js +++ b/test/tools/createSpec.js @@ -8,6 +8,7 @@ const dartSass = require('sass'); const nodeSass = require('node-sass'); const customImporter = require('./customImporter.js'); +const customResolver = require('./customResolver.js'); const customFunctions = require('./customFunctions.js'); const implementations = [nodeSass, dartSass]; @@ -22,6 +23,10 @@ function createSpec(ext) { basePath, path.resolve(testFolder, '..', 'node_modules', 'bootstrap-sass') ); + const pathToUnresolvable = path.relative( + basePath, + path.resolve(testFolder, 'node_modules', 'scss', 'unresolvable.scss') + ); const pathToScopedNpmPkg = path.relative( basePath, path.resolve(testFolder, 'node_modules', '@org', 'pkg', './index.scss') @@ -73,6 +78,9 @@ function createSpec(ext) { if (url === 'import-with-custom-logic') { return customImporter.returnValue; } + if (url === 'import-with-custom-resolver') { + return customResolver.returnValue; + } // Do not transform css imports if (/\.css$/.test(url) === false) { // eslint-disable-next-line no-param-reassign @@ -83,6 +91,7 @@ function createSpec(ext) { .replace(/^~@org\/pkg/, pathToScopedNpmPkg) .replace(/^~module/, pathToModule) .replace(/^~another/, pathToAnother) + .replace(/^unresolvable/, pathToUnresolvable) .replace(/^~/, testNodeModules) .replace(/^path-to-alias/, pathToFooAlias); } diff --git a/test/tools/customResolver.js b/test/tools/customResolver.js new file mode 100644 index 00000000..f3c13f20 --- /dev/null +++ b/test/tools/customResolver.js @@ -0,0 +1,18 @@ +'use strict'; + +require('should'); + +function customResolver(path, prev) { + path.should.equal('import-with-custom-resolver'); + prev.should.match(/(sass|scss)[/\\]custom-resolver\.(scss|sass)/); + + this.should.have.property('options'); // eslint-disable-line no-invalid-this + + return customResolver.returnValue; +} + +customResolver.returnValue = { + contents: '.custom-resolver {}', +}; + +module.exports = customResolver;