Skip to content

Commit d358cdb

Browse files
authoredDec 17, 2019
feat: esModule option (#1026)
1 parent 23bc1e9 commit d358cdb

17 files changed

+704
-43
lines changed
 

‎README.md

+29
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ module.exports = {
118118
| **[`importLoaders`](#importloaders)** | `{Number}` | `0` | Enables/Disables or setups number of loaders applied before CSS loader |
119119
| **[`localsConvention`](#localsconvention)** | `{String}` | `'asIs'` | Style of exported classnames |
120120
| **[`onlyLocals`](#onlylocals)** | `{Boolean}` | `false` | Export only locals |
121+
| **[`esModule`](#esmodule)** | `{Boolean}` | `false` | Use ES modules syntax |
121122

122123
### `url`
123124

@@ -857,6 +858,34 @@ module.exports = {
857858
};
858859
```
859860

861+
### `esModule`
862+
863+
Type: `Boolean`
864+
Default: `false`
865+
866+
By default, `css-loader` generates JS modules that use the CommonJS modules syntax.
867+
There are some cases in which using ES modules is beneficial, like in the case of [module concatenation](https://webpack.js.org/plugins/module-concatenation-plugin/) and [tree shaking](https://webpack.js.org/guides/tree-shaking/).
868+
869+
You can enable a ES module syntax using:
870+
871+
**webpack.config.js**
872+
873+
```js
874+
module.exports = {
875+
module: {
876+
rules: [
877+
{
878+
test: /\.css$/i,
879+
loader: 'css-loader',
880+
options: {
881+
esModule: true,
882+
},
883+
},
884+
],
885+
},
886+
};
887+
```
888+
860889
## Examples
861890

862891
### Assets

‎package-lock.json

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

‎src/index.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,16 @@ export default function loader(content, map, meta) {
107107
}
108108

109109
const { importLoaders, localsConvention } = options;
110+
const esModule =
111+
typeof options.esModule !== 'undefined' ? options.esModule : false;
112+
110113
const importCode = getImportCode(
111114
this,
112115
imports,
113116
exportType,
114117
sourceMap,
115-
importLoaders
118+
importLoaders,
119+
esModule
116120
);
117121
const moduleCode = getModuleCode(
118122
this,
@@ -126,7 +130,8 @@ export default function loader(content, map, meta) {
126130
exports,
127131
exportType,
128132
replacers,
129-
localsConvention
133+
localsConvention,
134+
esModule
130135
);
131136

132137
return callback(null, [importCode, moduleCode, exportCode].join(''));

‎src/options.json

+4
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@
9494
"onlyLocals": {
9595
"description": "Export only locals (https://github.com/webpack-contrib/css-loader#onlylocals).",
9696
"type": "boolean"
97+
},
98+
"esModule": {
99+
"description": "Use the ES modules syntax (https://github.com/webpack-contrib/css-loader#esmodule).",
100+
"type": "boolean"
97101
}
98102
},
99103
"type": "object"

‎src/utils.js

+62-25
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,8 @@ function getImportCode(
205205
imports,
206206
exportType,
207207
sourceMap,
208-
importLoaders
208+
importLoaders,
209+
esModule
209210
) {
210211
const importItems = [];
211212
const codeItems = [];
@@ -216,12 +217,21 @@ function getImportCode(
216217

217218
if (exportType === 'full') {
218219
importItems.push(
219-
`var ___CSS_LOADER_API_IMPORT___ = require(${stringifyRequest(
220-
loaderContext,
221-
require.resolve('./runtime/api')
222-
)});`
220+
esModule
221+
? `import ___CSS_LOADER_API_IMPORT___ from ${stringifyRequest(
222+
loaderContext,
223+
require.resolve('./runtime/api')
224+
)};`
225+
: `var ___CSS_LOADER_API_IMPORT___ = require(${stringifyRequest(
226+
loaderContext,
227+
require.resolve('./runtime/api')
228+
)});`
229+
);
230+
codeItems.push(
231+
esModule
232+
? `var exports = ___CSS_LOADER_API_IMPORT___(${sourceMap});`
233+
: `exports = ___CSS_LOADER_API_IMPORT___(${sourceMap});`
223234
);
224-
codeItems.push(`exports = ___CSS_LOADER_API_IMPORT___(${sourceMap});`);
225235
}
226236

227237
imports.forEach((item) => {
@@ -251,10 +261,15 @@ function getImportCode(
251261

252262
importName = `___CSS_LOADER_AT_RULE_IMPORT_${atRuleImportNames.size}___`;
253263
importItems.push(
254-
`var ${importName} = require(${stringifyRequest(
255-
loaderContext,
256-
importPrefix + url
257-
)});`
264+
esModule
265+
? `import ${importName} from ${stringifyRequest(
266+
loaderContext,
267+
importPrefix + url
268+
)};`
269+
: `var ${importName} = require(${stringifyRequest(
270+
loaderContext,
271+
importPrefix + url
272+
)});`
258273
);
259274

260275
atRuleImportNames.set(url, importName);
@@ -267,10 +282,15 @@ function getImportCode(
267282
{
268283
if (urlImportNames.size === 0) {
269284
importItems.push(
270-
`var ___CSS_LOADER_GET_URL_IMPORT___ = require(${stringifyRequest(
271-
loaderContext,
272-
require.resolve('./runtime/getUrl.js')
273-
)});`
285+
esModule
286+
? `import ___CSS_LOADER_GET_URL_IMPORT___ from ${stringifyRequest(
287+
loaderContext,
288+
require.resolve('./runtime/getUrl.js')
289+
)};`
290+
: `var ___CSS_LOADER_GET_URL_IMPORT___ = require(${stringifyRequest(
291+
loaderContext,
292+
require.resolve('./runtime/getUrl.js')
293+
)});`
274294
);
275295
}
276296

@@ -281,10 +301,15 @@ function getImportCode(
281301
if (!importName) {
282302
importName = `___CSS_LOADER_URL_IMPORT_${urlImportNames.size}___`;
283303
importItems.push(
284-
`var ${importName} = require(${stringifyRequest(
285-
loaderContext,
286-
url
287-
)});`
304+
esModule
305+
? `import ${importName} from ${stringifyRequest(
306+
loaderContext,
307+
url
308+
)};`
309+
: `var ${importName} = require(${stringifyRequest(
310+
loaderContext,
311+
url
312+
)});`
288313
);
289314

290315
urlImportNames.set(url, importName);
@@ -311,10 +336,15 @@ function getImportCode(
311336
}
312337

313338
importItems.push(
314-
`var ${importName} = require(${stringifyRequest(
315-
loaderContext,
316-
importPrefix + url
317-
)});`
339+
esModule
340+
? `import ${importName} from ${stringifyRequest(
341+
loaderContext,
342+
importPrefix + url
343+
)};`
344+
: `var ${importName} = require(${stringifyRequest(
345+
loaderContext,
346+
importPrefix + url
347+
)});`
318348
);
319349

320350
if (exportType === 'full') {
@@ -380,7 +410,8 @@ function getExportCode(
380410
exports,
381411
exportType,
382412
replacers,
383-
localsConvention
413+
localsConvention,
414+
esModule
384415
) {
385416
const exportItems = [];
386417
let exportLocalsCode;
@@ -448,13 +479,19 @@ function getExportCode(
448479
}
449480

450481
if (exportType === 'locals') {
451-
exportItems.push(`module.exports = {\n${exportLocalsCode}\n};`);
482+
exportItems.push(
483+
`${
484+
esModule ? 'export default' : 'module.exports ='
485+
} {\n${exportLocalsCode}\n};`
486+
);
452487
} else {
453488
if (exportLocalsCode) {
454489
exportItems.push(`exports.locals = {\n${exportLocalsCode}\n};`);
455490
}
456491

457-
exportItems.push('module.exports = exports;');
492+
exportItems.push(
493+
`${esModule ? 'export default' : 'module.exports ='} exports;`
494+
);
458495
}
459496

460497
return `// Exports\n${exportItems.join('\n')}\n`;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`"esModule" option should work when not specified: errors 1`] = `Array []`;
4+
5+
exports[`"esModule" option should work when not specified: module 1`] = `
6+
"// Imports
7+
var ___CSS_LOADER_API_IMPORT___ = require(\\"../../../src/runtime/api.js\\");
8+
var ___CSS_LOADER_AT_RULE_IMPORT_0___ = require(\\"-!../../../src/index.js??[ident]!./imported.css\\");
9+
var ___CSS_LOADER_GET_URL_IMPORT___ = require(\\"../../../src/runtime/getUrl.js\\");
10+
var ___CSS_LOADER_URL_IMPORT_0___ = require(\\"./img.png\\");
11+
exports = ___CSS_LOADER_API_IMPORT___(false);
12+
exports.i(___CSS_LOADER_AT_RULE_IMPORT_0___);
13+
var ___CSS_LOADER_URL_REPLACEMENT_0___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_0___);
14+
// Module
15+
exports.push([module.id, \\"@charset \\\\\\"UTF-8\\\\\\";\\\\n\\\\n/* Comment */\\\\n\\\\n.class {\\\\n color: red;\\\\n background: url(\\" + ___CSS_LOADER_URL_REPLACEMENT_0___ + \\");\\\\n}\\\\n\\", \\"\\"]);
16+
// Exports
17+
module.exports = exports;
18+
"
19+
`;
20+
21+
exports[`"esModule" option should work when not specified: result 1`] = `
22+
Array [
23+
Array [
24+
"../../src/index.js?[ident]!./es-module/imported.css",
25+
".foo {
26+
color: red;
27+
}
28+
",
29+
"",
30+
],
31+
Array [
32+
"./es-module/source.css",
33+
"@charset \\"UTF-8\\";
34+
35+
/* Comment */
36+
37+
.class {
38+
color: red;
39+
background: url(/webpack/public/path/img.png);
40+
}
41+
",
42+
"",
43+
],
44+
]
45+
`;
46+
47+
exports[`"esModule" option should work when not specified: warnings 1`] = `Array []`;
48+
49+
exports[`"esModule" option should work with a value equal to "false": errors 1`] = `Array []`;
50+
51+
exports[`"esModule" option should work with a value equal to "false": module 1`] = `
52+
"// Imports
53+
var ___CSS_LOADER_API_IMPORT___ = require(\\"../../../src/runtime/api.js\\");
54+
var ___CSS_LOADER_AT_RULE_IMPORT_0___ = require(\\"-!../../../src/index.js??[ident]!./imported.css\\");
55+
var ___CSS_LOADER_GET_URL_IMPORT___ = require(\\"../../../src/runtime/getUrl.js\\");
56+
var ___CSS_LOADER_URL_IMPORT_0___ = require(\\"./img.png\\");
57+
exports = ___CSS_LOADER_API_IMPORT___(false);
58+
exports.i(___CSS_LOADER_AT_RULE_IMPORT_0___);
59+
var ___CSS_LOADER_URL_REPLACEMENT_0___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_0___);
60+
// Module
61+
exports.push([module.id, \\"@charset \\\\\\"UTF-8\\\\\\";\\\\n\\\\n/* Comment */\\\\n\\\\n.class {\\\\n color: red;\\\\n background: url(\\" + ___CSS_LOADER_URL_REPLACEMENT_0___ + \\");\\\\n}\\\\n\\", \\"\\"]);
62+
// Exports
63+
module.exports = exports;
64+
"
65+
`;
66+
67+
exports[`"esModule" option should work with a value equal to "false": result 1`] = `
68+
Array [
69+
Array [
70+
"../../src/index.js?[ident]!./es-module/imported.css",
71+
".foo {
72+
color: red;
73+
}
74+
",
75+
"",
76+
],
77+
Array [
78+
"./es-module/source.css",
79+
"@charset \\"UTF-8\\";
80+
81+
/* Comment */
82+
83+
.class {
84+
color: red;
85+
background: url(/webpack/public/path/img.png);
86+
}
87+
",
88+
"",
89+
],
90+
]
91+
`;
92+
93+
exports[`"esModule" option should work with a value equal to "false": warnings 1`] = `Array []`;
94+
95+
exports[`"esModule" option should work with a value equal to "true" and the "mode" value equal to "global": errors 1`] = `Array []`;
96+
97+
exports[`"esModule" option should work with a value equal to "true" and the "mode" value equal to "global": module 1`] = `
98+
"// Imports
99+
import ___CSS_LOADER_API_IMPORT___ from \\"../../../src/runtime/api.js\\";
100+
import ___CSS_LOADER_AT_RULE_IMPORT_0___ from \\"-!../../../src/index.js??[ident]!./imported.css\\";
101+
import ___CSS_LOADER_GET_URL_IMPORT___ from \\"../../../src/runtime/getUrl.js\\";
102+
import ___CSS_LOADER_URL_IMPORT_0___ from \\"./img.png\\";
103+
var exports = ___CSS_LOADER_API_IMPORT___(false);
104+
exports.i(___CSS_LOADER_AT_RULE_IMPORT_0___);
105+
var ___CSS_LOADER_URL_REPLACEMENT_0___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_0___);
106+
// Module
107+
exports.push([module.id, \\"@charset \\\\\\"UTF-8\\\\\\";\\\\n\\\\n/* Comment */\\\\n\\\\n.class {\\\\n color: red;\\\\n background: url(\\" + ___CSS_LOADER_URL_REPLACEMENT_0___ + \\");\\\\n}\\\\n\\", \\"\\"]);
108+
// Exports
109+
export default exports;
110+
"
111+
`;
112+
113+
exports[`"esModule" option should work with a value equal to "true" and the "mode" value equal to "global": result 1`] = `
114+
Array [
115+
Array [
116+
"../../src/index.js?[ident]!./es-module/imported.css",
117+
".foo {
118+
color: red;
119+
}
120+
",
121+
"",
122+
],
123+
Array [
124+
"./es-module/source.css",
125+
"@charset \\"UTF-8\\";
126+
127+
/* Comment */
128+
129+
.class {
130+
color: red;
131+
background: url(/webpack/public/path/img.png);
132+
}
133+
",
134+
"",
135+
],
136+
]
137+
`;
138+
139+
exports[`"esModule" option should work with a value equal to "true" and the "mode" value equal to "global": warnings 1`] = `Array []`;
140+
141+
exports[`"esModule" option should work with a value equal to "true" and the "mode" value equal to "local": errors 1`] = `Array []`;
142+
143+
exports[`"esModule" option should work with a value equal to "true" and the "mode" value equal to "local": module 1`] = `
144+
"// Imports
145+
import ___CSS_LOADER_API_IMPORT___ from \\"../../../src/runtime/api.js\\";
146+
import ___CSS_LOADER_AT_RULE_IMPORT_0___ from \\"-!../../../src/index.js??[ident]!./imported.css\\";
147+
import ___CSS_LOADER_GET_URL_IMPORT___ from \\"../../../src/runtime/getUrl.js\\";
148+
import ___CSS_LOADER_URL_IMPORT_0___ from \\"./img.png\\";
149+
var exports = ___CSS_LOADER_API_IMPORT___(false);
150+
exports.i(___CSS_LOADER_AT_RULE_IMPORT_0___);
151+
var ___CSS_LOADER_URL_REPLACEMENT_0___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_0___);
152+
// Module
153+
exports.push([module.id, \\"@charset \\\\\\"UTF-8\\\\\\";\\\\n\\\\n/* Comment */\\\\n\\\\n._3S58jeCkC6SOPhVLbU-Bwn {\\\\n color: red;\\\\n background: url(\\" + ___CSS_LOADER_URL_REPLACEMENT_0___ + \\");\\\\n}\\\\n\\", \\"\\"]);
154+
// Exports
155+
exports.locals = {
156+
\\"class\\": \\"_3S58jeCkC6SOPhVLbU-Bwn\\"
157+
};
158+
export default exports;
159+
"
160+
`;
161+
162+
exports[`"esModule" option should work with a value equal to "true" and the "mode" value equal to "local": result 1`] = `
163+
Array [
164+
Array [
165+
"../../src/index.js?[ident]!./es-module/imported.css",
166+
"._3xfjtZ03Dx7Cld7Debi-wl {
167+
color: red;
168+
}
169+
",
170+
"",
171+
],
172+
Array [
173+
"./es-module/source.css",
174+
"@charset \\"UTF-8\\";
175+
176+
/* Comment */
177+
178+
._3S58jeCkC6SOPhVLbU-Bwn {
179+
color: red;
180+
background: url(/webpack/public/path/img.png);
181+
}
182+
",
183+
"",
184+
],
185+
]
186+
`;
187+
188+
exports[`"esModule" option should work with a value equal to "true" and the "mode" value equal to "local": warnings 1`] = `Array []`;
189+
190+
exports[`"esModule" option should work with a value equal to "true" and the "mode" value equal to "pure": errors 1`] = `Array []`;
191+
192+
exports[`"esModule" option should work with a value equal to "true" and the "mode" value equal to "pure": module 1`] = `
193+
"// Imports
194+
import ___CSS_LOADER_API_IMPORT___ from \\"../../../src/runtime/api.js\\";
195+
import ___CSS_LOADER_AT_RULE_IMPORT_0___ from \\"-!../../../src/index.js??[ident]!./imported.css\\";
196+
import ___CSS_LOADER_GET_URL_IMPORT___ from \\"../../../src/runtime/getUrl.js\\";
197+
import ___CSS_LOADER_URL_IMPORT_0___ from \\"./img.png\\";
198+
var exports = ___CSS_LOADER_API_IMPORT___(false);
199+
exports.i(___CSS_LOADER_AT_RULE_IMPORT_0___);
200+
var ___CSS_LOADER_URL_REPLACEMENT_0___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_0___);
201+
// Module
202+
exports.push([module.id, \\"@charset \\\\\\"UTF-8\\\\\\";\\\\n\\\\n/* Comment */\\\\n\\\\n._3S58jeCkC6SOPhVLbU-Bwn {\\\\n color: red;\\\\n background: url(\\" + ___CSS_LOADER_URL_REPLACEMENT_0___ + \\");\\\\n}\\\\n\\", \\"\\"]);
203+
// Exports
204+
exports.locals = {
205+
\\"class\\": \\"_3S58jeCkC6SOPhVLbU-Bwn\\"
206+
};
207+
export default exports;
208+
"
209+
`;
210+
211+
exports[`"esModule" option should work with a value equal to "true" and the "mode" value equal to "pure": result 1`] = `
212+
Array [
213+
Array [
214+
"../../src/index.js?[ident]!./es-module/imported.css",
215+
"._3xfjtZ03Dx7Cld7Debi-wl {
216+
color: red;
217+
}
218+
",
219+
"",
220+
],
221+
Array [
222+
"./es-module/source.css",
223+
"@charset \\"UTF-8\\";
224+
225+
/* Comment */
226+
227+
._3S58jeCkC6SOPhVLbU-Bwn {
228+
color: red;
229+
background: url(/webpack/public/path/img.png);
230+
}
231+
",
232+
"",
233+
],
234+
]
235+
`;
236+
237+
exports[`"esModule" option should work with a value equal to "true" and the "mode" value equal to "pure": warnings 1`] = `Array []`;
238+
239+
exports[`"esModule" option should work with a value equal to "true": errors 1`] = `Array []`;
240+
241+
exports[`"esModule" option should work with a value equal to "true": module 1`] = `
242+
"// Imports
243+
import ___CSS_LOADER_API_IMPORT___ from \\"../../../src/runtime/api.js\\";
244+
import ___CSS_LOADER_AT_RULE_IMPORT_0___ from \\"-!../../../src/index.js??[ident]!./imported.css\\";
245+
import ___CSS_LOADER_GET_URL_IMPORT___ from \\"../../../src/runtime/getUrl.js\\";
246+
import ___CSS_LOADER_URL_IMPORT_0___ from \\"./img.png\\";
247+
var exports = ___CSS_LOADER_API_IMPORT___(false);
248+
exports.i(___CSS_LOADER_AT_RULE_IMPORT_0___);
249+
var ___CSS_LOADER_URL_REPLACEMENT_0___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_0___);
250+
// Module
251+
exports.push([module.id, \\"@charset \\\\\\"UTF-8\\\\\\";\\\\n\\\\n/* Comment */\\\\n\\\\n.class {\\\\n color: red;\\\\n background: url(\\" + ___CSS_LOADER_URL_REPLACEMENT_0___ + \\");\\\\n}\\\\n\\", \\"\\"]);
252+
// Exports
253+
export default exports;
254+
"
255+
`;
256+
257+
exports[`"esModule" option should work with a value equal to "true": result 1`] = `
258+
Array [
259+
Array [
260+
"../../src/index.js?[ident]!./es-module/imported.css",
261+
".foo {
262+
color: red;
263+
}
264+
",
265+
"",
266+
],
267+
Array [
268+
"./es-module/source.css",
269+
"@charset \\"UTF-8\\";
270+
271+
/* Comment */
272+
273+
.class {
274+
color: red;
275+
background: url(/webpack/public/path/img.png);
276+
}
277+
",
278+
"",
279+
],
280+
]
281+
`;
282+
283+
exports[`"esModule" option should work with a value equal to "true": warnings 1`] = `Array []`;

‎test/__snapshots__/loader.test.js.snap

+4
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,10 @@ exports[`loader should work with ModuleConcatenationPlugin (url-loader): errors
151151

152152
exports[`loader should work with ModuleConcatenationPlugin (url-loader): warnings 1`] = `Array []`;
153153

154+
exports[`loader should work with ModuleConcatenationPlugin: errors 1`] = `Array []`;
155+
156+
exports[`loader should work with ModuleConcatenationPlugin: warnings 1`] = `Array []`;
157+
154158
exports[`loader should work with empty css: errors 1`] = `Array []`;
155159

156160
exports[`loader should work with empty css: module 1`] = `

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

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

3+
exports[`"onlyLocals" option should work with the "esModule" option: errors 1`] = `Array []`;
4+
5+
exports[`"onlyLocals" option should work with the "esModule" option: module 1`] = `
6+
"// Imports
7+
import ___CSS_LOADER_ICSS_IMPORT_0___ from \\"-!../../../../src/index.js??[ident]!./values.css\\";
8+
import ___CSS_LOADER_ICSS_IMPORT_1___ from \\"-!../../../../src/index.js??[ident]!./something.css\\";
9+
import ___CSS_LOADER_ICSS_IMPORT_2___ from \\"-!../../../../src/index.js??[ident]!./imported-simple.css\\";
10+
import ___CSS_LOADER_ICSS_IMPORT_3___ from \\"-!../../../../src/index.js??[ident]!./relative.css\\";
11+
import ___CSS_LOADER_ICSS_IMPORT_4___ from \\"-!../../../../src/index.js??[ident]!./top-relative.css\\";
12+
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\\";
14+
// Exports
15+
export default {
16+
\\"v-def\\": \\"\\" + ___CSS_LOADER_ICSS_IMPORT_0___[\\"v-def\\"] + \\"\\",
17+
\\"v-other\\": \\"\\" + ___CSS_LOADER_ICSS_IMPORT_0___[\\"v-other\\"] + \\"\\",
18+
\\"s-white\\": \\"\\" + ___CSS_LOADER_ICSS_IMPORT_0___[\\"s-white\\"] + \\"\\",
19+
\\"m-small\\": \\"\\" + ___CSS_LOADER_ICSS_IMPORT_0___[\\"m-small\\"] + \\"\\",
20+
\\"v-something\\": \\"\\" + ___CSS_LOADER_ICSS_IMPORT_1___[\\"v-something\\"] + \\"\\",
21+
\\"v-foo\\": \\"blue\\",
22+
\\"v-bar\\": \\"block\\",
23+
\\"v-primary\\": \\"#BF4040\\",
24+
\\"s-black\\": \\"black-selector\\",
25+
\\"m-large\\": \\"(min-width: 960px)\\",
26+
\\"v-ident\\": \\"validIdent\\",
27+
\\"v-pre-defined-ident\\": \\"left\\",
28+
\\"v-string\\": \\"'content'\\",
29+
\\"v-string-1\\": \\"''\\",
30+
\\"v-url\\": \\"url(https://www.exammple.com/images/my-background.png)\\",
31+
\\"v-url-1\\": \\"url('https://www.exammple.com/images/my-background.png')\\",
32+
\\"v-url-2\\": \\"url(\\\\\\"https://www.exammple.com/images/my-background.png\\\\\\")\\",
33+
\\"v-integer\\": \\"100\\",
34+
\\"v-integer-1\\": \\"-100\\",
35+
\\"v-integer-2\\": \\"+100\\",
36+
\\"v-number\\": \\".60\\",
37+
\\"v-number-1\\": \\"-456.8\\",
38+
\\"v-number-2\\": \\"-3.4e-2\\",
39+
\\"v-dimension\\": \\"12px\\",
40+
\\"v-percentage\\": \\"100%\\",
41+
\\"v-hex\\": \\"#fff\\",
42+
\\"v-function\\": \\"rgb(0,0,0)\\",
43+
\\"v-unicode-range\\": \\"U+0025-00FF\\",
44+
\\"ghi\\": \\"_ghi\\",
45+
\\"class\\": \\"_class\\",
46+
\\"other\\": \\"_other\\",
47+
\\"other-other\\": \\"_other-other\\",
48+
\\"green\\": \\"_green\\",
49+
\\"foo\\": \\"_foo\\",
50+
\\"simple\\": \\"_simple \\" + ___CSS_LOADER_ICSS_IMPORT_2___[\\"imported-simple\\"] + \\"\\",
51+
\\"relative\\": \\"_relative \\" + ___CSS_LOADER_ICSS_IMPORT_3___[\\"imported-relative\\"] + \\"\\",
52+
\\"top-relative\\": \\"_top-relative \\" + ___CSS_LOADER_ICSS_IMPORT_4___[\\"imported-relative\\"] + \\"\\",
53+
\\"module\\": \\"_module \\" + ___CSS_LOADER_ICSS_IMPORT_5___[\\"imported-module\\"] + \\"\\",
54+
\\"alias\\": \\"_alias \\" + ___CSS_LOADER_ICSS_IMPORT_6___[\\"imported-alias\\"] + \\"\\",
55+
\\"primary-selector\\": \\"_primary-selector\\",
56+
\\"black-selector\\": \\"_black-selector\\",
57+
\\"header\\": \\"_header\\",
58+
\\"foobarbaz\\": \\"_foobarbaz\\",
59+
\\"url\\": \\"_url\\"
60+
};
61+
"
62+
`;
63+
64+
exports[`"onlyLocals" option should work with the "esModule" option: result 1`] = `
65+
Object {
66+
"alias": "_alias _imported-alias",
67+
"black-selector": "_black-selector",
68+
"class": "_class",
69+
"foo": "_foo",
70+
"foobarbaz": "_foobarbaz",
71+
"ghi": "_ghi",
72+
"green": "_green",
73+
"header": "_header",
74+
"m-large": "(min-width: 960px)",
75+
"m-small": "(min-width: 320px)",
76+
"module": "_module _imported-module",
77+
"other": "_other",
78+
"other-other": "_other-other",
79+
"primary-selector": "_primary-selector",
80+
"relative": "_relative _imported-relative",
81+
"s-black": "black-selector",
82+
"s-white": "white",
83+
"simple": "_simple _imported-simple",
84+
"top-relative": "_top-relative undefined",
85+
"url": "_url",
86+
"v-bar": "block",
87+
"v-def": "red",
88+
"v-dimension": "12px",
89+
"v-foo": "blue",
90+
"v-function": "rgb(0,0,0)",
91+
"v-hex": "#fff",
92+
"v-ident": "validIdent",
93+
"v-integer": "100",
94+
"v-integer-1": "-100",
95+
"v-integer-2": "+100",
96+
"v-number": ".60",
97+
"v-number-1": "-456.8",
98+
"v-number-2": "-3.4e-2",
99+
"v-other": "green",
100+
"v-percentage": "100%",
101+
"v-pre-defined-ident": "left",
102+
"v-primary": "#BF4040",
103+
"v-something": "2112moon",
104+
"v-string": "'content'",
105+
"v-string-1": "''",
106+
"v-unicode-range": "U+0025-00FF",
107+
"v-url": "url(https://www.exammple.com/images/my-background.png)",
108+
"v-url-1": "url('https://www.exammple.com/images/my-background.png')",
109+
"v-url-2": "url(\\"https://www.exammple.com/images/my-background.png\\")",
110+
}
111+
`;
112+
113+
exports[`"onlyLocals" option should work with the "esModule" option: warnings 1`] = `Array []`;
114+
3115
exports[`"onlyLocals" option should work: errors 1`] = `Array []`;
4116

5117
exports[`"onlyLocals" option should work: module 1`] = `

‎test/__snapshots__/validate-options.test.js.snap

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

3+
exports[`validate options should throw an error on the "esModule" option with "true" value 1`] = `
4+
"Invalid options object. CSS Loader has been initialised using an options object that does not match the API schema.
5+
- options.esModule should be a boolean.
6+
-> Use the ES modules syntax (https://github.com/webpack-contrib/css-loader#esmodule)."
7+
`;
8+
39
exports[`validate options should throw an error on the "import" option with "true" value 1`] = `
410
"Invalid options object. CSS Loader has been initialised using an options object that does not match the API schema.
511
- options.import should be one of these:
@@ -159,49 +165,49 @@ exports[`validate options should throw an error on the "sourceMap" option with "
159165
exports[`validate options should throw an error on the "unknown" option with "/test/" value 1`] = `
160166
"Invalid options object. CSS Loader has been initialised using an options object that does not match the API schema.
161167
- options has an unknown property 'unknown'. These properties are valid:
162-
object { url?, import?, modules?, sourceMap?, importLoaders?, localsConvention?, onlyLocals? }"
168+
object { url?, import?, modules?, sourceMap?, importLoaders?, localsConvention?, onlyLocals?, esModule? }"
163169
`;
164170
165171
exports[`validate options should throw an error on the "unknown" option with "[]" value 1`] = `
166172
"Invalid options object. CSS Loader has been initialised using an options object that does not match the API schema.
167173
- options has an unknown property 'unknown'. These properties are valid:
168-
object { url?, import?, modules?, sourceMap?, importLoaders?, localsConvention?, onlyLocals? }"
174+
object { url?, import?, modules?, sourceMap?, importLoaders?, localsConvention?, onlyLocals?, esModule? }"
169175
`;
170176
171177
exports[`validate options should throw an error on the "unknown" option with "{"foo":"bar"}" value 1`] = `
172178
"Invalid options object. CSS Loader has been initialised using an options object that does not match the API schema.
173179
- options has an unknown property 'unknown'. These properties are valid:
174-
object { url?, import?, modules?, sourceMap?, importLoaders?, localsConvention?, onlyLocals? }"
180+
object { url?, import?, modules?, sourceMap?, importLoaders?, localsConvention?, onlyLocals?, esModule? }"
175181
`;
176182
177183
exports[`validate options should throw an error on the "unknown" option with "{}" value 1`] = `
178184
"Invalid options object. CSS Loader has been initialised using an options object that does not match the API schema.
179185
- options has an unknown property 'unknown'. These properties are valid:
180-
object { url?, import?, modules?, sourceMap?, importLoaders?, localsConvention?, onlyLocals? }"
186+
object { url?, import?, modules?, sourceMap?, importLoaders?, localsConvention?, onlyLocals?, esModule? }"
181187
`;
182188
183189
exports[`validate options should throw an error on the "unknown" option with "1" value 1`] = `
184190
"Invalid options object. CSS Loader has been initialised using an options object that does not match the API schema.
185191
- options has an unknown property 'unknown'. These properties are valid:
186-
object { url?, import?, modules?, sourceMap?, importLoaders?, localsConvention?, onlyLocals? }"
192+
object { url?, import?, modules?, sourceMap?, importLoaders?, localsConvention?, onlyLocals?, esModule? }"
187193
`;
188194
189195
exports[`validate options should throw an error on the "unknown" option with "false" value 1`] = `
190196
"Invalid options object. CSS Loader has been initialised using an options object that does not match the API schema.
191197
- options has an unknown property 'unknown'. These properties are valid:
192-
object { url?, import?, modules?, sourceMap?, importLoaders?, localsConvention?, onlyLocals? }"
198+
object { url?, import?, modules?, sourceMap?, importLoaders?, localsConvention?, onlyLocals?, esModule? }"
193199
`;
194200
195201
exports[`validate options should throw an error on the "unknown" option with "test" value 1`] = `
196202
"Invalid options object. CSS Loader has been initialised using an options object that does not match the API schema.
197203
- options has an unknown property 'unknown'. These properties are valid:
198-
object { url?, import?, modules?, sourceMap?, importLoaders?, localsConvention?, onlyLocals? }"
204+
object { url?, import?, modules?, sourceMap?, importLoaders?, localsConvention?, onlyLocals?, esModule? }"
199205
`;
200206
201207
exports[`validate options should throw an error on the "unknown" option with "true" value 1`] = `
202208
"Invalid options object. CSS Loader has been initialised using an options object that does not match the API schema.
203209
- options has an unknown property 'unknown'. These properties are valid:
204-
object { url?, import?, modules?, sourceMap?, importLoaders?, localsConvention?, onlyLocals? }"
210+
object { url?, import?, modules?, sourceMap?, importLoaders?, localsConvention?, onlyLocals?, esModule? }"
205211
`;
206212
207213
exports[`validate options should throw an error on the "url" option with "true" value 1`] = `

‎test/esModule-option.test.js

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import {
2+
compile,
3+
getCompiler,
4+
getErrors,
5+
getExecutedCode,
6+
getModuleSource,
7+
getWarnings,
8+
} from './helpers/index';
9+
10+
describe('"esModule" option', () => {
11+
it('should work when not specified', async () => {
12+
const compiler = getCompiler('./es-module/source.js');
13+
const stats = await compile(compiler);
14+
15+
expect(getModuleSource('./es-module/source.css', stats)).toMatchSnapshot(
16+
'module'
17+
);
18+
expect(getExecutedCode('main.bundle.js', compiler, stats)).toMatchSnapshot(
19+
'result'
20+
);
21+
expect(getWarnings(stats)).toMatchSnapshot('warnings');
22+
expect(getErrors(stats)).toMatchSnapshot('errors');
23+
});
24+
25+
it('should work with a value equal to "true"', async () => {
26+
const compiler = getCompiler('./es-module/source.js', { esModule: true });
27+
const stats = await compile(compiler);
28+
29+
expect(getModuleSource('./es-module/source.css', stats)).toMatchSnapshot(
30+
'module'
31+
);
32+
expect(getExecutedCode('main.bundle.js', compiler, stats)).toMatchSnapshot(
33+
'result'
34+
);
35+
expect(getWarnings(stats)).toMatchSnapshot('warnings');
36+
expect(getErrors(stats)).toMatchSnapshot('errors');
37+
});
38+
39+
it('should work with a value equal to "true" and the "mode" value equal to "local"', async () => {
40+
const compiler = getCompiler('./es-module/source.js', {
41+
esModule: true,
42+
modules: 'local',
43+
});
44+
const stats = await compile(compiler);
45+
46+
expect(getModuleSource('./es-module/source.css', stats)).toMatchSnapshot(
47+
'module'
48+
);
49+
expect(getExecutedCode('main.bundle.js', compiler, stats)).toMatchSnapshot(
50+
'result'
51+
);
52+
expect(getWarnings(stats)).toMatchSnapshot('warnings');
53+
expect(getErrors(stats)).toMatchSnapshot('errors');
54+
});
55+
56+
it('should work with a value equal to "true" and the "mode" value equal to "global"', async () => {
57+
const compiler = getCompiler('./es-module/source.js', {
58+
esModule: true,
59+
modules: 'global',
60+
});
61+
const stats = await compile(compiler);
62+
63+
expect(getModuleSource('./es-module/source.css', stats)).toMatchSnapshot(
64+
'module'
65+
);
66+
expect(getExecutedCode('main.bundle.js', compiler, stats)).toMatchSnapshot(
67+
'result'
68+
);
69+
expect(getWarnings(stats)).toMatchSnapshot('warnings');
70+
expect(getErrors(stats)).toMatchSnapshot('errors');
71+
});
72+
73+
it('should work with a value equal to "true" and the "mode" value equal to "pure"', async () => {
74+
const compiler = getCompiler('./es-module/source.js', {
75+
esModule: true,
76+
modules: 'pure',
77+
});
78+
const stats = await compile(compiler);
79+
80+
expect(getModuleSource('./es-module/source.css', stats)).toMatchSnapshot(
81+
'module'
82+
);
83+
expect(getExecutedCode('main.bundle.js', compiler, stats)).toMatchSnapshot(
84+
'result'
85+
);
86+
expect(getWarnings(stats)).toMatchSnapshot('warnings');
87+
expect(getErrors(stats)).toMatchSnapshot('errors');
88+
});
89+
90+
it('should work with a value equal to "false"', async () => {
91+
const compiler = getCompiler('./es-module/source.js', { esModule: false });
92+
const stats = await compile(compiler);
93+
94+
expect(getModuleSource('./es-module/source.css', stats)).toMatchSnapshot(
95+
'module'
96+
);
97+
expect(getExecutedCode('main.bundle.js', compiler, stats)).toMatchSnapshot(
98+
'result'
99+
);
100+
expect(getWarnings(stats)).toMatchSnapshot('warnings');
101+
expect(getErrors(stats)).toMatchSnapshot('errors');
102+
});
103+
});

‎test/fixtures/es-module/img.png

76.3 KB
Loading

‎test/fixtures/es-module/imported.css

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.foo {
2+
color: red;
3+
}

‎test/fixtures/es-module/source.css

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
@charset "UTF-8";
2+
3+
@import './imported.css';
4+
5+
/* Comment */
6+
7+
.class {
8+
color: red;
9+
background: url("./img.png");
10+
}

‎test/fixtures/es-module/source.js

+5
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/loader.test.js

+40-2
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,44 @@ describe('loader', () => {
154154
expect(getErrors(stats)).toMatchSnapshot('errors');
155155
});
156156

157+
it('should work with ModuleConcatenationPlugin', async () => {
158+
const compiler = getCompiler(
159+
'./basic.js',
160+
{},
161+
{
162+
mode: 'production',
163+
module: {
164+
rules: [
165+
{
166+
test: /\.css$/i,
167+
use: [
168+
{
169+
loader: path.resolve(__dirname, '../src'),
170+
options: { esModule: true },
171+
},
172+
],
173+
},
174+
{
175+
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
176+
loader: 'file-loader',
177+
options: { name: '[name].[ext]', esModule: true },
178+
},
179+
],
180+
},
181+
}
182+
);
183+
const stats = await compile(compiler);
184+
185+
if (stats.compilation.modules.size) {
186+
expect(stats.compilation.modules.size).toBe(10);
187+
} else {
188+
expect(stats.compilation.modules.length).toBe(6);
189+
}
190+
191+
expect(getWarnings(stats)).toMatchSnapshot('warnings');
192+
expect(getErrors(stats)).toMatchSnapshot('errors');
193+
});
194+
157195
it('should work with ModuleConcatenationPlugin (file-loader)', async () => {
158196
const compiler = getCompiler(
159197
'./basic.js',
@@ -169,7 +207,7 @@ describe('loader', () => {
169207
{
170208
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
171209
loader: 'file-loader',
172-
options: { name: '[name].[ext]', esModules: true },
210+
options: { name: '[name].[ext]', esModule: true },
173211
},
174212
],
175213
},
@@ -202,7 +240,7 @@ describe('loader', () => {
202240
{
203241
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
204242
loader: 'url-loader',
205-
options: { name: '[name].[ext]', limit: true, esModules: true },
243+
options: { name: '[name].[ext]', limit: true, esModule: true },
206244
},
207245
],
208246
},

‎test/onlyLocals-option.test.js

+18
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,22 @@ describe('"onlyLocals" option', () => {
2424
expect(getWarnings(stats)).toMatchSnapshot('warnings');
2525
expect(getErrors(stats)).toMatchSnapshot('errors');
2626
});
27+
28+
it('should work with the "esModule" option', async () => {
29+
const compiler = getCompiler('./modules/composes/composes.js', {
30+
modules: { mode: 'local', localIdentName: '_[local]' },
31+
onlyLocals: true,
32+
esModule: true,
33+
});
34+
const stats = await compile(compiler);
35+
36+
expect(
37+
getModuleSource('./modules/composes/composes.css', stats)
38+
).toMatchSnapshot('module');
39+
expect(getExecutedCode('main.bundle.js', compiler, stats)).toMatchSnapshot(
40+
'result'
41+
);
42+
expect(getWarnings(stats)).toMatchSnapshot('warnings');
43+
expect(getErrors(stats)).toMatchSnapshot('errors');
44+
});
2745
});

‎test/validate-options.test.js

+4
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ describe('validate options', () => {
5959
success: [true, false],
6060
failure: ['true'],
6161
},
62+
esModule: {
63+
success: [true, false],
64+
failure: ['true'],
65+
},
6266
unknown: {
6367
success: [],
6468
failure: [1, true, false, 'test', /test/, [], {}, { foo: 'bar' }],

0 commit comments

Comments
 (0)
Please sign in to comment.