Skip to content

Commit 6641a16

Browse files
fix: resolving _index.import.scss/index.import.scss in packages (#906)
1 parent 67aa139 commit 6641a16

File tree

13 files changed

+165
-10
lines changed

13 files changed

+165
-10
lines changed

src/utils.js

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ function getWebpackResolver(
358358
}
359359

360360
const isDartSass = implementation.info.includes("dart-sass");
361-
const sassResolve = promiseResolve(
361+
const sassModuleResolve = promiseResolve(
362362
resolverFactory({
363363
alias: [],
364364
aliasFields: [],
@@ -373,7 +373,22 @@ function getWebpackResolver(
373373
preferRelative: true,
374374
})
375375
);
376-
const webpackResolve = promiseResolve(
376+
const sassImportResolve = promiseResolve(
377+
resolverFactory({
378+
alias: [],
379+
aliasFields: [],
380+
conditionNames: [],
381+
descriptionFiles: [],
382+
extensions: [".sass", ".scss", ".css"],
383+
exportsFields: [],
384+
mainFields: [],
385+
mainFiles: ["_index.import", "_index", "index.import", "index"],
386+
modules: [],
387+
restrictions: [/\.((sa|sc|c)ss)$/i],
388+
preferRelative: true,
389+
})
390+
);
391+
const webpackModuleResolve = promiseResolve(
377392
resolverFactory({
378393
dependencyType: "sass",
379394
conditionNames: ["sass", "style"],
@@ -384,8 +399,19 @@ function getWebpackResolver(
384399
preferRelative: true,
385400
})
386401
);
402+
const webpackImportResolve = promiseResolve(
403+
resolverFactory({
404+
dependencyType: "sass",
405+
conditionNames: ["sass", "style"],
406+
mainFields: ["sass", "style", "main", "..."],
407+
mainFiles: ["_index.import", "_index", "index.import", "index", "..."],
408+
extensions: [".sass", ".scss", ".css"],
409+
restrictions: [/\.((sa|sc|c)ss)$/i],
410+
preferRelative: true,
411+
})
412+
);
387413

388-
return (context, request) => {
414+
return (context, request, fromImport) => {
389415
// See https://github.com/webpack/webpack/issues/12340
390416
// Because `node-sass` calls our importer before `1. Filesystem imports relative to the base file.`
391417
// custom importer may not return `{ file: '/path/to/name.ext' }` and therefore our `context` will be relative
@@ -434,7 +460,7 @@ function getWebpackResolver(
434460
// `node-sass` calls our importer before `1. Filesystem imports relative to the base file.`, so we need emulate this too
435461
if (!isDartSass) {
436462
resolutionMap = resolutionMap.concat({
437-
resolve: sassResolve,
463+
resolve: fromImport ? sassImportResolve : sassModuleResolve,
438464
context: path.dirname(context),
439465
possibleRequests: sassPossibleRequests,
440466
});
@@ -444,7 +470,7 @@ function getWebpackResolver(
444470
// eslint-disable-next-line no-shadow
445471
includePaths.map((context) => {
446472
return {
447-
resolve: sassResolve,
473+
resolve: fromImport ? sassImportResolve : sassModuleResolve,
448474
context,
449475
possibleRequests: sassPossibleRequests,
450476
};
@@ -455,7 +481,7 @@ function getWebpackResolver(
455481
const webpackPossibleRequests = getPossibleRequests(request, true);
456482

457483
resolutionMap = resolutionMap.concat({
458-
resolve: webpackResolve,
484+
resolve: fromImport ? webpackImportResolve : webpackModuleResolve,
459485
context: path.dirname(context),
460486
possibleRequests: webpackPossibleRequests,
461487
});
@@ -464,7 +490,7 @@ function getWebpackResolver(
464490
};
465491
}
466492

467-
const matchCss = /\.css$/i;
493+
const MATCH_CSS = /\.css$/i;
468494

469495
function getWebpackImporter(loaderContext, implementation, includePaths) {
470496
const resolve = getWebpackResolver(
@@ -473,16 +499,18 @@ function getWebpackImporter(loaderContext, implementation, includePaths) {
473499
includePaths
474500
);
475501

476-
return (originalUrl, prev, done) => {
477-
resolve(prev, originalUrl)
502+
return function importer(originalUrl, prev, done) {
503+
const { fromImport } = this;
504+
505+
resolve(prev, originalUrl, fromImport)
478506
.then((result) => {
479507
// Add the result as dependency.
480508
// Although we're also using stats.includedFiles, this might come in handy when an error occurs.
481509
// In this case, we don't get stats.includedFiles from node-sass/sass.
482510
loaderContext.addDependency(path.normalize(result));
483511

484512
// By removing the CSS file extension, we trigger node-sass to include the CSS file instead of just linking it.
485-
done({ file: result.replace(matchCss, "") });
513+
done({ file: result.replace(MATCH_CSS, "") });
486514
})
487515
// Catch all resolving errors, return the original file and pass responsibility back to other custom importers
488516
.catch(() => {

test/__snapshots__/loader.test.js.snap

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,45 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`loader should import .import.sass files (dart-sass) (sass): css 1`] = `
4+
"a {
5+
display: block;
6+
}"
7+
`;
8+
9+
exports[`loader should import .import.sass files (dart-sass) (sass): errors 1`] = `Array []`;
10+
11+
exports[`loader should import .import.sass files (dart-sass) (sass): warnings 1`] = `Array []`;
12+
13+
exports[`loader should import .import.sass files from a package (dart-sass) (sass): css 1`] = `
14+
"a {
15+
display: block;
16+
}"
17+
`;
18+
19+
exports[`loader should import .import.sass files from a package (dart-sass) (sass): errors 1`] = `Array []`;
20+
21+
exports[`loader should import .import.sass files from a package (dart-sass) (sass): warnings 1`] = `Array []`;
22+
23+
exports[`loader should import .import.scss files (dart-sass) (scss): css 1`] = `
24+
"a {
25+
display: block;
26+
}"
27+
`;
28+
29+
exports[`loader should import .import.scss files (dart-sass) (scss): errors 1`] = `Array []`;
30+
31+
exports[`loader should import .import.scss files (dart-sass) (scss): warnings 1`] = `Array []`;
32+
33+
exports[`loader should import .import.scss files from a package (dart-sass) (scss): css 1`] = `
34+
"a {
35+
display: block;
36+
}"
37+
`;
38+
39+
exports[`loader should import .import.scss files from a package (dart-sass) (scss): errors 1`] = `Array []`;
40+
41+
exports[`loader should import .import.scss files from a package (dart-sass) (scss): warnings 1`] = `Array []`;
42+
343
exports[`loader should load files with underscore in the name (dart-sass) (sass): css 1`] = `
444
"a {
545
color: red;
@@ -80,6 +120,24 @@ exports[`loader should load only sass/scss files for the "mainFiles" (node-sass)
80120

81121
exports[`loader should load only sass/scss files for the "mainFiles" (node-sass) (scss): warnings 1`] = `Array []`;
82122

123+
exports[`loader should not use .import.sass files (dart-sass) (sass): errors 1`] = `
124+
Array [
125+
"ModuleBuildError: Module build failed (from ../src/cjs.js):
126+
SassError: Can't find stylesheet to import.",
127+
]
128+
`;
129+
130+
exports[`loader should not use .import.sass files (dart-sass) (sass): warnings 1`] = `Array []`;
131+
132+
exports[`loader should not use .import.scss files (dart-sass) (scss): errors 1`] = `
133+
Array [
134+
"ModuleBuildError: Module build failed (from ../src/cjs.js):
135+
SassError: Can't find stylesheet to import.",
136+
]
137+
`;
138+
139+
exports[`loader should not use .import.scss files (dart-sass) (scss): warnings 1`] = `Array []`;
140+
83141
exports[`loader should output an understandable error (dart-sass) (sass): errors 1`] = `
84142
Array [
85143
"ModuleBuildError: Module build failed (from ../src/cjs.js):

test/loader.test.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1599,6 +1599,50 @@ describe("loader", () => {
15991599
expect(getErrors(stats)).toMatchSnapshot("errors");
16001600
});
16011601

1602+
it(`should import .import.${syntax} files (${implementationName}) (${syntax})`, async () => {
1603+
const testId = getTestId("import-index-import", syntax);
1604+
const options = {
1605+
implementation: getImplementationByName(implementationName),
1606+
};
1607+
const compiler = getCompiler(testId, { loader: { options } });
1608+
const stats = await compile(compiler);
1609+
const codeFromBundle = getCodeFromBundle(stats, compiler);
1610+
const codeFromSass = getCodeFromSass(testId, options);
1611+
1612+
expect(codeFromBundle.css).toBe(codeFromSass.css);
1613+
expect(codeFromBundle.css).toMatchSnapshot("css");
1614+
expect(getWarnings(stats)).toMatchSnapshot("warnings");
1615+
expect(getErrors(stats)).toMatchSnapshot("errors");
1616+
});
1617+
1618+
it(`should import .import.${syntax} files from a package (${implementationName}) (${syntax})`, async () => {
1619+
const testId = getTestId("import-index-import-from-package", syntax);
1620+
const options = {
1621+
implementation: getImplementationByName(implementationName),
1622+
};
1623+
const compiler = getCompiler(testId, { loader: { options } });
1624+
const stats = await compile(compiler);
1625+
const codeFromBundle = getCodeFromBundle(stats, compiler);
1626+
const codeFromSass = getCodeFromSass(testId, options);
1627+
1628+
expect(codeFromBundle.css).toBe(codeFromSass.css);
1629+
expect(codeFromBundle.css).toMatchSnapshot("css");
1630+
expect(getWarnings(stats)).toMatchSnapshot("warnings");
1631+
expect(getErrors(stats)).toMatchSnapshot("errors");
1632+
});
1633+
1634+
it(`should not use .import.${syntax} files (${implementationName}) (${syntax})`, async () => {
1635+
const testId = getTestId("use-index-import", syntax);
1636+
const options = {
1637+
implementation: getImplementationByName(implementationName),
1638+
};
1639+
const compiler = getCompiler(testId, { loader: { options } });
1640+
const stats = await compile(compiler);
1641+
1642+
expect(getWarnings(stats)).toMatchSnapshot("warnings");
1643+
expect(getErrors(stats)).toMatchSnapshot("errors");
1644+
});
1645+
16021646
it(`should work and output deprecation message (${implementationName})`, async () => {
16031647
const testId = getTestId("deprecation", syntax);
16041648
const options = {

test/node_modules/index-import-package/_index.import.scss

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/node_modules/index-import-package/package.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@import '~index-import-package'

test/sass/import-index-import.sass

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@import 'index-import'
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
a
2+
display: block

test/sass/use-index-import.sass

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@use 'index-import'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@import '~index-import-package';

0 commit comments

Comments
 (0)