Skip to content

Commit 17832fd

Browse files
fix: resolution for file scheme
1 parent 744112d commit 17832fd

File tree

5 files changed

+69
-21
lines changed

5 files changed

+69
-21
lines changed

src/webpackImporter.js

+39-21
Original file line numberDiff line numberDiff line change
@@ -70,41 +70,59 @@ function webpackImporter(loaderContext, includePaths) {
7070
mainFiles: [],
7171
modules: [],
7272
});
73+
// TODO implement the `restrictions` option for `enhanced-resolve` and avoid resolution `js` files from the `mainFields`
74+
// TODO avoid resolsing `_index`, `index` and files without extensions
75+
// TODO avoid resolving with multiple extensions - `file.sass.sass`/`file.sass.scss`/`file.sass.css`
7376
const webpackResolve = loaderContext.getResolve({
7477
mainFields: ['sass', 'style', 'main', '...'],
7578
mainFiles: ['_index', 'index', '...'],
7679
extensions: ['.sass', '.scss', '.css'],
7780
});
7881

79-
return (url, prev, done) => {
80-
// The order of import precedence is as follows:
81-
//
82-
// 1. Filesystem imports relative to the base file.
83-
// 2. Custom importer imports.
84-
// 3. Filesystem imports relative to the working directory.
85-
// 4. Filesystem imports relative to an `includePaths` path.
86-
// 5. Filesystem imports relative to a `SASS_PATH` path.
87-
//
88-
// Because `sass`/`node-sass` run custom importers after `3`, `4` and `5` points, we need to emulate this behavior to avoid wrong resolution.
89-
const sassPossibleRequests = getPossibleRequests(url);
90-
const webpackPossibleRequests = getPossibleRequests(url, true);
91-
const resolutionMap = []
92-
.concat(
82+
return (originalUrl, prev, done) => {
83+
let url = originalUrl;
84+
85+
const isFileScheme = originalUrl.startsWith('file:');
86+
87+
if (isFileScheme) {
88+
// eslint-disable-next-line no-param-reassign
89+
url = originalUrl.slice(5);
90+
}
91+
92+
let resolutionMap = [];
93+
94+
if (includePaths.length > 0 && !isFileScheme) {
95+
// The order of import precedence is as follows:
96+
//
97+
// 1. Filesystem imports relative to the base file.
98+
// 2. Custom importer imports.
99+
// 3. Filesystem imports relative to the working directory.
100+
// 4. Filesystem imports relative to an `includePaths` path.
101+
// 5. Filesystem imports relative to a `SASS_PATH` path.
102+
//
103+
// Because `sass`/`node-sass` run custom importers before `3`, `4` and `5` points, we need to emulate this behavior to avoid wrong resolution.
104+
const sassPossibleRequests = getPossibleRequests(url);
105+
106+
resolutionMap = resolutionMap.concat(
93107
includePaths.map((context) => ({
94108
resolve: sassResolve,
95109
context,
96110
possibleRequests: sassPossibleRequests,
97111
}))
98-
)
99-
.concat({
100-
resolve: webpackResolve,
101-
context: dirContextFrom(prev),
102-
possibleRequests: webpackPossibleRequests,
103-
});
112+
);
113+
}
114+
115+
const webpackPossibleRequests = getPossibleRequests(url, true);
116+
117+
resolutionMap = resolutionMap.concat({
118+
resolve: webpackResolve,
119+
context: isFileScheme ? '/' : dirContextFrom(prev),
120+
possibleRequests: webpackPossibleRequests,
121+
});
104122

105123
startResolving(resolutionMap)
106124
// Catch all resolving errors, return the original file and pass responsibility back to other custom importers
107-
.catch(() => ({ file: url }))
125+
.catch(() => ({ file: originalUrl }))
108126
.then(done);
109127
};
110128
}

test/helpers/getCodeFromSass.js

+4
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,9 @@ function getCodeFromSass(testId, options) {
252252
testFolder,
253253
'node_modules/package-with-js-and-css-main-files/index'
254254
);
255+
const pathToLanguage = isSass
256+
? path.resolve(testFolder, 'sass/language.sass')
257+
: path.resolve(testFolder, 'scss/language.scss');
255258

256259
// Pseudo importer for tests
257260
function testImporter(url) {
@@ -710,6 +713,7 @@ function getCodeFromSass(testId, options) {
710713
/^~package-with-js-and-css-main-files/,
711714
pathToPackageWithJsAndCssMainFiles
712715
)
716+
.replace(/^file:language/, pathToLanguage)
713717
.replace(/^~/, testNodeModules);
714718
}
715719

test/loader.test.js

+24
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,30 @@ describe('loader', () => {
721721
expect(getErrors(stats)).toMatchSnapshot('errors');
722722
});
723723

724+
// TODO need fix on webpack@5 side
725+
it.skip(`should support resolving using the "file" schema (${implementationName}) (${syntax})`, async () => {
726+
const testId = getTestId('import-file-scheme', syntax);
727+
const options = {
728+
implementation: getImplementationByName(implementationName),
729+
};
730+
const compiler = getCompiler(testId, {
731+
loader: { options },
732+
resolve: {
733+
alias: {
734+
'/language': path.resolve('./test', syntax, `language.${syntax}`),
735+
},
736+
},
737+
});
738+
const stats = await compile(compiler);
739+
const codeFromBundle = getCodeFromBundle(stats, compiler);
740+
const codeFromSass = getCodeFromSass(testId, options);
741+
742+
expect(codeFromBundle.css).toBe(codeFromSass.css);
743+
expect(codeFromBundle.css).toMatchSnapshot('css');
744+
expect(getWarnings(stats)).toMatchSnapshot('warnings');
745+
expect(getErrors(stats)).toMatchSnapshot('errors');
746+
});
747+
724748
if (implementation === dartSass) {
725749
it(`should output an understandable error with a problem in "@use" (${implementationName}) (${syntax})`, async () => {
726750
const testId = getTestId('error-use', syntax);

test/sass/import-file-scheme.sass

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@import 'file:language'

test/scss/import-file-scheme.scss

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@import 'file:language';

0 commit comments

Comments
 (0)