Skip to content

Commit a80fc7e

Browse files
refactor: attrs option (#217)
* refactor: `attrs` option BREAKING CHANGE: the `attrs` option was renamed to the `attributes` option
1 parent ed18e7f commit a80fc7e

File tree

6 files changed

+153
-101
lines changed

6 files changed

+153
-101
lines changed

README.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,21 +57,21 @@ You may need to specify loaders for images in your configuration (recommended `f
5757

5858
| Name | Type | Default | Description |
5959
| :-------------------------------: | :-----------------: | :------------------------------------------: | :--------------------------------------- |
60-
| **[`attrs`](#attrs)** | `{Array\|String}` | `['img:src']` | Enables/Disables attributes handling |
60+
| **[`attributes`](#attributes)** | `{Array\|String}` | `['img:src']` | Enables/Disables attributes handling |
6161
| **[`root`](#root)** | `{String}` | `undefiend` | Allow to handle root-relative attributes |
6262
| **[`interpolate`](#interpolate)** | `{Boolean\|String}` | `false` | Allow to use expressions in HTML syntax |
6363
| **[`minimize`](#minimize)** | `{Boolean\|Object}` | `true` in production mode, otherwise `false` | Tell `html-loader` to minimize HTML |
6464
| **[`esModule`](#esmodule)** | `{Boolean}` | `false` | Use ES modules syntax |
6565

66-
### `attrs`
66+
### `attributes`
6767

6868
Type: `Array|String`
6969
Default: `['img:src']`
7070

71-
You can specify which tag-attribute combination should be processed by this loader via the query parameter `attrs`.
72-
Pass an array or a space-separated list of `<tag>:<attribute>` combinations. (Default: `attrs=img:src`)
71+
You can specify which tag-attribute combination should be processed by this loader via the query parameter `attributes`.
72+
Pass an array or a space-separated list of `<tag>:<attribute>` combinations. (Default: `attributes=img:src`)
7373

74-
If you use `<custom-elements>`, and lots of them make use of a `custom-src` attribute, you don't have to specify each combination `<tag>:<attribute>`: just specify an empty tag like `attrs=:custom-src` and it will match every element.
74+
If you use `<custom-elements>`, and lots of them make use of a `custom-src` attribute, you don't have to specify each combination `<tag>:<attribute>`: just specify an empty tag like `attributes=:custom-src` and it will match every element.
7575

7676
**webpack.config.js**
7777

@@ -83,7 +83,7 @@ module.exports = {
8383
test: /\.html$/i,
8484
loader: 'html-loader',
8585
options: {
86-
attrs: [':data-src'],
86+
attributes: [':data-src'],
8787
},
8888
},
8989
],
@@ -323,20 +323,20 @@ require('html-loader!./file.html');
323323
```
324324

325325
```js
326-
require('html-loader?attrs=img:data-src!./file.html');
326+
require('html-loader?attributes=img:data-src!./file.html');
327327

328328
// => '<img src="image.png" data-src="data:image/png;base64,..." >'
329329
```
330330

331331
```js
332-
require('html-loader?attrs=img:src img:data-src!./file.html');
333-
require('html-loader?attrs[]=img:src&attrs[]=img:data-src!./file.html');
332+
require('html-loader?attributes=img:src img:data-src!./file.html');
333+
require('html-loader?attributes[]=img:src&attributes[]=img:data-src!./file.html');
334334

335335
// => '<img src="http://cdn.example.com/49eba9f/a992ca.png" data-src="data:image/png;base64,..." >'
336336
```
337337

338338
```js
339-
require('html-loader?-attrs!./file.html');
339+
require('html-loader?-attributes!./file.html');
340340

341341
// => '<img src="image.jpg" data-src="image2x.png" >'
342342
```

src/index.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import validateOptions from 'schema-utils';
88

99
import { GET_URL_CODE, IDENT_REGEX, REQUIRE_REGEX } from './constants';
1010
import {
11-
getAttributes,
1211
getExportsString,
1312
getLinks,
1413
getUniqueIdent,
@@ -30,9 +29,7 @@ export default function htmlLoader(source) {
3029

3130
let content = source.toString();
3231

33-
const attributes = getAttributes(options);
34-
const links = getLinks(content, attributes);
35-
32+
const links = getLinks(content, options.attributes);
3633
const data = new Map();
3734

3835
let offset = 0;

src/options.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
{
22
"type": "object",
33
"properties": {
4-
"attrs": {
5-
"anyOf": [{ "type": "array" }, { "type": "string" }]
4+
"attributes": {
5+
"anyOf": [
6+
{ "type": "boolean" },
7+
{ "type": "array" },
8+
{ "type": "string" }
9+
]
610
},
711
"root": {
812
"type": "string"

src/utils.js

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,42 +4,42 @@ function randomIdent() {
44
return `xxxHTMLLINKxxx${Math.random()}${Math.random()}xxx`;
55
}
66

7-
export function getAttributes(options) {
8-
if (typeof options.attrs !== 'undefined') {
9-
if (typeof options.attrs === 'string') {
10-
return options.attrs.split(' ');
7+
export function getTagsAndAttributes(attributes) {
8+
const defaultAttributes = ['img:src'];
9+
10+
if (typeof attributes !== 'undefined') {
11+
if (typeof attributes === 'string') {
12+
return attributes.split(' ');
1113
}
1214

13-
if (Array.isArray(options.attrs)) {
14-
return options.attrs;
15+
if (Array.isArray(attributes)) {
16+
return attributes;
1517
}
1618

17-
if (options.attrs === false) {
19+
if (attributes === false) {
1820
return [];
1921
}
2022

21-
throw new Error('Invalid value to options parameter attrs');
22-
}
23-
24-
return ['img:src'];
25-
}
23+
if (attributes === true) {
24+
return defaultAttributes;
25+
}
2626

27-
export function getExportsString(options) {
28-
if (options.esModule) {
29-
return 'export default ';
27+
throw new Error('Invalid value to options parameter attrs');
3028
}
3129

32-
return 'module.exports = ';
30+
return defaultAttributes;
3331
}
3432

3533
export function getLinks(content, attributes) {
36-
return parseAttributes(content, (tag, attr) => {
37-
const res = attributes.find((a) => {
34+
const tagsAndAttributes = getTagsAndAttributes(attributes);
35+
36+
return parseAttributes(content, (tag, attribute) => {
37+
const res = tagsAndAttributes.find((a) => {
3838
if (a.startsWith(':')) {
39-
return attr === a.slice(1);
39+
return attribute === a.slice(1);
4040
}
4141

42-
return `${tag}:${attr}` === a;
42+
return `${tag}:${attribute}` === a;
4343
});
4444

4545
return Boolean(res);
@@ -56,6 +56,14 @@ export function getUniqueIdent(data) {
5656
return ident;
5757
}
5858

59+
export function getExportsString(options) {
60+
if (options.esModule) {
61+
return 'export default ';
62+
}
63+
64+
return 'module.exports = ';
65+
}
66+
5967
export function replaceLinkWithIdent(source, link, ident, offset = 0) {
6068
return (
6169
source.substr(0, link.start + offset) +

test/attributes-option.test.js

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import loader from '../src';
2+
import { GET_URL_CODE } from '../src/constants';
3+
4+
describe("'attributes' option", () => {
5+
it('should work with a "string" notation', () => {
6+
const result = loader.call(
7+
{
8+
mode: 'development',
9+
query: '?attributes=script:src',
10+
},
11+
'Text <script src="script.js"><img src="image.png">'
12+
);
13+
14+
expect(result).toBe(
15+
`${GET_URL_CODE}module.exports = "Text <script src=\\"" + __url__(require("./script.js")) + "\\"><img src=\\"image.png\\">";`
16+
);
17+
});
18+
19+
it('should work with multiple a "string" notations', () => {
20+
const result = loader.call(
21+
{
22+
mode: 'development',
23+
query: '?attributes=script:src img:src',
24+
},
25+
'Text <script src="script.js"><img src="image.png">'
26+
);
27+
28+
expect(result).toBe(
29+
`${GET_URL_CODE}module.exports = "Text <script src=\\"" + __url__(require("./script.js")) + "\\"><img src=\\"" + __url__(require("./image.png")) + "\\">";`
30+
);
31+
});
32+
33+
it('should work with an "array" notations', () => {
34+
const result = loader.call(
35+
{
36+
mode: 'development',
37+
query: '?attributes[]=img:src',
38+
},
39+
'Text <script src="script.js"><img src="image.png">'
40+
);
41+
42+
expect(result).toBe(
43+
`${GET_URL_CODE}module.exports = "Text <script src=\\"script.js\\"><img src=\\"" + __url__(require("./image.png")) + "\\">";`
44+
);
45+
});
46+
47+
it('should work with multiple an "array" notations', () => {
48+
const result = loader.call(
49+
{
50+
mode: 'development',
51+
query: '?attributes[]=script:src&attributes[]=img:src',
52+
},
53+
'Text <script src="script.js"><img src="image.png">'
54+
);
55+
56+
expect(result).toBe(
57+
`${GET_URL_CODE}module.exports = "Text <script src=\\"" + __url__(require("./script.js")) + "\\"><img src=\\"" + __url__(require("./image.png")) + "\\">";`
58+
);
59+
});
60+
61+
it('should work with a custom attribute', () => {
62+
const result = loader.call(
63+
{
64+
mode: 'development',
65+
query: '?attributes[]=:custom-src',
66+
},
67+
'Text <custom-element custom-src="image1.png"><custom-img custom-src="image2.png"/></custom-element>'
68+
);
69+
70+
expect(result).toBe(
71+
`${GET_URL_CODE}module.exports = "Text <custom-element custom-src=\\"" + __url__(require("./image1.png")) + "\\"><custom-img custom-src=\\"" + __url__(require("./image2.png")) + "\\"/></custom-element>";`
72+
);
73+
});
74+
75+
it('should work with a "boolean" notation', () => {
76+
const result = loader.call(
77+
{
78+
mode: 'development',
79+
query: '?attributes=false',
80+
},
81+
'Text <script src="script.js"><img src="image.png">'
82+
);
83+
84+
expect(result).toBe(
85+
`${GET_URL_CODE}module.exports = "Text <script src=\\"script.js\\"><img src=\\"image.png\\">";`
86+
);
87+
});
88+
89+
it('should work with a "boolean" notation', () => {
90+
const result = loader.call(
91+
{
92+
mode: 'development',
93+
query: '?attributes=true',
94+
},
95+
'Text <script src="script.js"><img src="image.png">'
96+
);
97+
98+
expect(result).toBe(
99+
`${GET_URL_CODE}module.exports = "Text <script src=\\"script.js\\"><img src=\\"" + __url__(require("./image.png")) + "\\">";`
100+
);
101+
});
102+
});

test/loader.test.js

Lines changed: 6 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -15,71 +15,6 @@ describe('loader', () => {
1515
);
1616
});
1717

18-
it('should accept attrs from query', () => {
19-
const result = loader.call(
20-
{
21-
mode: 'development',
22-
query: '?attrs=script:src',
23-
},
24-
'Text <script src="script.js"><img src="image.png">'
25-
);
26-
27-
expect(result).toBe(
28-
`${GET_URL_CODE}module.exports = "Text <script src=\\"" + __url__(require("./script.js")) + "\\"><img src=\\"image.png\\">";`
29-
);
30-
});
31-
it('should accept attrs from query (space separated)', () => {
32-
const result = loader.call(
33-
{
34-
mode: 'development',
35-
query: '?attrs=script:src img:src',
36-
},
37-
'Text <script src="script.js"><img src="image.png">'
38-
);
39-
40-
expect(result).toBe(
41-
`${GET_URL_CODE}module.exports = "Text <script src=\\"" + __url__(require("./script.js")) + "\\"><img src=\\"" + __url__(require("./image.png")) + "\\">";`
42-
);
43-
});
44-
it('should accept attrs from query (multiple)', () => {
45-
const result = loader.call(
46-
{
47-
mode: 'development',
48-
query: '?attrs[]=script:src&attrs[]=img:src',
49-
},
50-
'Text <script src="script.js"><img src="image.png">'
51-
);
52-
53-
expect(result).toBe(
54-
`${GET_URL_CODE}module.exports = "Text <script src=\\"" + __url__(require("./script.js")) + "\\"><img src=\\"" + __url__(require("./image.png")) + "\\">";`
55-
);
56-
});
57-
it('should accept :attribute (empty tag) from query', () => {
58-
const result = loader.call(
59-
{
60-
mode: 'development',
61-
query: '?attrs[]=:custom-src',
62-
},
63-
'Text <custom-element custom-src="image1.png"><custom-img custom-src="image2.png"/></custom-element>'
64-
);
65-
66-
expect(result).toBe(
67-
`${GET_URL_CODE}module.exports = "Text <custom-element custom-src=\\"" + __url__(require("./image1.png")) + "\\"><custom-img custom-src=\\"" + __url__(require("./image2.png")) + "\\"/></custom-element>";`
68-
);
69-
});
70-
it('should accept :attribute (empty tag) from query and not collide with similar attributes', () => {
71-
const result = loader.call(
72-
{
73-
mode: 'development',
74-
query: '?attrs[]=:custom-src',
75-
},
76-
'Text <custom-element custom-src="image1.png" custom-src-other="other.png"><custom-img custom-src="image2.png"/></custom-element>'
77-
);
78-
79-
expect(result).toBe(
80-
`${GET_URL_CODE}module.exports = "Text <custom-element custom-src=\\"" + __url__(require("./image1.png")) + "\\" custom-src-other=\\"other.png\\"><custom-img custom-src=\\"" + __url__(require("./image2.png")) + "\\"/></custom-element>";`
81-
);
82-
});
8318
it('should not make bad things with templates', () => {
8419
const result = loader.call(
8520
{ mode: 'development' },
@@ -112,6 +47,7 @@ describe('loader', () => {
11247
`${GET_URL_CODE}module.exports = "Text <img src=\\"/image.png\\">";`
11348
);
11449
});
50+
11551
it('should accept root from query', () => {
11652
const result = loader.call(
11753
{
@@ -125,6 +61,7 @@ describe('loader', () => {
12561
`${GET_URL_CODE}module.exports = "Text <img src=\\"" + __url__(require("/test/image.png")) + "\\">";`
12662
);
12763
});
64+
12865
it('should ignore hash fragments in URLs', () => {
12966
const result = loader.call(
13067
{ mode: 'development' },
@@ -135,6 +72,7 @@ describe('loader', () => {
13572
`${GET_URL_CODE}module.exports = "<img src=\\"" + __url__(require("./icons.svg")) + "#hash\\">";`
13673
);
13774
});
75+
13876
it("should ignore anchor with 'mailto:' in the href attribute", () => {
13977
const result = loader.call(
14078
{ mode: 'development' },
@@ -170,6 +108,7 @@ describe('loader', () => {
170108
`${GET_URL_CODE}module.exports = "<img src=\\"" + ("Hello " + (1 + 1)) + "\\">";`
171109
);
172110
});
111+
173112
it('should not change handling of quotes when interpolation is enabled', () => {
174113
const result = loader.call(
175114
{
@@ -183,6 +122,7 @@ describe('loader', () => {
183122
`${GET_URL_CODE}module.exports = "<script>{\\\"json\\\": \\\"with \\\\\\\"quotes\\\\\\\" in value\\\"}</script>";`
184123
);
185124
});
125+
186126
it('should enable interpolations when using interpolate=require flag and only require function be translate', () => {
187127
const result = loader.call(
188128
{
@@ -196,6 +136,7 @@ describe('loader', () => {
196136
`${GET_URL_CODE}module.exports = "<a href=\\"\${list.href}\\"><img src=\\"" + __url__(require("./test.jpg")) + "\\" /></a>";`
197137
);
198138
});
139+
199140
it('should export as es6 default export', () => {
200141
const result = loader.call(
201142
{

0 commit comments

Comments
 (0)