Skip to content

Commit 03f1d6f

Browse files
feat(plugins/url): add url filter support (options.url) (#162)
1 parent eb8f5e3 commit 03f1d6f

File tree

8 files changed

+233
-17
lines changed

8 files changed

+233
-17
lines changed

README.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,40 @@ If your application includes many HTML Components or certain HTML Components are
6969

7070
### `url`
7171

72+
#### `{Boolean}`
73+
74+
**webpack.config.js**
75+
```js
76+
{
77+
loader: 'html-loader',
78+
options: {
79+
url: false
80+
}
81+
}
82+
```
83+
84+
#### `{RegExp}`
85+
7286
**webpack.config.js**
7387
```js
7488
{
7589
loader: 'html-loader',
7690
options: {
77-
url: // TODO add URL filter method (#158 && #159)
91+
url: /filter/
92+
}
93+
}
94+
```
95+
96+
#### `{Function}`
97+
98+
**webpack.config.js**
99+
```js
100+
{
101+
loader: 'html-loader',
102+
options: {
103+
url (url) {
104+
return /filter/.test(url)
105+
}
78106
}
79107
}
80108
```

src/index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export default function loader(html, map, meta) {
3939

4040
// HTML URL Plugin
4141
if (options.url) {
42-
plugins.push(urls());
42+
plugins.push(urls(options));
4343
}
4444

4545
// HTML IMPORT Plugin
@@ -49,7 +49,9 @@ export default function loader(html, map, meta) {
4949

5050
// TODO(michael-ciniawsky)
5151
// <imports src=""./file.html"> aren't minified (options.template) (#160)
52-
if (options.minimize) plugins.push(minifier());
52+
if (options.minimize) {
53+
plugins.push(minifier());
54+
}
5355

5456
// Reuse HTML AST (PostHTML AST)
5557
// (e.g posthtml-loader) to avoid HTML reparsing

src/options.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22
"type": "object",
33
"properties": {
44
"url": {
5-
"type": "boolean"
5+
"anyOf": [
6+
{ "type": "string" },
7+
{ "type": "boolean" },
8+
{ "instanceof": "RegExp" },
9+
{ "instanceof": "Function" }
10+
]
611
},
712
"import": {
813
"anyOf": [

src/plugins/url.js

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
11
/* eslint-disable */
22
// External URL (Protocol URL)
33
const URL = /^\w+:\/\//;
4-
// TODO(michael-ciniawsky)
5-
// extend with custom matchers
6-
// e.g <custom-element custom-src="">
7-
// (`options.url.filter`) (#159)
4+
// Attributes Matcher
85
const ATTRS = [
96
{ attrs: { src: true } },
107
{ attrs: { href: true } },
118
{ attrs: { srcset: true } },
129
];
1310

14-
// TODO(michael-ciniawsky)
15-
// add filter method for urls (e.g `options.url.filter`) (#158)
16-
const filter = (url) => {
17-
return URL.test(url) || url.startsWith('//');
11+
const filter = (url, options) => {
12+
if (URL.test(url)) {
13+
return true;
14+
}
15+
16+
if (url.startsWith('//')) {
17+
return true;
18+
}
19+
20+
if (options.url instanceof RegExp) {
21+
return options.url.test(url);
22+
}
23+
24+
if (typeof options.url === 'function') {
25+
return options.url(url);
26+
}
27+
28+
return false;
1829
};
1930

2031
export default function (options = {}) {
@@ -30,7 +41,7 @@ export default function (options = {}) {
3041
}
3142

3243
// Ignore external && filtered urls
33-
if (filter(node.attrs.src)) {
44+
if (filter(node.attrs.src, options)) {
3445
return node;
3546
}
3647

@@ -48,10 +59,11 @@ export default function (options = {}) {
4859

4960
return node;
5061
}
62+
5163
// <tag href="path/to/file.ext">
5264
if (node.attrs.href) {
5365
// Ignore external && filtered urls
54-
if (filter(node.attrs.href)) {
66+
if (filter(node.attrs.href, options)) {
5567
return node;
5668
}
5769

@@ -72,7 +84,7 @@ export default function (options = {}) {
7284
// <tag srcset="path/to/file.ext">
7385
if (node.attrs.srcset) {
7486
// Ignore external && filtered urls
75-
if (filter(node.attrs.srcset)) {
87+
if (filter(node.attrs.srcset, options)) {
7688
return node;
7789
}
7890

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!-- Ignore -->
2+
<img src="//file.png">
3+
<img src="//cdn.com/file.png">
4+
<img src="http://cdn.com/file.png">
5+
<img src="https://cdn.com/file.png">
6+
<!-- Transform -->
7+
<img src="./file.png">
8+
<img src="/file.png">
9+
<!-- Filter -->
10+
<img src="./filter/file.png">
11+
<img src="/filter/file.png">
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import html from './fixture.html';
2+
3+
export default html;

test/options/__snapshots__/url.test.js.snap

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,65 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`Options url {Boolean} 1`] = `
3+
exports[`Options url {Boolean} - false 1`] = `
4+
"// HTML Imports
5+
6+
7+
// HTML Exports
8+
9+
10+
// HTML
11+
export default \`<!DOCTYPE html>
12+
<html lang=\\"en\\">
13+
<head>
14+
<meta charset=\\"utf-8\\">
15+
<title>HTML Loader</title>
16+
<!-- Ignore -->
17+
<link href=\\"//file.css\\">
18+
<link href=\\"//cdn.com/file.css\\">
19+
<link href=\\"http://cdn.com/file.css\\">
20+
<link href=\\"https://cdn.com/file.css\\">
21+
<!-- Transform -->
22+
<link href=\\"./file.css\\">
23+
<link href=\\"/file.css\\">
24+
</head>
25+
<body>
26+
<!-- Ignore -->
27+
<img src=\\"//file.png\\">
28+
<img src=\\"//cdn.com/file.png\\">
29+
<img src=\\"http://cdn.com/file.png\\">
30+
<img src=\\"https://cdn.com/file.png\\">
31+
<!-- Transform -->
32+
<img src=\\"./file.png\\">
33+
<img src=\\"/file.png\\">
34+
35+
​<picture>
36+
<source srcset=\\"./file.svg\\" type=\\"image/svg+xml\\">
37+
<img src=\\"./file.png\\" alt=\\"Image\\">
38+
</picture>
39+
40+
<video width=\\"320\\" height=\\"240\\" controls=\\"\\">
41+
<source src=\\"./file.mp4\\" type=\\"video/mp4\\">
42+
<source src=\\"./file.ogg\\" type=\\"video/ogg\\">
43+
Your browser does not support the <code>video<code> element.
44+
</code></code></video>
45+
46+
<audio src=\\"./file.mp3\\" autoplay=\\"\\"></audio>
47+
48+
<audio controls=\\"controls\\">
49+
Your browser does not support the <code>audio</code> element.
50+
<source src=\\"./file.wav\\" type=\\"audio/wav\\">
51+
</audio>
52+
53+
<audio src=\\"./file.ogg\\">
54+
<track kind=\\"captions\\" src=\\"./file.en.vtt\\" srclang=\\"en\\" label=\\"English\\">
55+
<track kind=\\"captions\\" src=\\"./file.sv.vtt\\" srclang=\\"sv\\" label=\\"Svenska\\">
56+
</audio>
57+
</body>
58+
</html>
59+
\`"
60+
`;
61+
62+
exports[`Options url {Boolean} - true - (default) 1`] = `
463
"// HTML Imports
564
import HTML__URL__0 from './file.css';
665
import HTML__URL__1 from '/file.css';
@@ -71,3 +130,49 @@ export default \`<!DOCTYPE html>
71130
</html>
72131
\`"
73132
`;
133+
134+
exports[`Options url {Function} 1`] = `
135+
"// HTML Imports
136+
import HTML__URL__0 from './file.png';
137+
import HTML__URL__1 from '/file.png';
138+
139+
140+
// HTML Exports
141+
142+
143+
// HTML
144+
export default \`<!-- Ignore -->
145+
<img src=\\"//file.png\\">
146+
<img src=\\"//cdn.com/file.png\\">
147+
<img src=\\"http://cdn.com/file.png\\">
148+
<img src=\\"https://cdn.com/file.png\\">
149+
<!-- Transform -->
150+
<img src=\\"\${HTML__URL__0}\\">
151+
<img src=\\"\${HTML__URL__1}\\">
152+
<!-- Filter -->
153+
<img src=\\"./filter/file.png\\">
154+
<img src=\\"/filter/file.png\\">\`"
155+
`;
156+
157+
exports[`Options url {RegExp} 1`] = `
158+
"// HTML Imports
159+
import HTML__URL__0 from './file.png';
160+
import HTML__URL__1 from '/file.png';
161+
162+
163+
// HTML Exports
164+
165+
166+
// HTML
167+
export default \`<!-- Ignore -->
168+
<img src=\\"//file.png\\">
169+
<img src=\\"//cdn.com/file.png\\">
170+
<img src=\\"http://cdn.com/file.png\\">
171+
<img src=\\"https://cdn.com/file.png\\">
172+
<!-- Transform -->
173+
<img src=\\"\${HTML__URL__0}\\">
174+
<img src=\\"\${HTML__URL__1}\\">
175+
<!-- Filter -->
176+
<img src=\\"./filter/file.png\\">
177+
<img src=\\"/filter/file.png\\">\`"
178+
`;

test/options/url.test.js

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import webpack from '../helpers/compiler';
55

66
describe('Options', () => {
77
describe('url', () => {
8-
test('{Boolean}', async () => {
8+
test('{Boolean} - true - (default)', async () => {
99
const config = {
1010
loader: {
1111
test: /\.html$/,
@@ -18,5 +18,55 @@ describe('Options', () => {
1818

1919
expect(source).toMatchSnapshot();
2020
});
21+
22+
test('{Boolean} - false', async () => {
23+
const config = {
24+
loader: {
25+
test: /\.html$/,
26+
options: {
27+
url: false,
28+
},
29+
},
30+
};
31+
32+
const stats = await webpack('options/url/fixture.js', config);
33+
const { source } = stats.toJson().modules[1];
34+
35+
expect(source).toMatchSnapshot();
36+
});
37+
38+
test('{RegExp}', async () => {
39+
const config = {
40+
loader: {
41+
test: /\.html$/,
42+
options: {
43+
url: /filter/,
44+
},
45+
},
46+
};
47+
48+
const stats = await webpack('options/url/filter/fixture.js', config);
49+
const { source } = stats.toJson().modules[1];
50+
51+
expect(source).toMatchSnapshot();
52+
});
53+
54+
test('{Function}', async () => {
55+
const config = {
56+
loader: {
57+
test: /\.html$/,
58+
options: {
59+
url(url) {
60+
return /filter/.test(url);
61+
},
62+
},
63+
},
64+
};
65+
66+
const stats = await webpack('options/url/filter/fixture.js', config);
67+
const { source } = stats.toJson().modules[1];
68+
69+
expect(source).toMatchSnapshot();
70+
});
2171
});
2272
});

0 commit comments

Comments
 (0)