Skip to content

Commit 76f1480

Browse files
authoredJul 8, 2020
fix: resolution algorithm for CSS modules
1 parent f9b8ef9 commit 76f1480

22 files changed

+299
-110
lines changed
 

‎README.md

+2
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,8 @@ exports.locals = {
415415

416416
To import a local classname from another module.
417417

418+
> i We strongly recommend that you specify the extension when importing a file, since it is possible to import a file with any extension and it is not known in advance which file to use.
419+
418420
```css
419421
:local(.continueButton) {
420422
composes: button from 'library/button.css';

‎src/index.js

+18-3
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,19 @@ export default function loader(content, map, meta) {
4343
const preRequester = getPreRequester(this);
4444
const urlHandler = (url) =>
4545
stringifyRequest(this, preRequester(options.importLoaders) + url);
46+
const icssResolver = this.getResolve({
47+
mainFields: ['css', 'style', 'main', '...'],
48+
mainFiles: ['index', '...'],
49+
});
4650

47-
plugins.push(icssParser({ urlHandler }));
51+
plugins.push(
52+
icssParser({
53+
context: this.context,
54+
rootContext: this.rootContext,
55+
resolver: icssResolver,
56+
urlHandler,
57+
})
58+
);
4859

4960
if (options.import !== false && exportType === 'full') {
5061
const resolver = this.getResolve({
@@ -136,8 +147,6 @@ export default function loader(content, map, meta) {
136147
}
137148
}
138149

139-
apiImports.sort((a, b) => a.index - b.index);
140-
141150
/*
142151
* Order
143152
* CSS_LOADER_ICSS_IMPORT: [],
@@ -153,6 +162,12 @@ export default function loader(content, map, meta) {
153162
(b.index < a.index) - (a.index < b.index)
154163
);
155164
});
165+
apiImports.sort((a, b) => {
166+
return (
167+
(b.order < a.order) - (a.order < b.order) ||
168+
(b.index < a.index) - (a.index < b.index)
169+
);
170+
});
156171

157172
const { localsConvention } = options;
158173
const esModule =

‎src/plugins/postcss-icss-parser.js

+110-49
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import postcss from 'postcss';
22
import { extractICSS, replaceValueSymbols, replaceSymbols } from 'icss-utils';
3-
import { urlToRequest } from 'loader-utils';
43

5-
function makeRequestableIcssImports(icssImports) {
4+
import { normalizeUrl, resolveRequests, isUrlRequestable } from '../utils';
5+
6+
function makeRequestableIcssImports(icssImports, rootContext) {
67
return Object.keys(icssImports).reduce((accumulator, url) => {
78
const tokensMap = icssImports[url];
89
const tokens = Object.keys(tokensMap);
@@ -11,16 +12,27 @@ function makeRequestableIcssImports(icssImports) {
1112
return accumulator;
1213
}
1314

14-
const normalizedUrl = urlToRequest(url);
15+
const isRequestable = isUrlRequestable(url);
16+
17+
let normalizedUrl;
18+
19+
if (isRequestable) {
20+
normalizedUrl = normalizeUrl(url, true, rootContext);
21+
}
1522

16-
if (!accumulator[normalizedUrl]) {
23+
const key = typeof normalizedUrl !== 'undefined' ? normalizedUrl : url;
24+
25+
if (!accumulator[key]) {
1726
// eslint-disable-next-line no-param-reassign
18-
accumulator[normalizedUrl] = tokensMap;
27+
accumulator[key] = { url, tokenMap: tokensMap };
1928
} else {
2029
// eslint-disable-next-line no-param-reassign
21-
accumulator[normalizedUrl] = {
22-
...accumulator[normalizedUrl],
23-
...tokensMap,
30+
accumulator[key] = {
31+
url,
32+
tokenMap: {
33+
...accumulator[key].tokenMap,
34+
...tokensMap,
35+
},
2436
};
2537
}
2638

@@ -31,55 +43,104 @@ function makeRequestableIcssImports(icssImports) {
3143
export default postcss.plugin(
3244
'postcss-icss-parser',
3345
(options) => (css, result) => {
34-
const importReplacements = Object.create(null);
35-
const extractedICSS = extractICSS(css);
36-
const icssImports = makeRequestableIcssImports(extractedICSS.icssImports);
37-
38-
for (const [importIndex, url] of Object.keys(icssImports).entries()) {
39-
const importName = `___CSS_LOADER_ICSS_IMPORT_${importIndex}___`;
40-
41-
result.messages.push(
42-
{
43-
type: 'import',
44-
value: {
45-
// 'CSS_LOADER_ICSS_IMPORT'
46-
order: 0,
47-
importName,
48-
url: options.urlHandler ? options.urlHandler(url) : url,
49-
},
50-
},
51-
{
52-
type: 'api-import',
53-
value: { type: 'internal', importName, dedupe: true },
54-
}
46+
return new Promise(async (resolve, reject) => {
47+
const importReplacements = Object.create(null);
48+
const extractedICSS = extractICSS(css);
49+
const icssImports = makeRequestableIcssImports(
50+
extractedICSS.icssImports,
51+
options.rootContext
5552
);
5653

57-
const tokenMap = icssImports[url];
58-
const tokens = Object.keys(tokenMap);
59-
60-
for (const [replacementIndex, token] of tokens.entries()) {
61-
const replacementName = `___CSS_LOADER_ICSS_IMPORT_${importIndex}_REPLACEMENT_${replacementIndex}___`;
62-
const localName = tokenMap[token];
54+
const tasks = [];
55+
56+
let index = 0;
57+
58+
for (const [importIndex, normalizedUrl] of Object.keys(
59+
icssImports
60+
).entries()) {
61+
const { url } = icssImports[normalizedUrl];
62+
63+
index += 1;
64+
65+
tasks.push(
66+
Promise.resolve(index).then(async (currentIndex) => {
67+
const importName = `___CSS_LOADER_ICSS_IMPORT_${importIndex}___`;
68+
const { resolver, context } = options;
69+
70+
let resolvedUrl;
71+
72+
try {
73+
resolvedUrl = await resolveRequests(resolver, context, [
74+
...new Set([normalizedUrl, url]),
75+
]);
76+
} catch (error) {
77+
throw error;
78+
}
79+
80+
result.messages.push(
81+
{
82+
type: 'import',
83+
value: {
84+
// 'CSS_LOADER_ICSS_IMPORT'
85+
order: 0,
86+
importName,
87+
url: options.urlHandler(resolvedUrl),
88+
index: currentIndex,
89+
},
90+
},
91+
{
92+
type: 'api-import',
93+
value: {
94+
// 'CSS_LOADER_ICSS_IMPORT'
95+
order: 0,
96+
type: 'internal',
97+
importName,
98+
dedupe: true,
99+
index: currentIndex,
100+
},
101+
}
102+
);
103+
104+
const { tokenMap } = icssImports[normalizedUrl];
105+
const tokens = Object.keys(tokenMap);
106+
107+
for (const [replacementIndex, token] of tokens.entries()) {
108+
const replacementName = `___CSS_LOADER_ICSS_IMPORT_${importIndex}_REPLACEMENT_${replacementIndex}___`;
109+
const localName = tokenMap[token];
110+
111+
importReplacements[token] = replacementName;
112+
113+
result.messages.push({
114+
type: 'icss-replacement',
115+
value: { replacementName, importName, localName },
116+
});
117+
}
118+
})
119+
);
120+
}
63121

64-
importReplacements[token] = replacementName;
122+
try {
123+
await Promise.all(tasks);
124+
} catch (error) {
125+
reject(error);
126+
}
65127

66-
result.messages.push({
67-
type: 'icss-replacement',
68-
value: { replacementName, importName, localName },
69-
});
128+
if (Object.keys(importReplacements).length > 0) {
129+
replaceSymbols(css, importReplacements);
70130
}
71-
}
72131

73-
if (Object.keys(importReplacements).length > 0) {
74-
replaceSymbols(css, importReplacements);
75-
}
132+
const { icssExports } = extractedICSS;
76133

77-
const { icssExports } = extractedICSS;
134+
for (const name of Object.keys(icssExports)) {
135+
const value = replaceValueSymbols(
136+
icssExports[name],
137+
importReplacements
138+
);
78139

79-
for (const name of Object.keys(icssExports)) {
80-
const value = replaceValueSymbols(icssExports[name], importReplacements);
140+
result.messages.push({ type: 'export', value: { name, value } });
141+
}
81142

82-
result.messages.push({ type: 'export', value: { name, value } });
83-
}
143+
resolve();
144+
});
84145
}
85146
);

‎src/plugins/postcss-import-parser.js

+11-4
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,7 @@ export default postcss.plugin(pluginName, (options) => (css, result) => {
137137
// 'CSS_LOADER_AT_RULE_IMPORT'
138138
order: 1,
139139
importName,
140-
url: options.urlHandler
141-
? options.urlHandler(resolvedUrl)
142-
: resolvedUrl,
140+
url: options.urlHandler(resolvedUrl),
143141
index: currentIndex,
144142
},
145143
});
@@ -148,6 +146,8 @@ export default postcss.plugin(pluginName, (options) => (css, result) => {
148146
result.messages.push({
149147
type: 'api-import',
150148
value: {
149+
// 'CSS_LOADER_AT_RULE_IMPORT'
150+
order: 1,
151151
type: 'internal',
152152
importName,
153153
media,
@@ -161,7 +161,14 @@ export default postcss.plugin(pluginName, (options) => (css, result) => {
161161
result.messages.push({
162162
pluginName,
163163
type: 'api-import',
164-
value: { type: 'external', url, media, index: currentIndex },
164+
value: {
165+
// 'CSS_LOADER_AT_RULE_IMPORT'
166+
order: 1,
167+
type: 'external',
168+
url,
169+
media,
170+
index: currentIndex,
171+
},
165172
});
166173
})
167174
);

‎test/__snapshots__/import-option.test.js.snap

+9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`"import" option should emit warning when unresolved import: errors 1`] = `
4+
Array [
5+
"ModuleBuildError: Module build failed (from \`replaced original path\`):
6+
Error: Can't resolve 'unresolved-file.css' in '/test/fixtures/import'",
7+
]
8+
`;
9+
10+
exports[`"import" option should emit warning when unresolved import: warnings 1`] = `Array []`;
11+
312
exports[`"import" option should keep original order: errors 1`] = `Array []`;
413

514
exports[`"import" option should keep original order: module 1`] = `

‎test/__snapshots__/modules-option.test.js.snap

+57-31
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,51 @@ Array [
668668
669669
exports[`"modules" option should keep order: warnings 1`] = `Array []`;
670670
671+
exports[`"modules" option should resolve package from node_modules with and without tilde: errors 1`] = `Array []`;
672+
673+
exports[`"modules" option should resolve package from node_modules with and without tilde: module 1`] = `
674+
"// Imports
675+
var ___CSS_LOADER_API_IMPORT___ = require(\\"../../../../src/runtime/api.js\\");
676+
var ___CSS_LOADER_ICSS_IMPORT_0___ = require(\\"-!../../../../src/index.js??[ident]!../node_modules/test/index.css\\");
677+
var ___CSS_LOADER_ICSS_IMPORT_1___ = require(\\"-!../../../../src/index.js??[ident]!../node_modules/test/index.css\\");
678+
exports = ___CSS_LOADER_API_IMPORT___(false);
679+
exports.i(___CSS_LOADER_ICSS_IMPORT_0___, \\"\\", true);
680+
exports.i(___CSS_LOADER_ICSS_IMPORT_1___, \\"\\", true);
681+
// Module
682+
exports.push([module.id, \\"._1AcMgd5TrMMVc761JDuYuc {\\\\n color: \\" + ___CSS_LOADER_ICSS_IMPORT_0___.locals[\\"foo\\"] + \\";\\\\n background: \\" + ___CSS_LOADER_ICSS_IMPORT_1___.locals[\\"bar\\"] + \\";\\\\n}\\\\n\\\\n\\", \\"\\"]);
683+
// Exports
684+
exports.locals = {
685+
\\"foo\\": \\"\\" + ___CSS_LOADER_ICSS_IMPORT_0___.locals[\\"foo\\"] + \\"\\",
686+
\\"bar\\": \\"\\" + ___CSS_LOADER_ICSS_IMPORT_1___.locals[\\"bar\\"] + \\"\\",
687+
\\"className\\": \\"_1AcMgd5TrMMVc761JDuYuc\\"
688+
};
689+
module.exports = exports;
690+
"
691+
`;
692+
693+
exports[`"modules" option should resolve package from node_modules with and without tilde: result 1`] = `
694+
Array [
695+
Array [
696+
"../../src/index.js?[ident]!./modules/node_modules/test/index.css",
697+
"
698+
",
699+
"",
700+
],
701+
Array [
702+
"./modules/issue-914/source.css",
703+
"._1AcMgd5TrMMVc761JDuYuc {
704+
color: red;
705+
background: green;
706+
}
707+
708+
",
709+
"",
710+
],
711+
]
712+
`;
713+
714+
exports[`"modules" option should resolve package from node_modules with and without tilde: warnings 1`] = `Array []`;
715+
671716
exports[`"modules" option should should work with two leading hyphens: errors 1`] = `Array []`;
672717
673718
exports[`"modules" option should should work with two leading hyphens: module 1`] = `
@@ -1050,25 +1095,21 @@ var ___CSS_LOADER_API_IMPORT___ = require(\\"../../../../src/runtime/api.js\\");
10501095
var ___CSS_LOADER_ICSS_IMPORT_0___ = require(\\"-!../../../../src/index.js??[ident]!./values.css\\");
10511096
var ___CSS_LOADER_ICSS_IMPORT_1___ = require(\\"-!../../../../src/index.js??[ident]!./less-file.less\\");
10521097
var ___CSS_LOADER_ICSS_IMPORT_2___ = require(\\"-!../../../../src/index.js??[ident]!./scss-file.scss\\");
1053-
var ___CSS_LOADER_ICSS_IMPORT_3___ = require(\\"-!../../../../src/index.js??[ident]!./sass-file.sass\\");
10541098
exports = ___CSS_LOADER_API_IMPORT___(false);
10551099
exports.i(___CSS_LOADER_ICSS_IMPORT_0___, \\"\\", true);
10561100
exports.i(___CSS_LOADER_ICSS_IMPORT_1___, \\"\\", true);
10571101
exports.i(___CSS_LOADER_ICSS_IMPORT_2___, \\"\\", true);
1058-
exports.i(___CSS_LOADER_ICSS_IMPORT_3___, \\"\\", true);
10591102
// Module
1060-
exports.push([module.id, \\".globalClassName {\\\\n color: orange;\\\\n}\\\\n\\\\n._2vZioV5tEV-AlqaI8c_mtN {\\\\n color: \\" + ___CSS_LOADER_ICSS_IMPORT_0___.locals[\\"v-def\\"] + \\";\\\\n}\\\\n\\\\n.YX1POP6L7ESwR7pdtyRna {\\\\n color: \\" + ___CSS_LOADER_ICSS_IMPORT_1___.locals[\\"v-foo\\"] + \\";\\\\n}\\\\n\\\\n._1578mz8iEiOG2qNa19R11c {\\\\n color: \\" + ___CSS_LOADER_ICSS_IMPORT_2___.locals[\\"v-bar\\"] + \\";\\\\n}\\\\n\\\\n._1yWiOyfH6HuDl7TOzpnWkK {\\\\n color: \\" + ___CSS_LOADER_ICSS_IMPORT_3___.locals[\\"v-baz\\"] + \\";\\\\n}\\\\n\\\\n.OVj95yO5B9JEdIo3xDMtO {\\\\n background: #000;\\\\n}\\\\n\\", \\"\\"]);
1103+
exports.push([module.id, \\".globalClassName {\\\\n color: orange;\\\\n}\\\\n\\\\n._2vZioV5tEV-AlqaI8c_mtN {\\\\n color: \\" + ___CSS_LOADER_ICSS_IMPORT_0___.locals[\\"v-def\\"] + \\";\\\\n}\\\\n\\\\n.YX1POP6L7ESwR7pdtyRna {\\\\n color: \\" + ___CSS_LOADER_ICSS_IMPORT_1___.locals[\\"v-foo\\"] + \\";\\\\n}\\\\n\\\\n._1578mz8iEiOG2qNa19R11c {\\\\n color: \\" + ___CSS_LOADER_ICSS_IMPORT_2___.locals[\\"v-bar\\"] + \\";\\\\n}\\\\n\\\\n.OVj95yO5B9JEdIo3xDMtO {\\\\n background: #000;\\\\n}\\\\n\\", \\"\\"]);
10611104
// Exports
10621105
exports.locals = {
10631106
\\"v-def\\": \\"\\" + ___CSS_LOADER_ICSS_IMPORT_0___.locals[\\"v-def\\"] + \\"\\",
10641107
\\"v-foo\\": \\"\\" + ___CSS_LOADER_ICSS_IMPORT_1___.locals[\\"v-foo\\"] + \\"\\",
10651108
\\"v-bar\\": \\"\\" + ___CSS_LOADER_ICSS_IMPORT_2___.locals[\\"v-bar\\"] + \\"\\",
1066-
\\"v-baz\\": \\"\\" + ___CSS_LOADER_ICSS_IMPORT_3___.locals[\\"v-baz\\"] + \\"\\",
10671109
\\"globalClassName\\": \\"globalClassName\\",
10681110
\\"ghi\\": \\"_2vZioV5tEV-AlqaI8c_mtN\\",
10691111
\\"class\\": \\"YX1POP6L7ESwR7pdtyRna \\" + ___CSS_LOADER_ICSS_IMPORT_1___.locals[\\"lessClass\\"] + \\"\\",
10701112
\\"other\\": \\"_1578mz8iEiOG2qNa19R11c \\" + ___CSS_LOADER_ICSS_IMPORT_2___.locals[\\"scssClass\\"] + \\"\\",
1071-
\\"last\\": \\"_1yWiOyfH6HuDl7TOzpnWkK \\" + ___CSS_LOADER_ICSS_IMPORT_3___.locals[\\"sassClass\\"] + \\"\\",
10721113
\\"otherClassName\\": \\"OVj95yO5B9JEdIo3xDMtO globalClassName\\"
10731114
};
10741115
module.exports = exports;
@@ -1096,13 +1137,6 @@ Array [
10961137
"._228B9eI0iy8oD-AJowJJdF {
10971138
padding: 15px;
10981139
}
1099-
",
1100-
"",
1101-
],
1102-
Array [
1103-
"../../src/index.js?[ident]!./modules/composes/sass-file.sass",
1104-
"
1105-
11061140
",
11071141
"",
11081142
],
@@ -1124,10 +1158,6 @@ Array [
11241158
color: white;
11251159
}
11261160
1127-
._1yWiOyfH6HuDl7TOzpnWkK {
1128-
color: undefined;
1129-
}
1130-
11311161
.OVj95yO5B9JEdIo3xDMtO {
11321162
background: #000;
11331163
}
@@ -1137,20 +1167,7 @@ Array [
11371167
]
11381168
`;
11391169
1140-
exports[`"modules" option should support resolving in composes preprocessor files with extensions: warnings 1`] = `
1141-
Array [
1142-
"ModuleWarning: Module Warning (from \`replaced original path\`):
1143-
Warning
1144-
1145-
Invalid value definition: v-def: red
1146-
@value v-foo: green
1147-
@value v-bar: white
1148-
@value v-baz: coral
1149-
1150-
.sassClass
1151-
padding: 10px",
1152-
]
1153-
`;
1170+
exports[`"modules" option should support resolving in composes preprocessor files with extensions: warnings 1`] = `Array []`;
11541171
11551172
exports[`"modules" option should support resolving in composes: errors 1`] = `Array []`;
11561173
@@ -1163,7 +1180,7 @@ var ___CSS_LOADER_ICSS_IMPORT_2___ = require(\\"-!../../../../src/index.js??[ide
11631180
var ___CSS_LOADER_ICSS_IMPORT_3___ = require(\\"-!../../../../src/index.js??[ident]!./relative.css\\");
11641181
var ___CSS_LOADER_ICSS_IMPORT_4___ = require(\\"-!../../../../src/index.js??[ident]!./top-relative.css\\");
11651182
var ___CSS_LOADER_ICSS_IMPORT_5___ = require(\\"-!../../../../src/index.js??[ident]!../issue-861/node_modules/package/style.css\\");
1166-
var ___CSS_LOADER_ICSS_IMPORT_6___ = require(\\"-!../../../../src/index.js??[ident]!aliasesComposes/alias.css\\");
1183+
var ___CSS_LOADER_ICSS_IMPORT_6___ = require(\\"-!../../../../src/index.js??[ident]!./alias.css\\");
11671184
var ___CSS_LOADER_AT_RULE_IMPORT_0___ = require(\\"-!../../../../src/index.js??[ident]!./test-other.css\\");
11681185
var ___CSS_LOADER_GET_URL_IMPORT___ = require(\\"../../../../src/runtime/getUrl.js\\");
11691186
var ___CSS_LOADER_URL_IMPORT_0___ = require(\\"../../url/img.png\\");
@@ -1413,6 +1430,15 @@ a {
14131430
14141431
exports[`"modules" option should support resolving in composes: warnings 1`] = `Array []`;
14151432
1433+
exports[`"modules" option should throw error when unresolved import: errors 1`] = `
1434+
Array [
1435+
"ModuleBuildError: Module build failed (from \`replaced original path\`):
1436+
Error: Can't resolve '//exammple.com/unresolved.css' in '/test/fixtures/modules/unresolved'",
1437+
]
1438+
`;
1439+
1440+
exports[`"modules" option should throw error when unresolved import: warnings 1`] = `Array []`;
1441+
14161442
exports[`"modules" option should work and correctly replace escaped symbols: errors 1`] = `Array []`;
14171443
14181444
exports[`"modules" option should work and correctly replace escaped symbols: module 1`] = `

‎test/__snapshots__/onlyLocals-option.test.js.snap

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import ___CSS_LOADER_ICSS_IMPORT_2___ from \\"-!../../../../src/index.js??[ident
1010
import ___CSS_LOADER_ICSS_IMPORT_3___ from \\"-!../../../../src/index.js??[ident]!./relative.css\\";
1111
import ___CSS_LOADER_ICSS_IMPORT_4___ from \\"-!../../../../src/index.js??[ident]!./top-relative.css\\";
1212
import ___CSS_LOADER_ICSS_IMPORT_5___ from \\"-!../../../../src/index.js??[ident]!../issue-861/node_modules/package/style.css\\";
13-
import ___CSS_LOADER_ICSS_IMPORT_6___ from \\"-!../../../../src/index.js??[ident]!aliasesComposes/alias.css\\";
13+
import ___CSS_LOADER_ICSS_IMPORT_6___ from \\"-!../../../../src/index.js??[ident]!./alias.css\\";
1414
// Exports
1515
export default {
1616
\\"v-def\\": \\"\\" + ___CSS_LOADER_ICSS_IMPORT_0___[\\"v-def\\"] + \\"\\",
@@ -122,7 +122,7 @@ var ___CSS_LOADER_ICSS_IMPORT_2___ = require(\\"-!../../../../src/index.js??[ide
122122
var ___CSS_LOADER_ICSS_IMPORT_3___ = require(\\"-!../../../../src/index.js??[ident]!./relative.css\\");
123123
var ___CSS_LOADER_ICSS_IMPORT_4___ = require(\\"-!../../../../src/index.js??[ident]!./top-relative.css\\");
124124
var ___CSS_LOADER_ICSS_IMPORT_5___ = require(\\"-!../../../../src/index.js??[ident]!../issue-861/node_modules/package/style.css\\");
125-
var ___CSS_LOADER_ICSS_IMPORT_6___ = require(\\"-!../../../../src/index.js??[ident]!aliasesComposes/alias.css\\");
125+
var ___CSS_LOADER_ICSS_IMPORT_6___ = require(\\"-!../../../../src/index.js??[ident]!./alias.css\\");
126126
// Exports
127127
module.exports = {
128128
\\"v-def\\": \\"\\" + ___CSS_LOADER_ICSS_IMPORT_0___[\\"v-def\\"] + \\"\\",

‎test/fixtures/import/unresolved.css

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@import "unresolved-file.css";

‎test/fixtures/import/unresolved.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import css from './unresolved.css';
2+
3+
__export__ = css;
4+
5+
export default css;

‎test/fixtures/modules/composes/composes-preprocessors.css

-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
@value v-def from './values.css';
22
@value v-foo from './less-file.less';
33
@value v-bar from './scss-file.scss';
4-
@value v-baz from './sass-file.sass';
54

65
:global(.globalClassName) {
76
color: orange;
@@ -21,11 +20,6 @@
2120
composes: scssClass from "scss-file.scss";
2221
}
2322

24-
.last {
25-
color: v-baz;
26-
composes: sassClass from "sass-file.sass";
27-
}
28-
2923
.otherClassName {
3024
composes: globalClassName from global;
3125
background: #000;

‎test/fixtures/modules/composes/composes.css

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
@import url(./test-other.css) (min-width: 100px);
22

3-
@value v-def from './values.css';
3+
@value v-def from './values\
4+
\
5+
.css';
46
@value v-other from './values.css';
57
@value v-other from './values.css';
68
@value s-white from './values.css';

‎test/fixtures/modules/composes/sass-file.sass

-8
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@value foo from '~test';
2+
@value bar from 'test';
3+
4+
.className {
5+
color: foo;
6+
background: bar;
7+
}
8+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import css from './source.css';
2+
3+
__export__ = css;
4+
5+
export default css;

‎test/fixtures/modules/node_modules/test/index.css

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎test/fixtures/modules/node_modules/test/package.json

+9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@value foo from '//exammple.com/unresolved.css';
2+
3+
.className {
4+
color: foo;
5+
}
6+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import css from './source.css';
2+
3+
__export__ = css;
4+
5+
export default css;

‎test/helpers/getErrors.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import normalizeErrors from './normalizeErrors';
22

3-
export default (stats) => {
4-
return normalizeErrors(stats.compilation.errors).sort();
3+
export default (stats, shortError) => {
4+
return normalizeErrors(stats.compilation.errors, shortError).sort();
55
};

‎test/helpers/normalizeErrors.js

+10-4
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,14 @@ function removeCWD(str) {
1616
.replace(new RegExp(cwd, 'g'), '');
1717
}
1818

19-
export default (errors) => {
20-
return errors.map((error) =>
21-
removeCWD(error.toString().split('\n').slice(0, 12).join('\n'))
22-
);
19+
export default (errors, shortError) => {
20+
return errors.map((error) => {
21+
let errorMessage = error.toString();
22+
23+
if (shortError) {
24+
errorMessage = errorMessage.split('\n').slice(0, 2).join('\n');
25+
}
26+
27+
return removeCWD(errorMessage.split('\n').slice(0, 12).join('\n'));
28+
});
2329
};

‎test/import-option.test.js

+8
Original file line numberDiff line numberDiff line change
@@ -152,4 +152,12 @@ describe('"import" option', () => {
152152
expect(getWarnings(stats)).toMatchSnapshot('warnings');
153153
expect(getErrors(stats)).toMatchSnapshot('errors');
154154
});
155+
156+
it('should emit warning when unresolved import', async () => {
157+
const compiler = getCompiler('./import/unresolved.js');
158+
const stats = await compile(compiler);
159+
160+
expect(getWarnings(stats)).toMatchSnapshot('warnings');
161+
expect(getErrors(stats, true)).toMatchSnapshot('errors');
162+
});
155163
});

‎test/modules-option.test.js

+26
Original file line numberDiff line numberDiff line change
@@ -818,4 +818,30 @@ describe('"modules" option', () => {
818818
expect(getWarnings(stats)).toMatchSnapshot('warnings');
819819
expect(getErrors(stats)).toMatchSnapshot('errors');
820820
});
821+
822+
it('should resolve package from node_modules with and without tilde', async () => {
823+
const compiler = getCompiler('./modules/issue-914/source.js', {
824+
modules: true,
825+
});
826+
const stats = await compile(compiler);
827+
828+
expect(
829+
getModuleSource('./modules/issue-914/source.css', stats)
830+
).toMatchSnapshot('module');
831+
expect(getExecutedCode('main.bundle.js', compiler, stats)).toMatchSnapshot(
832+
'result'
833+
);
834+
expect(getWarnings(stats)).toMatchSnapshot('warnings');
835+
expect(getErrors(stats)).toMatchSnapshot('errors');
836+
});
837+
838+
it('should throw error when unresolved import', async () => {
839+
const compiler = getCompiler('./modules/unresolved/source.js', {
840+
modules: true,
841+
});
842+
const stats = await compile(compiler);
843+
844+
expect(getWarnings(stats)).toMatchSnapshot('warnings');
845+
expect(getErrors(stats, true)).toMatchSnapshot('errors');
846+
});
821847
});

0 commit comments

Comments
 (0)
Please sign in to comment.