Skip to content

Commit aeb86f0

Browse files
fix: resolution logic (#839)
1 parent 7380b7b commit aeb86f0

8 files changed

+114
-30
lines changed

src/getPossibleRequests.js

+17-10
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ const matchModuleImport = /^~([^/]+|[^/]+\/|@[^/]+[/][^/]+|@[^/]+\/?|@[^/]+[/][^
1818
* to enable straight-forward webpack.config aliases.
1919
*
2020
* @param {string} url
21+
* @param {boolean} forWebpackResolver
2122
* @returns {Array<string>}
2223
*/
23-
export default function getPossibleRequests(url) {
24+
export default function getPossibleRequests(url, forWebpackResolver = false) {
2425
const request = utils.urlToRequest(url);
2526

2627
// In case there is module request, send this to webpack resolver
27-
if (matchModuleImport.test(url)) {
28+
if (forWebpackResolver && matchModuleImport.test(url)) {
2829
return [request, url];
2930
}
3031

@@ -51,23 +52,29 @@ export default function getPossibleRequests(url) {
5152
//
5253
// 1. Try to resolve `_` file.
5354
// 2. Try to resolve file without `_`.
54-
// 3. Send a original url to webpack resolver, maybe it is alias.
55-
if (['.scss', '.sass'].includes(ext)) {
56-
return [`${dirname}/_${basename}`, `${dirname}/${basename}`, url];
55+
// 3. Send a original url to webpack resolver, maybe it is alias for webpack resolving.
56+
if (['.scss', '.sass', '.css'].includes(ext)) {
57+
return [`${dirname}/_${basename}`, `${dirname}/${basename}`].concat(
58+
forWebpackResolver ? [url] : []
59+
);
5760
}
5861

5962
// In case there is no file extension
6063
//
61-
// 1. Try to resolve files starts with `_` and normal with order `sass`, `scss` and `css`
62-
// 2. Send a original url to webpack resolver, maybe it is alias.
64+
// 1. Try to resolve files starts with `_` and normal with order `sass`, `scss` and `css`.
65+
// 2. Send a original url to webpack resolver, maybe it is alias for webpack resolving.
6366
return [
6467
`${dirname}/_${basename}.sass`,
6568
`${dirname}/${basename}.sass`,
6669
`${dirname}/_${basename}.scss`,
6770
`${dirname}/${basename}.scss`,
6871
`${dirname}/_${basename}.css`,
6972
`${dirname}/${basename}.css`,
70-
request,
71-
url,
72-
];
73+
`${dirname}/${basename}/_index.sass`,
74+
`${dirname}/${basename}/index.sass`,
75+
`${dirname}/${basename}/_index.scss`,
76+
`${dirname}/${basename}/index.scss`,
77+
`${dirname}/${basename}/_index.css`,
78+
`${dirname}/${basename}/index.css`,
79+
].concat(forWebpackResolver ? [request, url] : []);
7380
}

src/index.js

+2-5
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,10 @@ function loader(content) {
3636
const resolve = this.getResolve({
3737
mainFields: ['sass', 'style', 'main', '...'],
3838
mainFiles: ['_index', 'index', '...'],
39-
extensions: ['.scss', '.sass', '.css'],
39+
extensions: ['.sass', '.scss', '.css'],
4040
});
4141

42-
const includePaths =
43-
options.sassOptions && options.sassOptions.includePaths
44-
? options.sassOptions.includePaths
45-
: [];
42+
const { includePaths } = sassOptions;
4643

4744
sassOptions.importer.push(webpackImporter(this, resolve, includePaths));
4845
}

src/webpackImporter.js

+21-12
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
/**
2-
* @name PromisedResolve
3-
* @type {Function}
4-
* @param {string} dir
5-
* @param {string} request
6-
* @returns Promise
7-
*/
8-
91
/**
102
* @name Importer
113
* @type {Function}
@@ -69,11 +61,28 @@ function webpackImporter(loaderContext, resolve, includePaths) {
6961
}
7062

7163
return (url, prev, done) => {
72-
const possibleRequests = getPossibleRequests(url);
64+
// The order of import precedence is as follows:
65+
//
66+
// 1. Filesystem imports relative to the base file.
67+
// 2. Custom importer imports.
68+
// 3. Filesystem imports relative to the working directory.
69+
// 4. Filesystem imports relative to an `includePaths` path.
70+
// 5. Filesystem imports relative to a `SASS_PATH` path.
71+
//
72+
// Because `sass`/`node-sass` run custom importers after `3`, `4` and `5` points, we need to emulate this behavior to avoid wrong resolution.
73+
const sassPossibleRequests = getPossibleRequests(url);
74+
const webpackPossibleRequests = getPossibleRequests(url, true);
7375
const resolutionMap = []
74-
.concat(includePaths)
75-
.concat(dirContextFrom(prev))
76-
.map((context) => ({ context, possibleRequests }));
76+
.concat(
77+
includePaths.map((context) => ({
78+
context,
79+
possibleRequests: sassPossibleRequests,
80+
}))
81+
)
82+
.concat({
83+
context: dirContextFrom(prev),
84+
possibleRequests: webpackPossibleRequests,
85+
});
7786

7887
startResolving(resolutionMap)
7988
// Catch all resolving errors, return the original file and pass responsibility back to other custom importers

test/__snapshots__/loader.test.js.snap

+40
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,46 @@ SassError: expected \\"{\\".",
224224

225225
exports[`loader should output an understandable error with a problem in "@use" (dart-sass) (scss): warnings 1`] = `Array []`;
226226

227+
exports[`loader should respect resolving directory with the "index" file from "process.cwd()" (dart-sass) (sass): css 1`] = `
228+
".dir-with-underscore-index {
229+
color: red;
230+
}"
231+
`;
232+
233+
exports[`loader should respect resolving directory with the "index" file from "process.cwd()" (dart-sass) (sass): errors 1`] = `Array []`;
234+
235+
exports[`loader should respect resolving directory with the "index" file from "process.cwd()" (dart-sass) (sass): warnings 1`] = `Array []`;
236+
237+
exports[`loader should respect resolving directory with the "index" file from "process.cwd()" (dart-sass) (scss): css 1`] = `
238+
".dir-with-underscore-index {
239+
color: red;
240+
}"
241+
`;
242+
243+
exports[`loader should respect resolving directory with the "index" file from "process.cwd()" (dart-sass) (scss): errors 1`] = `Array []`;
244+
245+
exports[`loader should respect resolving directory with the "index" file from "process.cwd()" (dart-sass) (scss): warnings 1`] = `Array []`;
246+
247+
exports[`loader should respect resolving directory with the "index" file from "process.cwd()" (node-sass) (sass): css 1`] = `
248+
".dir-with-underscore-index {
249+
color: red; }
250+
"
251+
`;
252+
253+
exports[`loader should respect resolving directory with the "index" file from "process.cwd()" (node-sass) (sass): errors 1`] = `Array []`;
254+
255+
exports[`loader should respect resolving directory with the "index" file from "process.cwd()" (node-sass) (sass): warnings 1`] = `Array []`;
256+
257+
exports[`loader should respect resolving directory with the "index" file from "process.cwd()" (node-sass) (scss): css 1`] = `
258+
".dir-with-underscore-index {
259+
color: red; }
260+
"
261+
`;
262+
263+
exports[`loader should respect resolving directory with the "index" file from "process.cwd()" (node-sass) (scss): errors 1`] = `Array []`;
264+
265+
exports[`loader should respect resolving directory with the "index" file from "process.cwd()" (node-sass) (scss): warnings 1`] = `Array []`;
266+
227267
exports[`loader should respect resolving from "process.cwd()" (dart-sass) (sass): css 1`] = `
228268
"body {
229269
font: 100% Helvetica, sans-serif;

test/helpers/getCodeFromSass.js

+12
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,18 @@ function getCodeFromSass(testId, options) {
259259
if (/\.css$/i.test(url) === false) {
260260
// Polyfill for node-sass implementation
261261
if (isNodeSassImplementation) {
262+
if (url === 'test/scss/dir-with-underscore-index') {
263+
return {
264+
file: pathToSCSSIndexAlias,
265+
};
266+
}
267+
268+
if (url === 'test/sass/dir-with-underscore-index') {
269+
return {
270+
file: pathToSassIndexAlias,
271+
};
272+
}
273+
262274
if (url === '~sass-package-with-index') {
263275
return {
264276
file: pathToSassPackageWithIndexFile,

test/loader.test.js

+20-3
Original file line numberDiff line numberDiff line change
@@ -656,8 +656,6 @@ describe('loader', () => {
656656
});
657657

658658
it(`should respect resolving from the "SASS_PATH" environment variable (${implementationName}) (${syntax})`, async () => {
659-
const OLD_SASS_PATH = process.env.SASS_PATH;
660-
661659
process.env.SASS_PATH =
662660
process.platform === 'win32'
663661
? `${path.resolve('test', syntax, 'sass_path')};${path.resolve(
@@ -685,7 +683,7 @@ describe('loader', () => {
685683
expect(getWarnings(stats)).toMatchSnapshot('warnings');
686684
expect(getErrors(stats)).toMatchSnapshot('errors');
687685

688-
process.env.SASS_PATH = OLD_SASS_PATH;
686+
delete process.env.SASS_PATH;
689687
});
690688

691689
it(`should respect resolving from "process.cwd()" (${implementationName}) (${syntax})`, async () => {
@@ -704,6 +702,25 @@ describe('loader', () => {
704702
expect(getErrors(stats)).toMatchSnapshot('errors');
705703
});
706704

705+
it(`should respect resolving directory with the "index" file from "process.cwd()" (${implementationName}) (${syntax})`, async () => {
706+
const testId = getTestId(
707+
'process-cwd-with-index-file-inside-directory',
708+
syntax
709+
);
710+
const options = {
711+
implementation: getImplementationByName(implementationName),
712+
};
713+
const compiler = getCompiler(testId, { loader: { options } });
714+
const stats = await compile(compiler);
715+
const codeFromBundle = getCodeFromBundle(stats, compiler);
716+
const codeFromSass = getCodeFromSass(testId, options);
717+
718+
expect(codeFromBundle.css).toBe(codeFromSass.css);
719+
expect(codeFromBundle.css).toMatchSnapshot('css');
720+
expect(getWarnings(stats)).toMatchSnapshot('warnings');
721+
expect(getErrors(stats)).toMatchSnapshot('errors');
722+
});
723+
707724
if (implementation === dartSass) {
708725
it(`should output an understandable error with a problem in "@use" (${implementationName}) (${syntax})`, async () => {
709726
const testId = getTestId('error-use', syntax);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@import 'test/sass/dir-with-underscore-index'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@import 'test/scss/dir-with-underscore-index';

0 commit comments

Comments
 (0)