Skip to content

Commit 777d46f

Browse files
feat(url): add url filter support (options.url)
1 parent 00e5686 commit 777d46f

File tree

8 files changed

+311
-35
lines changed

8 files changed

+311
-35
lines changed

README.md

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,52 @@ 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+
#### `{String}`
85+
86+
**webpack.config.js**
87+
```js
88+
{
89+
loader: 'html-loader',
90+
options: {
91+
url: 'filter'
92+
}
93+
}
94+
```
95+
96+
#### `{RegExp}`
97+
7298
**webpack.config.js**
7399
```js
74100
{
75101
loader: 'html-loader',
76102
options: {
77-
url: // TODO add URL filter method (#158 && #159)
103+
url: /filter/
104+
}
105+
}
106+
```
107+
108+
#### `{Function}`
109+
110+
**webpack.config.js**
111+
```js
112+
{
113+
loader: 'html-loader',
114+
options: {
115+
url (url) {
116+
return /filter/.test(url)
117+
}
78118
}
79119
}
80120
```

src/index.js

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import schema from './options.json';
1111
import LoaderError from './lib/Error';
1212

1313
// Loader Defaults
14-
const defaults = {
14+
const DEFAULTS = {
1515
url: true,
1616
import: true,
1717
minimize: false,
@@ -20,7 +20,11 @@ const defaults = {
2020

2121
export default function loader(html, map, meta) {
2222
// Loader Options
23-
const options = Object.assign(defaults, getOptions(this));
23+
const options = Object.assign(
24+
{},
25+
DEFAULTS,
26+
getOptions(this)
27+
);
2428

2529
validateOptions(schema, options, 'HTML Loader');
2630
// Make the loader async
@@ -30,14 +34,20 @@ export default function loader(html, map, meta) {
3034
// HACK add Module.type
3135
this._module.type = 'text/html';
3236

33-
const template = options.template
37+
options.template = options.template
3438
? typeof options.template === 'string' ? options.template : '_'
3539
: false;
3640

3741
const plugins = [];
3842

39-
if (options.url) plugins.push(urls());
40-
if (options.import) plugins.push(imports({ template }));
43+
if (options.url) {
44+
plugins.push(urls(options));
45+
}
46+
47+
if (options.import) {
48+
plugins.push(imports(options));
49+
}
50+
4151
// TODO(michael-ciniawsky)
4252
// <imports src=""./file.html"> aren't minified (#160)
4353
if (options.minimize) plugins.push(minifier());
@@ -55,7 +65,7 @@ export default function loader(html, map, meta) {
5565
let imports = messages[1];
5666

5767
// TODO(michael-ciniawsky) revisit
58-
// Ensure to cleanup/reset messages
68+
// HACK Ensure to cleanup/reset messages
5969
// during recursive resolving of imports
6070
messages.length = 0;
6171

@@ -66,6 +76,7 @@ export default function loader(html, map, meta) {
6676
.map((url) => `import ${url} from '${urls[url]}';`)
6777
.join('\n');
6878
}
79+
6980
// <import src="./file.html">
7081
// => import HTML__IMPORT__${idx} from './file.html';
7182
if (imports) {
@@ -75,7 +86,7 @@ export default function loader(html, map, meta) {
7586
}
7687

7788
html = options.template
78-
? `function (${template}) { return \`${html}\`; }`
89+
? `function (${options.template}) { return \`${html}\`; }`
7990
: `\`${html}\``;
8091

8192
const result = [

src/lib/plugins/url.js

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,76 @@
11
/* eslint-disable */
22
// External URL (Protocol URL)
3-
const TEST_URL = /^\w+:\/\//;
4-
// TODO(michael-ciniawsky)
5-
// extend with custom matchers
6-
// e.g <custom-element custom-src="">
7-
// (`options.url.filter`) (#159)
8-
const MATCH_ATTRS = [
3+
const URL = /^\w+:\/\//;
4+
const ATTRS = [
95
{ attrs: { src: true } },
106
{ attrs: { href: true } },
117
{ attrs: { srcset: true } },
128
];
139

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

2034
export default function(options = {}) {
2135
return function(tree) {
2236
let idx = 0;
2337
const urls = {};
2438

25-
tree.match(MATCH_ATTRS, (node) => {
39+
tree.match(ATTRS, (node) => {
2640
// <tag src="path/to/file.ext">
2741
if (node.attrs.src) {
2842
// Ignore <import>/<include
29-
if (node.tag === 'import' || node.tag === 'include') return node;
30-
// Ignore external && filtered urls
31-
if (filter(node.attrs.src, options)) return node;
32-
// Add url to messages.urls
43+
if (node.tag === 'import' || node.tag === 'include') {
44+
return node;
45+
}
46+
47+
// Ignore external && filtered URLs
48+
if (options.url && filter(node.attrs.src, options)) {
49+
return node;
50+
}
51+
52+
// Add URL to result.messages.urls
3353
urls[`HTML__URL__${idx}`] = node.attrs.src;
34-
// Add content placeholders to HTML
54+
55+
// Add URL content placeholders to HTML
3556
node.attrs.src = '${' + `HTML__URL__${idx}` + '}';
3657

3758
idx++;
3859

3960
return node;
4061
}
62+
4163
// <tag href="path/to/file.ext">
4264
if (node.attrs.href) {
43-
// Ignore external && filtered urls
44-
if (filter(node.attrs.href, options)) return node;
45-
// Add url to messages.urls
65+
// Ignore external && filtered URLs
66+
if (filter(node.attrs.href, options)) {
67+
return node;
68+
}
69+
70+
// Add URL to result.messages.urls
4671
urls[`HTML__URL__${idx}`] = node.attrs.href;
47-
// Add content placeholder to HTML
72+
73+
// Add URL content placeholder to HTML
4874
node.attrs.href = '${' + `HTML__URL__${idx}` + '}';
4975

5076
idx++;
@@ -53,11 +79,14 @@ export default function(options = {}) {
5379
}
5480
// <tag srcset="path/to/file.ext">
5581
if (node.attrs.srcset) {
56-
// Ignore external && filtered urls
57-
if (filter(node.attrs.srcset, options)) return node;
58-
// Add url to messages.urls
82+
// Ignore external && filtered URLs
83+
if (filter(node.attrs.srcset, options)) {
84+
return node;
85+
}
86+
// Add URL to messages.urls
5987
urls[`HTML__URL__${idx}`] = node.attrs.srcset;
60-
// Add content placeholder to HTML
88+
89+
// Add URL content placeholder to HTML
6190
node.attrs.srcset = '${' + `HTML__URL__${idx}` + '}';
6291

6392
idx++;
@@ -66,7 +95,7 @@ export default function(options = {}) {
6695
}
6796
});
6897

69-
// Add urls to result.messages
98+
// Add URLs to result.messages
7099
tree.messages.push(urls);
71100

72101
return tree;

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
"type": "boolean"
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;

0 commit comments

Comments
 (0)