Skip to content

Commit e2664e9

Browse files
authoredJul 31, 2019
feat: new injectType option
BREAKING CHANGE: the `style-loader/url` and the `style-loader/useable` were removed in favor `injectType` option (look documentation). The `singleton` option was removed (look documentation about `injectType`).
1 parent c5992e4 commit e2664e9

32 files changed

+1199
-569
lines changed
 

‎README.md

+221-49
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,42 @@ import style from './file.css';
7171
style.className === 'z849f98ca812';
7272
```
7373

74-
### `Useable`
74+
## Options
75+
76+
| Name | Type | Default | Description |
77+
| :--------------: | :------------------: | :--------: | :------------------------------------------------- |
78+
| **`injectType`** | `{String}` | `styleTag` | Allows to setup how styles will be injected in DOM |
79+
| **`attributes`** | `{Object}` | `{}` | Add custom attributes to tag |
80+
| **`insertAt`** | `{String\|Object}` | `bottom` | Inserts tag at the given position |
81+
| **`insertInto`** | `{String\|Function}` | `<head>` | Inserts tag into the given position |
82+
| **`base`** | `{Number}` | `true` | Set module ID base (DLLPlugin) |
83+
84+
### `injectType`
85+
86+
Type: `String`
87+
Default: `styleTag`
88+
89+
Allows to setup how styles will be injected in DOM.
7590

76-
The `style-loader` injects the styles lazily making them useable on-demand via `style.use()` / `style.unuse()`
91+
Possible values:
92+
93+
- `styleTag`
94+
- `singletonStyleTag`
95+
- `lazyStyleTag`
96+
- `lazySingletonStyleTag`
97+
- `linkTag`
98+
99+
When you `lazyStyleTag` or `lazySingletonStyleTag` value the `style-loader` injects the styles lazily making them useable on-demand via `style.use()` / `style.unuse()`.
100+
It is named `Reference Counter API`.
101+
102+
**component.js**
103+
104+
```js
105+
import style from './file.css';
106+
107+
style.use(); // = style.ref();
108+
style.unuse(); // = style.unref();
109+
```
77110

78111
By convention the `Reference Counter API` should be bound to `.useable.css` and the `.css` should be loaded with basic `style-loader` usage.(similar to other file types, i.e. `.useable.less` and `.less`).
79112

@@ -84,15 +117,19 @@ module.exports = {
84117
module: {
85118
rules: [
86119
{
87-
test: /\.css$/,
88-
exclude: /\.useable\.css$/,
120+
test: /\.css$/i,
121+
exclude: /\.useable\.css$/i,
89122
use: [{ loader: 'style-loader' }, { loader: 'css-loader' }],
90123
},
91124
{
92-
test: /\.useable\.css$/,
125+
test: /\.useable\.css$/i,
93126
use: [
94127
{
95-
loader: 'style-loader/useable',
128+
loader: 'style-loader',
129+
options: {
130+
// Can be `'lazyStyleTag'` or `'lazySingletonStyleTag'`
131+
injectType: 'lazyStyleTag',
132+
},
96133
},
97134
{ loader: 'css-loader' },
98135
],
@@ -102,27 +139,57 @@ module.exports = {
102139
};
103140
```
104141

105-
#### `Reference Counter API`
142+
Styles are not added on `import/require()`, but instead on call to `use`/`ref`. Styles are removed from page if `unuse`/`unref` is called exactly as often as `use`/`ref`.
106143

107-
**component.js**
144+
> ⚠️ Behavior is undefined when `unuse`/`unref` is called more often than `use`/`ref`. Don't do that.
145+
146+
#### `styleTag`
147+
148+
Injects styles in multiple `<style></style>`. It is **default** behaviour.
108149

109150
```js
110-
import style from './file.css';
151+
import './styles.css';
152+
```
111153

112-
style.use(); // = style.ref();
113-
style.unuse(); // = style.unref();
154+
**webpack.config.js**
155+
156+
```js
157+
module.exports = {
158+
module: {
159+
rules: [
160+
{
161+
test: /\.css$/i,
162+
use: [
163+
{ loader: 'style-loader', options: { injectType: 'styleTag' } },
164+
'css-loader',
165+
],
166+
},
167+
],
168+
},
169+
};
114170
```
115171

116-
Styles are not added on `import/require()`, but instead on call to `use`/`ref`. Styles are removed from page if `unuse`/`unref` is called exactly as often as `use`/`ref`.
172+
The loader inject styles like:
117173

118-
> ⚠️ Behavior is undefined when `unuse`/`unref` is called more often than `use`/`ref`. Don't do that.
174+
```html
175+
<style>
176+
.foo {
177+
color: red;
178+
}
179+
</style>
180+
<style>
181+
.bar {
182+
color: blue;
183+
}
184+
</style>
185+
```
119186

120-
### `Url`
187+
#### `singletonStyleTag`
121188

122-
It's also possible to add a URL `<link href="path/to/file.css" rel="stylesheet">` instead of inlining the CSS `{String}` with `<style></style>` tag.
189+
Injects styles in one `<style></style>`.
123190

124191
```js
125-
import url from 'file.css';
192+
import './styles.css';
126193
```
127194

128195
**webpack.config.js**
@@ -132,90 +199,159 @@ module.exports = {
132199
module: {
133200
rules: [
134201
{
135-
test: /\.css$/,
136-
use: [{ loader: 'style-loader/url' }, { loader: 'file-loader' }],
202+
test: /\.css$/i,
203+
use: [
204+
{
205+
loader: 'style-loader',
206+
options: { injectType: 'singletonStyleTag' },
207+
},
208+
'css-loader',
209+
],
137210
},
138211
],
139212
},
140213
};
141214
```
142215

216+
The loader inject styles like:
217+
143218
```html
144-
<link rel="stylesheet" href="path/to/file.css" />
219+
<style>
220+
.foo {
221+
color: red;
222+
}
223+
.bar {
224+
color: blue;
225+
}
226+
</style>
145227
```
146228

147-
## Options
229+
#### `lazyStyleTag`
148230

149-
| Name | Type | Default | Description |
150-
| :--------------: | :------------------: | :---------: | :------------------------------------------------------------------------------------------------------------------ |
151-
| **`base`** | `{Number}` | `true` | Set module ID base (DLLPlugin) |
152-
| **`attributes`** | `{Object}` | `{}` | Add custom attributes to `<style></style>` |
153-
| **`insertAt`** | `{String\|Object}` | `bottom` | Inserts `<style></style>` at the given position |
154-
| **`insertInto`** | `{String\|Function}` | `<head>` | Inserts `<style></style>` into the given position |
155-
| **`singleton`** | `{Boolean}` | `undefined` | Reuses a single `<style></style>` element, instead of adding/removing individual elements for each required module. |
231+
Injects styles in multiple `<style></style>` on demand (documentation above).
156232

157-
### `base`
233+
```js
234+
import styles from './styles.css';
158235

159-
This setting is primarily used as a workaround for [css clashes](https://github.com/webpack-contrib/style-loader/issues/163) when using one or more [DllPlugin](https://robertknight.github.io/posts/webpack-dll-plugins/)'s. `base` allows you to prevent either the _app_'s css (or _DllPlugin2_'s css) from overwriting _DllPlugin1_'s css by specifying a css module id base which is greater than the range used by _DllPlugin1_ e.g.:
236+
styles.use();
237+
```
160238

161-
**webpack.dll1.config.js**
239+
**webpack.config.js**
162240

163241
```js
164242
module.exports = {
165243
module: {
166244
rules: [
167245
{
168-
test: /\.css$/i,
246+
test: /\.useable\.css$/i,
169247
use: [
170-
{
171-
loader: 'style-loader',
172-
},
173-
{ loader: 'css-loader' },
248+
{ loader: 'style-loader', options: { injectType: 'lazyStyleTag' } },
249+
'css-loader',
174250
],
175251
},
176252
],
177253
},
178254
};
179255
```
180256

181-
**webpack.dll2.config.js**
257+
The loader inject styles like:
258+
259+
```html
260+
<style>
261+
.foo {
262+
color: red;
263+
}
264+
</style>
265+
<style>
266+
.bar {
267+
color: blue;
268+
}
269+
</style>
270+
```
271+
272+
#### `lazySingletonStyleTag`
273+
274+
Injects styles in one `<style></style>` on demand (documentation above).
275+
276+
```js
277+
import styles from './styles.css';
278+
279+
styles.use();
280+
```
281+
282+
**webpack.config.js**
182283

183284
```js
184285
module.exports = {
185286
module: {
186287
rules: [
187288
{
188-
test: /\.css$/,
289+
test: /\.useable\.css$/i,
189290
use: [
190-
{ loader: 'style-loader', options: { base: 1000 } },
191-
{ loader: 'css-loader' },
291+
{
292+
loader: 'style-loader',
293+
options: { injectType: 'lazySingletonStyleTag' },
294+
},
295+
'css-loader',
192296
],
193297
},
194298
],
195299
},
196300
};
197301
```
198302

199-
**webpack.app.config.js**
303+
The loader generate this:
304+
305+
```html
306+
<style>
307+
.foo {
308+
color: red;
309+
}
310+
.bar {
311+
color: blue;
312+
}
313+
</style>
314+
```
315+
316+
#### `linkTag`
317+
318+
Injects styles in multiple `<link rel="stylesheet" href="path/to/file.css">` .
319+
320+
```js
321+
import './styles.css';
322+
import './other-styles.css';
323+
```
324+
325+
**webpack.config.js**
200326

201327
```js
202328
module.exports = {
203329
module: {
204330
rules: [
205331
{
206-
test: /\.css$/,
332+
test: /\.css$/i,
207333
use: [
208-
{ loader: 'style-loader', options: { base: 2000 } },
209-
{ loader: 'css-loader' },
334+
{ loader: 'style-loader', options: { injectType: 'linkTag' } },
335+
{ loader: 'file-loader' },
210336
],
211337
},
212338
],
213339
},
214340
};
215341
```
216342

343+
The loader generate this:
344+
345+
```html
346+
<link rel="stylesheet" href="path/to/style.css" />
347+
<link rel="stylesheet" href="path/to/other-styles.css" />
348+
```
349+
217350
### `attributes`
218351

352+
Type: `Object`
353+
Default: `{}`
354+
219355
If defined, style-loader will attach given attributes with their values on `<style>` / `<link>` element.
220356

221357
**component.js**
@@ -231,7 +367,7 @@ module.exports = {
231367
module: {
232368
rules: [
233369
{
234-
test: /\.css$/,
370+
test: /\.css$/i,
235371
use: [
236372
{ loader: 'style-loader', options: { attributes: { id: 'id' } } },
237373
{ loader: 'css-loader' },
@@ -354,13 +490,49 @@ module.exports = {
354490
};
355491
```
356492

357-
### `singleton`
493+
### `base`
358494

359-
If defined, the style-loader will reuse a single `<style></style>` element, instead of adding/removing individual elements for each required module.
495+
This setting is primarily used as a workaround for [css clashes](https://github.com/webpack-contrib/style-loader/issues/163) when using one or more [DllPlugin](https://robertknight.github.io/posts/webpack-dll-plugins/)'s. `base` allows you to prevent either the _app_'s css (or _DllPlugin2_'s css) from overwriting _DllPlugin1_'s css by specifying a css module id base which is greater than the range used by _DllPlugin1_ e.g.:
360496

361-
> ℹ️ This option is on by default in IE9, which has strict limitations on the number of style tags allowed on a page. You can enable or disable it with the singleton option.
497+
**webpack.dll1.config.js**
362498

363-
**webpack.config.js**
499+
```js
500+
module.exports = {
501+
module: {
502+
rules: [
503+
{
504+
test: /\.css$/i,
505+
use: [
506+
{
507+
loader: 'style-loader',
508+
},
509+
{ loader: 'css-loader' },
510+
],
511+
},
512+
],
513+
},
514+
};
515+
```
516+
517+
**webpack.dll2.config.js**
518+
519+
```js
520+
module.exports = {
521+
module: {
522+
rules: [
523+
{
524+
test: /\.css$/i,
525+
use: [
526+
{ loader: 'style-loader', options: { base: 1000 } },
527+
{ loader: 'css-loader' },
528+
],
529+
},
530+
],
531+
},
532+
};
533+
```
534+
535+
**webpack.app.config.js**
364536

365537
```js
366538
module.exports = {
@@ -369,7 +541,7 @@ module.exports = {
369541
{
370542
test: /\.css$/i,
371543
use: [
372-
{ loader: 'style-loader', options: { singleton: true } },
544+
{ loader: 'style-loader', options: { base: 2000 } },
373545
{ loader: 'css-loader' },
374546
],
375547
},

‎package.json

+1-3
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,7 @@
3434
"defaults": "webpack-defaults"
3535
},
3636
"files": [
37-
"dist",
38-
"url.js",
39-
"useable.js"
37+
"dist"
4038
],
4139
"peerDependencies": {
4240
"webpack": "^4.0.0"

‎src/index.js

+112-9
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,105 @@ module.exports.pitch = function loader(request) {
3030
insertInto = `"${options.insertInto}"`;
3131
}
3232

33-
const hmrCode = `
33+
const injectType = options.injectType || 'styleTag';
34+
35+
switch (injectType) {
36+
case 'linkTag': {
37+
const hmrCode = this.hot
38+
? `
39+
if (module.hot) {
40+
module.hot.accept(
41+
${loaderUtils.stringifyRequest(this, `!!${request}`)},
42+
function() {
43+
update(require(${loaderUtils.stringifyRequest(this, `!!${request}`)}));
44+
}
45+
);
46+
47+
module.hot.dispose(function() {
48+
update();
49+
});
50+
}`
51+
: '';
52+
53+
return `var update = require(${loaderUtils.stringifyRequest(
54+
this,
55+
`!${path.join(__dirname, 'runtime/addStyleUrl.js')}`
56+
)})(require(${loaderUtils.stringifyRequest(
57+
this,
58+
`!!${request}`
59+
)}), ${JSON.stringify(options)});
60+
${hmrCode}`;
61+
}
62+
63+
case 'lazyStyleTag':
64+
case 'lazySingletonStyleTag': {
65+
const isSingleton = injectType === 'lazySingletonStyleTag';
66+
67+
const hmrCode = this.hot
68+
? `
69+
if (module.hot) {
70+
var lastRefs = module.hot.data && module.hot.data.refs || 0;
71+
72+
if (lastRefs) {
73+
exports.ref();
74+
if (!content.locals) {
75+
refs = lastRefs;
76+
}
77+
}
78+
79+
if (!content.locals) {
80+
module.hot.accept();
81+
}
82+
83+
module.hot.dispose(function(data) {
84+
data.refs = content.locals ? 0 : refs;
85+
86+
if (dispose) {
87+
dispose();
88+
}
89+
});
90+
}`
91+
: '';
92+
93+
return `var refs = 0;
94+
var dispose;
95+
var content = require(${loaderUtils.stringifyRequest(this, `!!${request}`)});
96+
var options = ${JSON.stringify(options)};
97+
98+
options.insertInto = ${insertInto};
99+
options.singleton = ${isSingleton};
100+
101+
if (typeof content === 'string') content = [[module.id, content, '']];
102+
if (content.locals) exports.locals = content.locals;
103+
104+
exports.use = exports.ref = function() {
105+
if (!(refs++)) {
106+
dispose = require(${loaderUtils.stringifyRequest(
107+
this,
108+
`!${path.join(__dirname, 'runtime/addStyles.js')}`
109+
)})(content, options);
110+
}
111+
112+
return exports;
113+
};
114+
115+
exports.unuse = exports.unref = function() {
116+
if (refs > 0 && !--refs) {
117+
dispose();
118+
dispose = null;
119+
}
120+
};
121+
${hmrCode}
122+
`;
123+
}
124+
125+
case 'styleTag':
126+
case 'singletonStyleTag':
127+
default: {
128+
const isSingleton = injectType === 'singletonStyleTag';
129+
130+
const hmrCode = this.hot
131+
? `
34132
if (module.hot) {
35133
module.hot.accept(
36134
${loaderUtils.stringifyRequest(this, `!!${request}`)},
@@ -67,10 +165,13 @@ if (module.hot) {
67165
module.hot.dispose(function() {
68166
update();
69167
});
70-
}`;
168+
}`
169+
: '';
71170

72-
return `
73-
var content = require(${loaderUtils.stringifyRequest(this, `!!${request}`)});
171+
return `var content = require(${loaderUtils.stringifyRequest(
172+
this,
173+
`!!${request}`
174+
)});
74175
75176
if (typeof content === 'string') content = [[module.id, content, '']];
76177
@@ -79,13 +180,15 @@ var insertInto;
79180
var options = ${JSON.stringify(options)}
80181
81182
options.insertInto = ${insertInto};
183+
options.singleton = ${isSingleton};
82184
83185
var update = require(${loaderUtils.stringifyRequest(
84-
this,
85-
`!${path.join(__dirname, 'runtime/addStyles.js')}`
86-
)})(content, options);
186+
this,
187+
`!${path.join(__dirname, 'runtime/addStyles.js')}`
188+
)})(content, options);
87189
88190
if (content.locals) module.exports = content.locals;
89-
${this.hot ? hmrCode : ''}
90-
`;
191+
${hmrCode}`;
192+
}
193+
}
91194
};

‎src/options.json

+10-4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@
55
"description": "Set module ID base for DLLPlugin (https://github.com/webpack-contrib/style-loader#base).",
66
"type": "number"
77
},
8+
"injectType": {
9+
"description": "Allows to setup how styles will be injected in DOM.",
10+
"enum": [
11+
"styleTag",
12+
"singletonStyleTag",
13+
"lazyStyleTag",
14+
"lazySingletonStyleTag",
15+
"linkTag"
16+
]
17+
},
818
"attributes": {
919
"description": "Add custom attributes to tag (https://github.com/webpack-contrib/style-loader#attributes).",
1020
"type": "object"
@@ -16,10 +26,6 @@
1626
"insertInto": {
1727
"description": "Inserts <style></style> into the given position (https://github.com/webpack-contrib/style-loader#insertinto).",
1828
"anyOf": [{ "type": "string" }, { "instanceof": "Function" }]
19-
},
20-
"singleton": {
21-
"description": "Reuses a single <style></style> element, instead of adding/removing individual elements for each required module (https://github.com/webpack-contrib/style-loader#singleton).",
22-
"type": "boolean"
2329
}
2430
},
2531
"additionalProperties": false

‎src/runtime/addStyleUrl.js

+9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ module.exports = function addStyleUrl(url, options) {
1515
options.attributes =
1616
typeof options.attributes === 'object' ? options.attributes : {};
1717

18+
if (options.attributes.nonce === undefined) {
19+
var nonce =
20+
typeof __webpack_nonce__ !== 'undefined' ? __webpack_nonce__ : null;
21+
22+
if (nonce) {
23+
options.attributes.nonce = nonce;
24+
}
25+
}
26+
1827
const link = document.createElement('link');
1928

2029
link.rel = 'stylesheet';

‎src/url-loader.js

-40
This file was deleted.

‎src/useable-loader.js

-87
This file was deleted.

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

+187-31
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,58 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`attributes option should add attributes to tag ("injectType" option is "linkTag"): DOM 1`] = `
3+
exports[`attributes option should add attributes to tag when the "injectType" option is "lazySingletonStyleTag": DOM 1`] = `
44
"<!DOCTYPE html><html><head>
55
<title>style-loader test</title>
66
<style id=\\"existing-style\\">.existing { color: yellow }</style>
7-
<link rel=\\"stylesheet\\" href=\\"ceb98dd1e5ab94be0d4081cb8b89f79d.css\\" id=\\"style-tag-id\\"></head>
7+
<style type=\\"text/css\\" foo=\\"bar\\" data-id=\\"style-tag-id\\">body {
8+
color: red;
9+
}
10+
h1 {
11+
color: blue;
12+
}
13+
</style></head>
14+
<body>
15+
<h1>Body</h1>
16+
<div class=\\"target\\"></div>
17+
<iframe class=\\"iframeTarget\\"></iframe>
18+
19+
20+
</body></html>"
21+
`;
22+
23+
exports[`attributes option should add attributes to tag when the "injectType" option is "lazySingletonStyleTag": errors 1`] = `Array []`;
24+
25+
exports[`attributes option should add attributes to tag when the "injectType" option is "lazySingletonStyleTag": warnings 1`] = `Array []`;
26+
27+
exports[`attributes option should add attributes to tag when the "injectType" option is "lazyStyleTag": DOM 1`] = `
28+
"<!DOCTYPE html><html><head>
29+
<title>style-loader test</title>
30+
<style id=\\"existing-style\\">.existing { color: yellow }</style>
31+
<style type=\\"text/css\\" foo=\\"bar\\" data-id=\\"style-tag-id\\">body {
32+
color: red;
33+
}
34+
</style><style type=\\"text/css\\" foo=\\"bar\\" data-id=\\"style-tag-id\\">h1 {
35+
color: blue;
36+
}
37+
</style></head>
38+
<body>
39+
<h1>Body</h1>
40+
<div class=\\"target\\"></div>
41+
<iframe class=\\"iframeTarget\\"></iframe>
42+
43+
44+
</body></html>"
45+
`;
46+
47+
exports[`attributes option should add attributes to tag when the "injectType" option is "lazyStyleTag": errors 1`] = `Array []`;
48+
49+
exports[`attributes option should add attributes to tag when the "injectType" option is "lazyStyleTag": warnings 1`] = `Array []`;
50+
51+
exports[`attributes option should add attributes to tag when the "injectType" option is "linkTag": DOM 1`] = `
52+
"<!DOCTYPE html><html><head>
53+
<title>style-loader test</title>
54+
<style id=\\"existing-style\\">.existing { color: yellow }</style>
55+
<link rel=\\"stylesheet\\" href=\\"a4197ed8dcb93d681801318bd25a41ed.css\\" type=\\"text/css\\" foo=\\"bar\\" data-id=\\"style-tag-id\\"><link rel=\\"stylesheet\\" href=\\"b37e8500d4037735f116e83ab5fd79a3.css\\" type=\\"text/css\\" foo=\\"bar\\" data-id=\\"style-tag-id\\"></head>
856
<body>
957
<h1>Body</h1>
1058
<div class=\\"target\\"></div>
@@ -14,17 +62,20 @@ exports[`attributes option should add attributes to tag ("injectType" option is
1462
</body></html>"
1563
`;
1664
17-
exports[`attributes option should add attributes to tag ("injectType" option is "linkTag"): errors 1`] = `Array []`;
65+
exports[`attributes option should add attributes to tag when the "injectType" option is "linkTag": errors 1`] = `Array []`;
1866
19-
exports[`attributes option should add attributes to tag ("injectType" option is "linkTag"): warnings 1`] = `Array []`;
67+
exports[`attributes option should add attributes to tag when the "injectType" option is "linkTag": warnings 1`] = `Array []`;
2068
21-
exports[`attributes option should add attributes to tag ("injectType" option is "styleTag"): DOM 1`] = `
69+
exports[`attributes option should add attributes to tag when the "injectType" option is "singletonStyleTag": DOM 1`] = `
2270
"<!DOCTYPE html><html><head>
2371
<title>style-loader test</title>
2472
<style id=\\"existing-style\\">.existing { color: yellow }</style>
25-
<style id=\\"style-tag-id\\">body {
73+
<style type=\\"text/css\\" foo=\\"bar\\" data-id=\\"style-tag-id\\">body {
2674
color: red;
2775
}
76+
h1 {
77+
color: blue;
78+
}
2879
</style></head>
2980
<body>
3081
<h1>Body</h1>
@@ -35,15 +86,18 @@ exports[`attributes option should add attributes to tag ("injectType" option is
3586
</body></html>"
3687
`;
3788
38-
exports[`attributes option should add attributes to tag ("injectType" option is "styleTag"): errors 1`] = `Array []`;
89+
exports[`attributes option should add attributes to tag when the "injectType" option is "singletonStyleTag": errors 1`] = `Array []`;
3990
40-
exports[`attributes option should add attributes to tag ("injectType" option is "styleTag"): warnings 1`] = `Array []`;
91+
exports[`attributes option should add attributes to tag when the "injectType" option is "singletonStyleTag": warnings 1`] = `Array []`;
4192
42-
exports[`attributes option should add attributes to tag ("injectType" option is "useableStyleTag"): DOM 1`] = `
93+
exports[`attributes option should add attributes to tag when the "injectType" option is "styleTag": DOM 1`] = `
4394
"<!DOCTYPE html><html><head>
4495
<title>style-loader test</title>
4596
<style id=\\"existing-style\\">.existing { color: yellow }</style>
46-
<style id=\\"style-tag-id\\">h1 {
97+
<style type=\\"text/css\\" foo=\\"bar\\" data-id=\\"style-tag-id\\">body {
98+
color: red;
99+
}
100+
</style><style type=\\"text/css\\" foo=\\"bar\\" data-id=\\"style-tag-id\\">h1 {
47101
color: blue;
48102
}
49103
</style></head>
@@ -56,11 +110,11 @@ exports[`attributes option should add attributes to tag ("injectType" option is
56110
</body></html>"
57111
`;
58112
59-
exports[`attributes option should add attributes to tag ("injectType" option is "useableStyleTag"): errors 1`] = `Array []`;
113+
exports[`attributes option should add attributes to tag when the "injectType" option is "styleTag": errors 1`] = `Array []`;
60114
61-
exports[`attributes option should add attributes to tag ("injectType" option is "useableStyleTag"): warnings 1`] = `Array []`;
115+
exports[`attributes option should add attributes to tag when the "injectType" option is "styleTag": warnings 1`] = `Array []`;
62116
63-
exports[`attributes option should add nonce attribute #2: DOM 1`] = `
117+
exports[`attributes option should add nonce attribute when "injectType" option is "lazySingletonStyleTag" #2: DOM 1`] = `
64118
"<!DOCTYPE html><html><head>
65119
<title>style-loader test</title>
66120
<style id=\\"existing-style\\">.existing { color: yellow }</style>
@@ -77,11 +131,11 @@ exports[`attributes option should add nonce attribute #2: DOM 1`] = `
77131
</body></html>"
78132
`;
79133
80-
exports[`attributes option should add nonce attribute #2: errors 1`] = `Array []`;
134+
exports[`attributes option should add nonce attribute when "injectType" option is "lazySingletonStyleTag" #2: errors 1`] = `Array []`;
81135
82-
exports[`attributes option should add nonce attribute #2: warnings 1`] = `Array []`;
136+
exports[`attributes option should add nonce attribute when "injectType" option is "lazySingletonStyleTag" #2: warnings 1`] = `Array []`;
83137
84-
exports[`attributes option should add nonce attribute: DOM 1`] = `
138+
exports[`attributes option should add nonce attribute when "injectType" option is "lazySingletonStyleTag": DOM 1`] = `
85139
"<!DOCTYPE html><html><head>
86140
<title>style-loader test</title>
87141
<style id=\\"existing-style\\">.existing { color: yellow }</style>
@@ -98,15 +152,18 @@ exports[`attributes option should add nonce attribute: DOM 1`] = `
98152
</body></html>"
99153
`;
100154
101-
exports[`attributes option should add nonce attribute: errors 1`] = `Array []`;
155+
exports[`attributes option should add nonce attribute when "injectType" option is "lazySingletonStyleTag": errors 1`] = `Array []`;
102156
103-
exports[`attributes option should add nonce attribute: warnings 1`] = `Array []`;
157+
exports[`attributes option should add nonce attribute when "injectType" option is "lazySingletonStyleTag": warnings 1`] = `Array []`;
104158
105-
exports[`attributes option should override/add default type attribute to tag ("injectType" option is "linkTag"): DOM 1`] = `
159+
exports[`attributes option should add nonce attribute when "injectType" option is "lazyStyleTag" #2: DOM 1`] = `
106160
"<!DOCTYPE html><html><head>
107161
<title>style-loader test</title>
108162
<style id=\\"existing-style\\">.existing { color: yellow }</style>
109-
<link rel=\\"stylesheet\\" href=\\"ceb98dd1e5ab94be0d4081cb8b89f79d.css\\" type=\\"text/less\\"></head>
163+
<style nonce=\\"12345678\\">body {
164+
color: red;
165+
}
166+
</style></head>
110167
<body>
111168
<h1>Body</h1>
112169
<div class=\\"target\\"></div>
@@ -116,15 +173,15 @@ exports[`attributes option should override/add default type attribute to tag ("i
116173
</body></html>"
117174
`;
118175
119-
exports[`attributes option should override/add default type attribute to tag ("injectType" option is "linkTag"): errors 1`] = `Array []`;
176+
exports[`attributes option should add nonce attribute when "injectType" option is "lazyStyleTag" #2: errors 1`] = `Array []`;
120177
121-
exports[`attributes option should override/add default type attribute to tag ("injectType" option is "linkTag"): warnings 1`] = `Array []`;
178+
exports[`attributes option should add nonce attribute when "injectType" option is "lazyStyleTag" #2: warnings 1`] = `Array []`;
122179
123-
exports[`attributes option should override/add default type attribute to tag ("injectType" option is "styleTag"): DOM 1`] = `
180+
exports[`attributes option should add nonce attribute when "injectType" option is "lazyStyleTag": DOM 1`] = `
124181
"<!DOCTYPE html><html><head>
125182
<title>style-loader test</title>
126183
<style id=\\"existing-style\\">.existing { color: yellow }</style>
127-
<style type=\\"text/less\\">body {
184+
<style nonce=\\"12345678\\">body {
128185
color: red;
129186
}
130187
</style></head>
@@ -137,16 +194,115 @@ exports[`attributes option should override/add default type attribute to tag ("i
137194
</body></html>"
138195
`;
139196
140-
exports[`attributes option should override/add default type attribute to tag ("injectType" option is "styleTag"): errors 1`] = `Array []`;
197+
exports[`attributes option should add nonce attribute when "injectType" option is "lazyStyleTag": errors 1`] = `Array []`;
141198
142-
exports[`attributes option should override/add default type attribute to tag ("injectType" option is "styleTag"): warnings 1`] = `Array []`;
199+
exports[`attributes option should add nonce attribute when "injectType" option is "lazyStyleTag": warnings 1`] = `Array []`;
143200
144-
exports[`attributes option should override/add default type attribute to tag ("injectType" option is "useableStyleTag"): DOM 1`] = `
201+
exports[`attributes option should add nonce attribute when "injectType" option is "linkTag" #2: DOM 1`] = `
145202
"<!DOCTYPE html><html><head>
146203
<title>style-loader test</title>
147204
<style id=\\"existing-style\\">.existing { color: yellow }</style>
148-
<style type=\\"text/less\\">h1 {
149-
color: blue;
205+
<link rel=\\"stylesheet\\" href=\\"a4197ed8dcb93d681801318bd25a41ed.css\\" nonce=\\"12345678\\"></head>
206+
<body>
207+
<h1>Body</h1>
208+
<div class=\\"target\\"></div>
209+
<iframe class=\\"iframeTarget\\"></iframe>
210+
211+
212+
</body></html>"
213+
`;
214+
215+
exports[`attributes option should add nonce attribute when "injectType" option is "linkTag" #2: errors 1`] = `Array []`;
216+
217+
exports[`attributes option should add nonce attribute when "injectType" option is "linkTag" #2: warnings 1`] = `Array []`;
218+
219+
exports[`attributes option should add nonce attribute when "injectType" option is "linkTag": DOM 1`] = `
220+
"<!DOCTYPE html><html><head>
221+
<title>style-loader test</title>
222+
<style id=\\"existing-style\\">.existing { color: yellow }</style>
223+
<link rel=\\"stylesheet\\" href=\\"a4197ed8dcb93d681801318bd25a41ed.css\\" nonce=\\"12345678\\"></head>
224+
<body>
225+
<h1>Body</h1>
226+
<div class=\\"target\\"></div>
227+
<iframe class=\\"iframeTarget\\"></iframe>
228+
229+
230+
</body></html>"
231+
`;
232+
233+
exports[`attributes option should add nonce attribute when "injectType" option is "linkTag": errors 1`] = `Array []`;
234+
235+
exports[`attributes option should add nonce attribute when "injectType" option is "linkTag": warnings 1`] = `Array []`;
236+
237+
exports[`attributes option should add nonce attribute when "injectType" option is "singletonStyleTag" #2: DOM 1`] = `
238+
"<!DOCTYPE html><html><head>
239+
<title>style-loader test</title>
240+
<style id=\\"existing-style\\">.existing { color: yellow }</style>
241+
<style nonce=\\"12345678\\">body {
242+
color: red;
243+
}
244+
</style></head>
245+
<body>
246+
<h1>Body</h1>
247+
<div class=\\"target\\"></div>
248+
<iframe class=\\"iframeTarget\\"></iframe>
249+
250+
251+
</body></html>"
252+
`;
253+
254+
exports[`attributes option should add nonce attribute when "injectType" option is "singletonStyleTag" #2: errors 1`] = `Array []`;
255+
256+
exports[`attributes option should add nonce attribute when "injectType" option is "singletonStyleTag" #2: warnings 1`] = `Array []`;
257+
258+
exports[`attributes option should add nonce attribute when "injectType" option is "singletonStyleTag": DOM 1`] = `
259+
"<!DOCTYPE html><html><head>
260+
<title>style-loader test</title>
261+
<style id=\\"existing-style\\">.existing { color: yellow }</style>
262+
<style nonce=\\"12345678\\">body {
263+
color: red;
264+
}
265+
</style></head>
266+
<body>
267+
<h1>Body</h1>
268+
<div class=\\"target\\"></div>
269+
<iframe class=\\"iframeTarget\\"></iframe>
270+
271+
272+
</body></html>"
273+
`;
274+
275+
exports[`attributes option should add nonce attribute when "injectType" option is "singletonStyleTag": errors 1`] = `Array []`;
276+
277+
exports[`attributes option should add nonce attribute when "injectType" option is "singletonStyleTag": warnings 1`] = `Array []`;
278+
279+
exports[`attributes option should add nonce attribute when "injectType" option is "styleTag" #2: DOM 1`] = `
280+
"<!DOCTYPE html><html><head>
281+
<title>style-loader test</title>
282+
<style id=\\"existing-style\\">.existing { color: yellow }</style>
283+
<style nonce=\\"12345678\\">body {
284+
color: red;
285+
}
286+
</style></head>
287+
<body>
288+
<h1>Body</h1>
289+
<div class=\\"target\\"></div>
290+
<iframe class=\\"iframeTarget\\"></iframe>
291+
292+
293+
</body></html>"
294+
`;
295+
296+
exports[`attributes option should add nonce attribute when "injectType" option is "styleTag" #2: errors 1`] = `Array []`;
297+
298+
exports[`attributes option should add nonce attribute when "injectType" option is "styleTag" #2: warnings 1`] = `Array []`;
299+
300+
exports[`attributes option should add nonce attribute when "injectType" option is "styleTag": DOM 1`] = `
301+
"<!DOCTYPE html><html><head>
302+
<title>style-loader test</title>
303+
<style id=\\"existing-style\\">.existing { color: yellow }</style>
304+
<style nonce=\\"12345678\\">body {
305+
color: red;
150306
}
151307
</style></head>
152308
<body>
@@ -158,6 +314,6 @@ exports[`attributes option should override/add default type attribute to tag ("i
158314
</body></html>"
159315
`;
160316
161-
exports[`attributes option should override/add default type attribute to tag ("injectType" option is "useableStyleTag"): errors 1`] = `Array []`;
317+
exports[`attributes option should add nonce attribute when "injectType" option is "styleTag": errors 1`] = `Array []`;
162318
163-
exports[`attributes option should override/add default type attribute to tag ("injectType" option is "useableStyleTag"): warnings 1`] = `Array []`;
319+
exports[`attributes option should add nonce attribute when "injectType" option is "styleTag": warnings 1`] = `Array []`;

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

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ exports[`base option should work: DOM 1`] = `
77
<style>body {
88
color: red;
99
}
10+
</style><style>h1 {
11+
color: blue;
12+
}
1013
</style></head>
1114
<body>
1215
<h1>Body</h1>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`injectType option should work when the "injectType" option is "lazySingletonStyleTag": DOM 1`] = `
4+
"<!DOCTYPE html><html><head>
5+
<title>style-loader test</title>
6+
<style id=\\"existing-style\\">.existing { color: yellow }</style>
7+
<style>body {
8+
color: red;
9+
}
10+
h1 {
11+
color: blue;
12+
}
13+
</style></head>
14+
<body>
15+
<h1>Body</h1>
16+
<div class=\\"target\\"></div>
17+
<iframe class=\\"iframeTarget\\"></iframe>
18+
19+
20+
</body></html>"
21+
`;
22+
23+
exports[`injectType option should work when the "injectType" option is "lazySingletonStyleTag": errors 1`] = `Array []`;
24+
25+
exports[`injectType option should work when the "injectType" option is "lazySingletonStyleTag": warnings 1`] = `Array []`;
26+
27+
exports[`injectType option should work when the "injectType" option is "lazyStyleTag": DOM 1`] = `
28+
"<!DOCTYPE html><html><head>
29+
<title>style-loader test</title>
30+
<style id=\\"existing-style\\">.existing { color: yellow }</style>
31+
<style>body {
32+
color: red;
33+
}
34+
</style><style>h1 {
35+
color: blue;
36+
}
37+
</style></head>
38+
<body>
39+
<h1>Body</h1>
40+
<div class=\\"target\\"></div>
41+
<iframe class=\\"iframeTarget\\"></iframe>
42+
43+
44+
</body></html>"
45+
`;
46+
47+
exports[`injectType option should work when the "injectType" option is "lazyStyleTag": errors 1`] = `Array []`;
48+
49+
exports[`injectType option should work when the "injectType" option is "lazyStyleTag": warnings 1`] = `Array []`;
50+
51+
exports[`injectType option should work when the "injectType" option is "linkTag": DOM 1`] = `
52+
"<!DOCTYPE html><html><head>
53+
<title>style-loader test</title>
54+
<style id=\\"existing-style\\">.existing { color: yellow }</style>
55+
<link rel=\\"stylesheet\\" href=\\"a4197ed8dcb93d681801318bd25a41ed.css\\"><link rel=\\"stylesheet\\" href=\\"b37e8500d4037735f116e83ab5fd79a3.css\\"></head>
56+
<body>
57+
<h1>Body</h1>
58+
<div class=\\"target\\"></div>
59+
<iframe class=\\"iframeTarget\\"></iframe>
60+
61+
62+
</body></html>"
63+
`;
64+
65+
exports[`injectType option should work when the "injectType" option is "linkTag": errors 1`] = `Array []`;
66+
67+
exports[`injectType option should work when the "injectType" option is "linkTag": warnings 1`] = `Array []`;
68+
69+
exports[`injectType option should work when the "injectType" option is "singletonStyleTag": DOM 1`] = `
70+
"<!DOCTYPE html><html><head>
71+
<title>style-loader test</title>
72+
<style id=\\"existing-style\\">.existing { color: yellow }</style>
73+
<style>body {
74+
color: red;
75+
}
76+
h1 {
77+
color: blue;
78+
}
79+
</style></head>
80+
<body>
81+
<h1>Body</h1>
82+
<div class=\\"target\\"></div>
83+
<iframe class=\\"iframeTarget\\"></iframe>
84+
85+
86+
</body></html>"
87+
`;
88+
89+
exports[`injectType option should work when the "injectType" option is "singletonStyleTag": errors 1`] = `Array []`;
90+
91+
exports[`injectType option should work when the "injectType" option is "singletonStyleTag": warnings 1`] = `Array []`;
92+
93+
exports[`injectType option should work when the "injectType" option is "styleTag": DOM 1`] = `
94+
"<!DOCTYPE html><html><head>
95+
<title>style-loader test</title>
96+
<style id=\\"existing-style\\">.existing { color: yellow }</style>
97+
<style>body {
98+
color: red;
99+
}
100+
</style><style>h1 {
101+
color: blue;
102+
}
103+
</style></head>
104+
<body>
105+
<h1>Body</h1>
106+
<div class=\\"target\\"></div>
107+
<iframe class=\\"iframeTarget\\"></iframe>
108+
109+
110+
</body></html>"
111+
`;
112+
113+
exports[`injectType option should work when the "injectType" option is "styleTag": errors 1`] = `Array []`;
114+
115+
exports[`injectType option should work when the "injectType" option is "styleTag": warnings 1`] = `Array []`;

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

+21
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ exports[`insert option should insert styles before "#existing-style" id: DOM 1`]
66
<style>body {
77
color: red;
88
}
9+
</style><style>h1 {
10+
color: blue;
11+
}
912
</style><style id=\\"existing-style\\">.existing { color: yellow }</style>
1013
</head>
1114
<body>
@@ -49,6 +52,9 @@ exports[`insert option should insert styles in bottom when not specified: DOM 1`
4952
<style>body {
5053
color: red;
5154
}
55+
</style><style>h1 {
56+
color: blue;
57+
}
5258
</style></head>
5359
<body>
5460
<h1>Body</h1>
@@ -70,6 +76,9 @@ exports[`insert option should insert styles in bottom when selector was not foun
7076
<style>body {
7177
color: red;
7278
}
79+
</style><style>h1 {
80+
color: blue;
81+
}
7382
</style></head>
7483
<body>
7584
<h1>Body</h1>
@@ -91,6 +100,9 @@ exports[`insert option should insert styles in bottom: DOM 1`] = `
91100
<style>body {
92101
color: red;
93102
}
103+
</style><style>h1 {
104+
color: blue;
105+
}
94106
</style></head>
95107
<body>
96108
<h1>Body</h1>
@@ -130,6 +142,9 @@ exports[`insert option should insert styles in top: DOM 1`] = `
130142
"<!DOCTYPE html><html><head><style>body {
131143
color: red;
132144
}
145+
</style><style>h1 {
146+
color: blue;
147+
}
133148
</style>
134149
<title>style-loader test</title>
135150
<style id=\\"existing-style\\">.existing { color: yellow }</style>
@@ -167,6 +182,9 @@ exports[`insert option should insert styles into target when target is iframe: i
167182
"<style>body {
168183
color: red;
169184
}
185+
</style><style>h1 {
186+
color: blue;
187+
}
170188
</style>"
171189
`;
172190
@@ -182,6 +200,9 @@ exports[`insert option should insert styles into target: DOM 1`] = `
182200
<div class=\\"target\\"><style>body {
183201
color: red;
184202
}
203+
</style><style>h1 {
204+
color: blue;
205+
}
185206
</style></div>
186207
<iframe class=\\"iframeTarget\\"></iframe>
187208

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

+341-60
Large diffs are not rendered by default.

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

-73
This file was deleted.

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

+4-9
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
exports[`validate options 1`] = `
44
"Invalid options object. Style Loader has been initialised using an options object that does not match the API schema.
5-
- options.base should be a number.
6-
-> Set module ID base for DLLPlugin (https://github.com/webpack-contrib/style-loader#base)."
5+
- options.injectType should be one of these:
6+
\\"styleTag\\" | \\"singletonStyleTag\\" | \\"lazyStyleTag\\" | \\"lazySingletonStyleTag\\" | \\"linkTag\\"
7+
-> Allows to setup how styles will be injected in DOM."
78
`;
89

910
exports[`validate options 2`] = `
@@ -31,13 +32,7 @@ exports[`validate options 4`] = `
3132
`;
3233

3334
exports[`validate options 5`] = `
34-
"Invalid options object. Style Loader has been initialised using an options object that does not match the API schema.
35-
- options.singleton should be a boolean.
36-
-> Reuses a single <style></style> element, instead of adding/removing individual elements for each required module (https://github.com/webpack-contrib/style-loader#singleton)."
37-
`;
38-
39-
exports[`validate options 6`] = `
4035
"Invalid options object. Style Loader has been initialised using an options object that does not match the API schema.
4136
- options has an unknown property 'unknown'. These properties are valid:
42-
object { base?, attributes?, insertAt?, insertInto?, singleton? }"
37+
object { base?, injectType?, attributes?, insertAt?, insertInto? }"
4338
`;

‎test/attributes-option.test.js

+28-42
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,27 @@
1-
import compile from './helpers/compiler';
2-
import runTestInJsdom from './helpers/runTestInJsdom';
1+
import { compile, getTestId, runTestInJsdom } from './helpers';
32

43
describe('attributes option', () => {
5-
const injectTypes = ['styleTag', 'useableStyleTag', 'linkTag'];
4+
const injectTypes = [
5+
'styleTag',
6+
'singletonStyleTag',
7+
'lazyStyleTag',
8+
'lazySingletonStyleTag',
9+
'linkTag',
10+
];
611

712
injectTypes.forEach((injectType) => {
8-
it(`should add attributes to tag ("injectType" option is "${injectType}")`, async () => {
13+
it(`should add attributes to tag when the "injectType" option is "${injectType}"`, async () => {
914
expect.assertions(3);
1015

11-
const testId =
12-
injectType === 'useableStyleTag' ? './useable.js' : './simple.js';
16+
const testId = getTestId('simple.js', injectType);
1317
const stats = await compile(testId, {
1418
loader: {
15-
injectType,
1619
options: {
20+
injectType,
1721
attributes: {
18-
id: 'style-tag-id',
22+
type: 'text/css',
23+
foo: 'bar',
24+
'data-id': 'style-tag-id',
1925
},
2026
},
2127
},
@@ -29,20 +35,12 @@ describe('attributes option', () => {
2935
expect(stats.compilation.errors).toMatchSnapshot('errors');
3036
});
3137

32-
it(`should override/add default type attribute to tag ("injectType" option is "${injectType}")`, async () => {
38+
it(`should add nonce attribute when "injectType" option is "${injectType}"`, async () => {
3339
expect.assertions(3);
3440

35-
const testId =
36-
injectType === 'useableStyleTag' ? './useable.js' : './simple.js';
41+
const testId = getTestId('nonce-require.js', injectType);
3742
const stats = await compile(testId, {
38-
loader: {
39-
injectType,
40-
options: {
41-
attributes: {
42-
type: 'text/less',
43-
},
44-
},
45-
},
43+
loader: { options: { injectType } },
4644
});
4745

4846
runTestInJsdom(stats, (dom) => {
@@ -52,33 +50,21 @@ describe('attributes option', () => {
5250
expect(stats.compilation.warnings).toMatchSnapshot('warnings');
5351
expect(stats.compilation.errors).toMatchSnapshot('errors');
5452
});
55-
});
56-
57-
it('should add nonce attribute', async () => {
58-
expect.assertions(3);
59-
60-
const testId = './nonce-require.js';
61-
const stats = await compile(testId);
62-
63-
runTestInJsdom(stats, (dom) => {
64-
expect(dom.serialize()).toMatchSnapshot('DOM');
65-
});
6653

67-
expect(stats.compilation.warnings).toMatchSnapshot('warnings');
68-
expect(stats.compilation.errors).toMatchSnapshot('errors');
69-
});
54+
it(`should add nonce attribute when "injectType" option is "${injectType}" #2`, async () => {
55+
expect.assertions(3);
7056

71-
it('should add nonce attribute #2', async () => {
72-
expect.assertions(3);
57+
const testId = getTestId('nonce-import.js', injectType);
58+
const stats = await compile(testId, {
59+
loader: { options: { injectType } },
60+
});
7361

74-
const testId = './nonce-import.js';
75-
const stats = await compile(testId);
62+
runTestInJsdom(stats, (dom) => {
63+
expect(dom.serialize()).toMatchSnapshot('DOM');
64+
});
7665

77-
runTestInJsdom(stats, (dom) => {
78-
expect(dom.serialize()).toMatchSnapshot('DOM');
66+
expect(stats.compilation.warnings).toMatchSnapshot('warnings');
67+
expect(stats.compilation.errors).toMatchSnapshot('errors');
7968
});
80-
81-
expect(stats.compilation.warnings).toMatchSnapshot('warnings');
82-
expect(stats.compilation.errors).toMatchSnapshot('errors');
8369
});
8470
});

‎test/fixtures/lazy-nonce-import.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import './create-nonce';
2+
import styles from './style.css';
3+
4+
styles.use();
5+
6+

‎test/fixtures/lazy-nonce-require.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
__webpack_nonce__ = '12345678';
2+
3+
const styles = require('./style.css');
4+
5+
styles.use();
6+
7+

‎test/fixtures/useable.js renamed to ‎test/fixtures/lazy-simple.js

-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,3 @@ import styleOther from './style-other.css';
33

44
style.use();
55
styleOther.use();
6-
style.unuse();

‎test/fixtures/simple.js

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
import './style.css';
2+
import './style-other.css';

‎test/helpers/compiler.js

+16-32
Original file line numberDiff line numberDiff line change
@@ -8,47 +8,31 @@ import path from 'path';
88
import webpack from 'webpack';
99
import MemoryFS from 'memory-fs';
1010

11-
function getLoaderByInjectType(injectType) {
12-
// eslint-disable-next-line default-case
13-
switch (injectType) {
14-
case 'styleTag':
15-
return path.resolve(__dirname, '../../src');
16-
case 'useableStyleTag':
17-
return path.resolve(__dirname, '../../src/useable-loader.js');
18-
case 'linkTag':
19-
return path.resolve(__dirname, '../../src/url-loader.js');
20-
}
21-
22-
return path.join(__dirname, '../../src');
23-
}
24-
25-
function getUse(config) {
11+
const module = (config) => {
2612
const shouldUseFileLoader =
2713
config.loader &&
28-
config.loader.injectType &&
29-
config.loader.injectType === 'linkTag';
14+
config.loader.options &&
15+
config.loader.options.injectType === 'linkTag';
3016

31-
return [
32-
{
33-
loader: getLoaderByInjectType(config.loader && config.loader.injectType),
34-
options: (config.loader && config.loader.options) || {},
35-
},
36-
shouldUseFileLoader ? { loader: 'file-loader' } : false,
37-
{
38-
loader: 'css-loader',
39-
options: (config.cssLoader && config.cssLoader.options) || {},
40-
},
41-
].filter(Boolean);
42-
}
43-
44-
const module = (config) => {
4517
return {
4618
rules: config.rules
4719
? config.rules
4820
: [
4921
{
5022
test: (config.loader && config.loader.test) || /\.css$/i,
51-
use: getUse(config),
23+
use: [
24+
{
25+
loader: path.join(__dirname, '../../src'),
26+
options: (config.loader && config.loader.options) || {},
27+
},
28+
shouldUseFileLoader
29+
? { loader: 'file-loader' }
30+
: {
31+
loader: 'css-loader',
32+
options:
33+
(config.cssLoader && config.cssLoader.options) || {},
34+
},
35+
],
5236
},
5337
],
5438
};

‎test/helpers/getTestId.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
function getTestId(testId, injectType) {
2+
const isLazy = injectType && injectType.toLowerCase().includes('lazy');
3+
4+
return `./${isLazy ? 'lazy-' : ''}${testId}`;
5+
}
6+
7+
export default getTestId;

‎test/helpers/index.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import compile from './compiler';
2+
import getTestId from './getTestId';
3+
import runTestInJsdom from './runTestInJsdom';
4+
5+
export { compile, getTestId, runTestInJsdom };

‎test/injectType-option.test.js

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/* eslint-env browser */
2+
3+
import { compile, getTestId, runTestInJsdom } from './helpers';
4+
5+
describe('injectType option', () => {
6+
const injectTypes = [
7+
'styleTag',
8+
'singletonStyleTag',
9+
'lazyStyleTag',
10+
'lazySingletonStyleTag',
11+
'linkTag',
12+
];
13+
14+
injectTypes.forEach((injectType) => {
15+
it(`should work when the "injectType" option is "${injectType}"`, async () => {
16+
expect.assertions(3);
17+
18+
const testId = getTestId('simple.js', injectType);
19+
const stats = await compile(testId, {
20+
loader: { options: { injectType } },
21+
});
22+
23+
runTestInJsdom(stats, (dom) => {
24+
expect(dom.serialize()).toMatchSnapshot('DOM');
25+
});
26+
27+
expect(stats.compilation.warnings).toMatchSnapshot('warnings');
28+
expect(stats.compilation.errors).toMatchSnapshot('errors');
29+
});
30+
});
31+
});

‎test/insert-option.test.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
/* eslint-env browser */
2-
import compile from './helpers/compiler';
3-
import runTestInJsdom from './helpers/runTestInJsdom';
2+
import { compile, runTestInJsdom } from './helpers';
43

54
describe('insert option', () => {
65
it('should insert styles in bottom when not specified', async () => {
76
expect.assertions(3);
87

98
const testId = './simple.js';
10-
const stats = await compile(testId, {});
9+
const stats = await compile(testId);
1110

1211
runTestInJsdom(stats, (dom) => {
1312
expect(dom.serialize()).toMatchSnapshot('DOM');

‎test/loader.test.js

+58-43
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,37 @@
22

33
import webpack from 'webpack';
44

5-
import compile from './helpers/compiler';
6-
import runTestInJsdom from './helpers/runTestInJsdom';
5+
import { compile, getTestId, runTestInJsdom } from './helpers';
76

87
describe('loader', () => {
9-
const injectTypes = ['styleTag', 'useableStyleTag', 'linkTag'];
8+
const injectTypes = [
9+
'styleTag',
10+
'singletonStyleTag',
11+
'lazyStyleTag',
12+
'lazySingletonStyleTag',
13+
'linkTag',
14+
];
15+
16+
it(`should work`, async () => {
17+
const testId = './simple.js';
18+
const stats = await compile(testId);
19+
20+
runTestInJsdom(stats, (dom) => {
21+
expect(dom.serialize()).toMatchSnapshot('DOM');
22+
});
23+
24+
expect(stats.compilation.warnings).toMatchSnapshot('warnings');
25+
expect(stats.compilation.errors).toMatchSnapshot('errors');
26+
});
1027

1128
injectTypes.forEach((injectType) => {
12-
expect.assertions(3);
29+
it(`should work when the "injectType" option is "${injectType}"`, async () => {
30+
expect.assertions(3);
1331

14-
it(`should work ("injectType" option is "${injectType}")`, async () => {
15-
const testId =
16-
injectType === 'useableStyleTag' ? './useable.js' : './simple.js';
17-
const stats = await compile(testId, { loader: { injectType } });
32+
const testId = getTestId('simple.js', injectType);
33+
const stats = await compile(testId, {
34+
loader: { options: { injectType } },
35+
});
1836

1937
runTestInJsdom(stats, (dom) => {
2038
expect(dom.serialize()).toMatchSnapshot('DOM');
@@ -24,15 +42,12 @@ describe('loader', () => {
2442
expect(stats.compilation.errors).toMatchSnapshot('errors');
2543
});
2644

27-
it(`should work with css modules ("injectType" option is "${injectType}")`, async () => {
45+
it(`should work with css modules when the "injectType" option is "${injectType}"`, async () => {
2846
expect.assertions(3);
2947

30-
const testId =
31-
injectType === 'useableStyleTag'
32-
? './useable-css-modules.js'
33-
: './css-modules.js';
48+
const testId = getTestId('css-modules.js', injectType);
3449
const stats = await compile(testId, {
35-
loader: { injectType },
50+
loader: { options: { injectType } },
3651
cssLoader: {
3752
options: {
3853
modules: { localIdentName: '[name]-[local]_[hash:base64:7]' },
@@ -48,9 +63,13 @@ describe('loader', () => {
4863
expect(stats.compilation.errors).toMatchSnapshot('errors');
4964
});
5065

51-
it(`should not inject hmr code without HotModuleReplacementPlugin ("injectType" option is "${injectType}")`, async () => {
66+
it(`should not inject hmr code without HotModuleReplacementPlugin when the "injectType" option is "${injectType}"`, async () => {
67+
expect.assertions(4);
68+
5269
const testId = './hot.js';
53-
const stats = await compile(testId, { loader: { injectType } });
70+
const stats = await compile(testId, {
71+
loader: { options: { injectType } },
72+
});
5473

5574
runTestInJsdom(stats, (dom) => {
5675
expect(dom.window.hotApi).not.toBeDefined();
@@ -64,13 +83,13 @@ describe('loader', () => {
6483
expect(stats.compilation.errors).toMatchSnapshot('errors');
6584
});
6685

67-
it(`should inject hmr code with HotModuleReplacementPlugin ("injectType" option is "${injectType}")`, async () => {
86+
it(`should inject hmr code with HotModuleReplacementPlugin when the "injectType" option is "${injectType}"`, async () => {
6887
expect.assertions(4);
6988

7089
const testId = './hot.js';
7190
const stats = await compile(testId, {
7291
plugins: [new webpack.HotModuleReplacementPlugin()],
73-
loader: { injectType },
92+
loader: { options: { injectType } },
7493
});
7594

7695
runTestInJsdom(stats, (dom) => {
@@ -85,14 +104,13 @@ describe('loader', () => {
85104
expect(stats.compilation.errors).toMatchSnapshot('errors');
86105
});
87106

88-
it(`should not generate source maps when previous loader don't emit them ("injectType" option is "${injectType}")`, async () => {
107+
it(`should not generate source maps when previous loader don't emit them when the "injectType" option is "${injectType}"`, async () => {
89108
expect.assertions(3);
90109

91-
const testId =
92-
injectType === 'useableStyleTag' ? './useable.js' : './simple.js';
110+
const testId = getTestId('simple.js', injectType);
93111
const stats = await compile(testId, {
94112
devtool: 'source-map',
95-
loader: { injectType },
113+
loader: { options: { injectType } },
96114
});
97115

98116
runTestInJsdom(stats, (dom) => {
@@ -104,19 +122,14 @@ describe('loader', () => {
104122
});
105123

106124
// `linkTag` doesn't generate source maps, original source should contains them
107-
it(`should generate source maps when previous loader emit them ("injectType" option is "${injectType}")`, async () => {
125+
it(`should generate source maps when previous loader emit them when the "injectType" option is "${injectType}"`, async () => {
108126
expect.assertions(3);
109127

110-
const testId =
111-
injectType === 'useableStyleTag' ? './useable.js' : './simple.js';
128+
const testId = getTestId('simple.js', injectType);
112129
const stats = await compile(testId, {
113130
devtool: 'source-map',
114-
loader: { injectType },
115-
cssLoader: {
116-
options: {
117-
sourceMap: true,
118-
},
119-
},
131+
loader: { options: { injectType } },
132+
cssLoader: { options: { sourceMap: true } },
120133
});
121134

122135
runTestInJsdom(stats, (dom) => {
@@ -126,21 +139,23 @@ describe('loader', () => {
126139
expect(stats.compilation.warnings).toMatchSnapshot('warnings');
127140
expect(stats.compilation.errors).toMatchSnapshot('errors');
128141
});
129-
});
130142

131-
it('should work for useable inject type and negative ref', async () => {
132-
expect.assertions(3);
143+
if (['lazyStyleTag', 'lazySingletonStyleTag'].includes(injectType)) {
144+
it(`should work when ref is negative when the "injectType" option is "${injectType}")`, async () => {
145+
expect.assertions(3);
133146

134-
const testId = './useable-negative-refs.js';
135-
const stats = await compile(testId, {
136-
loader: { injectType: 'useableStyleTag' },
137-
});
147+
const testId = './lazy-negative-refs.js';
148+
const stats = await compile(testId, {
149+
loader: { options: { injectType } },
150+
});
138151

139-
runTestInJsdom(stats, (dom) => {
140-
expect(dom.serialize()).toMatchSnapshot('DOM');
141-
});
152+
runTestInJsdom(stats, (dom) => {
153+
expect(dom.serialize()).toMatchSnapshot('DOM');
154+
});
142155

143-
expect(stats.compilation.warnings).toMatchSnapshot('warnings');
144-
expect(stats.compilation.errors).toMatchSnapshot('errors');
156+
expect(stats.compilation.warnings).toMatchSnapshot('warnings');
157+
expect(stats.compilation.errors).toMatchSnapshot('errors');
158+
});
159+
}
145160
});
146161
});

‎test/manual/webpack.config.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ module.exports = {
3131
test: /\.lazy\.css$/i,
3232
use: [
3333
{
34-
loader: require.resolve('../../dist/useable-loader.js'),
34+
loader: require.resolve('../../dist/index.js'),
35+
options: { injectType: 'lazyStyleTag' },
3536
},
3637
{
3738
loader: 'css-loader',
@@ -45,7 +46,8 @@ module.exports = {
4546
test: /\.link\.css$/i,
4647
use: [
4748
{
48-
loader: require.resolve('../../dist/url-loader.js'),
49+
loader: require.resolve('../../dist/index.js'),
50+
options: { injectType: 'linkTag' },
4951
},
5052
{
5153
loader: 'file-loader',
@@ -79,7 +81,8 @@ module.exports = {
7981
test: /\.lazy\.scss$/i,
8082
use: [
8183
{
82-
loader: require.resolve('../../dist/useable-loader.js'),
84+
loader: require.resolve('../../dist/index.js'),
85+
options: { injectType: 'lazyStyleTag' },
8386
},
8487
{
8588
loader: 'css-loader',

‎test/singleton-option.test.js

-58
This file was deleted.

‎test/validate-options.test.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,14 @@ it('validate options', () => {
2020
'file.css'
2121
);
2222

23-
expect(() => validate({ base: 1000 })).not.toThrow();
24-
expect(() => validate({ base: 'unknown' })).toThrowErrorMatchingSnapshot();
23+
expect(() => validate({ injectType: 'styleTag' })).not.toThrow();
24+
expect(() => validate({ injectType: 'singletonStyleTag' })).not.toThrow();
25+
expect(() => validate({ injectType: 'lazyStyleTag' })).not.toThrow();
26+
expect(() => validate({ injectType: 'lazySingletonStyleTag' })).not.toThrow();
27+
expect(() => validate({ injectType: 'linkTag' })).not.toThrow();
28+
expect(() =>
29+
validate({ injectType: 'unknown' })
30+
).toThrowErrorMatchingSnapshot();
2531

2632
expect(() => validate({ attributes: {} })).not.toThrow();
2733
expect(() => validate({ attributes: { id: 'id' } })).not.toThrow();
@@ -44,11 +50,5 @@ it('validate options', () => {
4450
expect(() => validate({ insertInto: 'test' })).not.toThrow();
4551
expect(() => validate({ insertInto: true })).toThrowErrorMatchingSnapshot();
4652

47-
expect(() => validate({ singleton: true })).not.toThrow();
48-
expect(() => validate({ singleton: false })).not.toThrow();
49-
expect(() =>
50-
validate({ singleton: 'unknown' })
51-
).toThrowErrorMatchingSnapshot();
52-
5353
expect(() => validate({ unknown: 'unknown' })).toThrowErrorMatchingSnapshot();
5454
});

‎url.js

-7
This file was deleted.

‎useable.js

-7
This file was deleted.

0 commit comments

Comments
 (0)
Please sign in to comment.