Skip to content

Commit e8a2d5a

Browse files
feat: added attributes option
1 parent a5f17c4 commit e8a2d5a

File tree

17 files changed

+970
-755
lines changed

17 files changed

+970
-755
lines changed

README.md

+37-2
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ module.exports = {
8181
| **[`chunkFilename`](#chunkFilename)** | `{String\|Function}` | `based on filename` | This option determines the name of non-entry chunk files |
8282
| **[`ignoreOrder`](#ignoreOrder)** | `{Boolean}` | `false` | Remove Order Warnings |
8383
| **[`insert`](#insert)** | `{String\|Function}` | `var head = document.getElementsByTagName("head")[0];head.appendChild(linkTag);` | Inserts `<link>` at the given position |
84+
| **[`attributes`](#attributes)** | `{Object}` | `{}` | Adds custom attributes to tag |
8485

8586
#### `filename`
8687

@@ -113,7 +114,7 @@ See [examples](#remove-order-warnings) below for details.
113114
#### `insert`
114115

115116
Type: `String|Function`
116-
Default: `var head = document.getElementsByTagName("head")[0];head.appendChild(linkTag);`
117+
Default: `var head = document.getElementsByTagName("head")[0]; head.appendChild(linkTag);`
117118

118119
By default, the `extract-css-chunks-plugin` appends styles (`<link>` elements) to `document.head` of the current `window`.
119120

@@ -151,7 +152,7 @@ Allows to override default behavior and insert styles at any position.
151152
```js
152153
new MiniCssExtractPlugin({
153154
insert: function (linkTag) {
154-
const reference = document.querySelector('#some-element');
155+
var reference = document.querySelector('#some-element');
155156
if (reference) {
156157
reference.parentNode.insertBefore(linkTag, reference);
157158
}
@@ -161,6 +162,40 @@ new MiniCssExtractPlugin({
161162

162163
A new `<link>` element will be inserted before the element with id `some-element`.
163164

165+
#### `attributes`
166+
167+
Type: `Object`
168+
Default: `{}`
169+
170+
If defined, the `mini-css-extract-plugin` will attach given attributes with their values on <link> element.
171+
172+
**webpack.config.js**
173+
174+
```js
175+
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
176+
177+
module.exports = {
178+
plugins: [
179+
new MiniCssExtractPlugin({
180+
attributes: {
181+
id: 'target',
182+
'data-target': 'example',
183+
},
184+
}),
185+
],
186+
module: {
187+
rules: [
188+
{
189+
test: /\.css$/i,
190+
use: [MiniCssExtractPlugin.loader, 'css-loader'],
191+
},
192+
],
193+
},
194+
};
195+
```
196+
197+
Note: It's only applied to dynamically loaded css chunks, if you want to modify link attributes inside html file, please using [html-webpack-plugin](https://github.com/jantimon/html-webpack-plugin)
198+
164199
### Loader Options
165200

166201
| Name | Type | Default | Description |

package-lock.json

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

src/CssLoadingRuntimeModule.js

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ module.exports = class CssLoadingRuntimeModule extends RuntimeModule {
5555
'fullhref, resolve, reject',
5656
[
5757
'var linkTag = document.createElement("link");',
58+
this.runtimeOptions.attributes,
5859
'linkTag.rel = "stylesheet";',
5960
'linkTag.type = "text/css";',
6061
'linkTag.onload = resolve;',

src/index.js

+14
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ class MiniCssExtractPlugin {
4949
'head.appendChild(linkTag);',
5050
]);
5151

52+
const attributes =
53+
typeof options.attributes === 'object' ? options.attributes : {};
54+
5255
this.options = Object.assign(
5356
{
5457
filename: DEFAULT_FILENAME,
@@ -61,6 +64,16 @@ class MiniCssExtractPlugin {
6164
insert,
6265
};
6366

67+
this.runtimeOptions.attributes = Template.asString(
68+
Object.entries(attributes).map((entry) => {
69+
const [key, value] = entry;
70+
71+
return `linkTag.setAttribute(${JSON.stringify(key)}, ${JSON.stringify(
72+
value
73+
)});`;
74+
})
75+
);
76+
6477
if (!this.options.chunkFilename) {
6578
const { filename } = this.options;
6679

@@ -383,6 +396,7 @@ class MiniCssExtractPlugin {
383396
]),
384397
'}',
385398
'var linkTag = document.createElement("link");',
399+
this.runtimeOptions.attributes,
386400
'linkTag.rel = "stylesheet";',
387401
'linkTag.type = "text/css";',
388402
'linkTag.onload = resolve;',

src/plugin-options.json

+4
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@
3535
"instanceof": "Function"
3636
}
3737
]
38+
},
39+
"attributes": {
40+
"description": "Adds custom attributes to tag (https://github.com/webpack-contrib/mini-css-extract-plugin#attributes).",
41+
"type": "object"
3842
}
3943
}
4044
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`attributes option should work with attributes option: DOM 1`] = `
4+
"<!DOCTYPE html><html><head>
5+
<title>style-loader test</title>
6+
<style id=\\"existing-style\\">.existing { color: yellow }</style>
7+
<link id=\\"target\\" data-target=\\"example\\" rel=\\"stylesheet\\" type=\\"text/css\\" href=\\"simple.css\\"><script charset=\\"utf-8\\" src=\\"simple.bundle.js\\"></script></head>
8+
<body>
9+
<h1>Body</h1>
10+
<div class=\\"target\\"></div>
11+
<iframe class=\\"iframeTarget\\"></iframe>
12+
13+
14+
</body></html>"
15+
`;
16+
17+
exports[`attributes option should work with attributes option: errors 1`] = `Array []`;
18+
19+
exports[`attributes option should work with attributes option: warnings 1`] = `Array []`;
20+
21+
exports[`attributes option should work without attributes option: DOM 1`] = `
22+
"<!DOCTYPE html><html><head>
23+
<title>style-loader test</title>
24+
<style id=\\"existing-style\\">.existing { color: yellow }</style>
25+
<link rel=\\"stylesheet\\" type=\\"text/css\\" href=\\"simple.css\\"><script charset=\\"utf-8\\" src=\\"simple.bundle.js\\"></script></head>
26+
<body>
27+
<h1>Body</h1>
28+
<div class=\\"target\\"></div>
29+
<iframe class=\\"iframeTarget\\"></iframe>
30+
31+
32+
</body></html>"
33+
`;
34+
35+
exports[`attributes option should work without attributes option: errors 1`] = `Array []`;
36+
37+
exports[`attributes option should work without attributes option: warnings 1`] = `Array []`;

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

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

3+
exports[`validate options should throw an error on the "attributes" option with "true" value 1`] = `
4+
"Invalid options object. Mini CSS Extract Plugin has been initialized using an options object that does not match the API schema.
5+
- options.attributes should be an object:
6+
object {}
7+
-> Adds custom attributes to tag (https://github.com/webpack-contrib/mini-css-extract-plugin#attributes)."
8+
`;
9+
310
exports[`validate options should throw an error on the "chunkFilename" option with "true" value 1`] = `
411
"Invalid options object. Mini CSS Extract Plugin has been initialized using an options object that does not match the API schema.
512
- options.chunkFilename should be one of these:

test/attributes-option.test.js

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/* eslint-env browser */
2+
import path from 'path';
3+
4+
import MiniCssExtractPlugin from '../src/cjs';
5+
6+
import {
7+
compile,
8+
getCompiler,
9+
getErrors,
10+
getWarnings,
11+
runInJsDom,
12+
} from './helpers/index';
13+
14+
describe('attributes option', () => {
15+
it(`should work without attributes option`, async () => {
16+
const compiler = getCompiler(
17+
'attributes.js',
18+
{},
19+
{
20+
output: {
21+
publicPath: '',
22+
path: path.resolve(__dirname, '../outputs'),
23+
filename: '[name].bundle.js',
24+
},
25+
plugins: [
26+
new MiniCssExtractPlugin({
27+
filename: '[name].css',
28+
}),
29+
],
30+
}
31+
);
32+
const stats = await compile(compiler);
33+
34+
runInJsDom('main.bundle.js', compiler, stats, (dom) => {
35+
// console.log(dom.serialize())
36+
expect(dom.serialize()).toMatchSnapshot('DOM');
37+
});
38+
39+
expect(getWarnings(stats)).toMatchSnapshot('warnings');
40+
expect(getErrors(stats)).toMatchSnapshot('errors');
41+
});
42+
43+
it(`should work with attributes option`, async () => {
44+
const compiler = getCompiler(
45+
'attributes.js',
46+
{},
47+
{
48+
output: {
49+
publicPath: '',
50+
path: path.resolve(__dirname, '../outputs'),
51+
filename: '[name].bundle.js',
52+
},
53+
plugins: [
54+
new MiniCssExtractPlugin({
55+
attributes: {
56+
id: 'target',
57+
'data-target': 'example',
58+
},
59+
filename: '[name].css',
60+
}),
61+
],
62+
}
63+
);
64+
const stats = await compile(compiler);
65+
66+
runInJsDom('main.bundle.js', compiler, stats, (dom) => {
67+
// console.log(dom.serialize())
68+
expect(dom.serialize()).toMatchSnapshot('DOM');
69+
});
70+
71+
expect(getWarnings(stats)).toMatchSnapshot('warnings');
72+
expect(getErrors(stats)).toMatchSnapshot('errors');
73+
});
74+
});

test/cases/hmr/expected/webpack-5/main.js

+1
Original file line numberDiff line numberDiff line change
@@ -3292,6 +3292,7 @@ module.exports = function (x) {
32923292
/******/ (() => {
32933293
/******/ var createStylesheet = (fullhref, resolve, reject) => {
32943294
/******/ var linkTag = document.createElement("link");
3295+
/******/
32953296
/******/ linkTag.rel = "stylesheet";
32963297
/******/ linkTag.type = "text/css";
32973298
/******/ linkTag.onload = resolve;

test/cases/insert-function/expected/webpack-4/main.js

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
/******/ if(dataHref === href || dataHref === fullhref) return resolve();
102102
/******/ }
103103
/******/ var linkTag = document.createElement("link");
104+
/******/
104105
/******/ linkTag.rel = "stylesheet";
105106
/******/ linkTag.type = "text/css";
106107
/******/ linkTag.onload = resolve;

test/cases/insert-function/expected/webpack-5/main.js

+1
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@
159159
/******/ (() => {
160160
/******/ var createStylesheet = (fullhref, resolve, reject) => {
161161
/******/ var linkTag = document.createElement("link");
162+
/******/
162163
/******/ linkTag.rel = "stylesheet";
163164
/******/ linkTag.type = "text/css";
164165
/******/ linkTag.onload = resolve;

test/cases/insert-string/expected/webpack-4/main.js

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
/******/ if(dataHref === href || dataHref === fullhref) return resolve();
102102
/******/ }
103103
/******/ var linkTag = document.createElement("link");
104+
/******/
104105
/******/ linkTag.rel = "stylesheet";
105106
/******/ linkTag.type = "text/css";
106107
/******/ linkTag.onload = resolve;

test/cases/insert-string/expected/webpack-5/main.js

+1
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@
159159
/******/ (() => {
160160
/******/ var createStylesheet = (fullhref, resolve, reject) => {
161161
/******/ var linkTag = document.createElement("link");
162+
/******/
162163
/******/ linkTag.rel = "stylesheet";
163164
/******/ linkTag.type = "text/css";
164165
/******/ linkTag.onload = resolve;

test/cases/insert-undefined/expected/webpack-4/main.js

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
/******/ if(dataHref === href || dataHref === fullhref) return resolve();
102102
/******/ }
103103
/******/ var linkTag = document.createElement("link");
104+
/******/
104105
/******/ linkTag.rel = "stylesheet";
105106
/******/ linkTag.type = "text/css";
106107
/******/ linkTag.onload = resolve;

test/cases/insert-undefined/expected/webpack-5/main.js

+1
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@
159159
/******/ (() => {
160160
/******/ var createStylesheet = (fullhref, resolve, reject) => {
161161
/******/ var linkTag = document.createElement("link");
162+
/******/
162163
/******/ linkTag.rel = "stylesheet";
163164
/******/ linkTag.type = "text/css";
164165
/******/ linkTag.onload = resolve;

test/fixtures/attributes.js

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/* eslint-disable-next-line no-unused-expressions */
2+
import(/* webpackChunkName: "simple" */ './simple.css');

test/validate-plugin-options.test.js

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ describe('validate options', () => {
2828
success: ['#existing-style', function insert() {}],
2929
failure: [1, true, {}],
3030
},
31+
attributes: {
32+
success: [{}, { id: 'id' }],
33+
failure: [true],
34+
},
3135
unknown: {
3236
success: [],
3337
// TODO failed in next release

0 commit comments

Comments
 (0)