Skip to content

Commit

Permalink
feat(url): add url filter support (options.url)
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-ciniawsky committed Jan 4, 2018
1 parent 00e5686 commit 777d46f
Show file tree
Hide file tree
Showing 8 changed files with 311 additions and 35 deletions.
42 changes: 41 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,52 @@ If your application includes many HTML Components or certain HTML Components are

### `url`

#### `{Boolean}`

**webpack.config.js**
```js
{
loader: 'html-loader',
options: {
url: false
}
}
```

#### `{String}`

**webpack.config.js**
```js
{
loader: 'html-loader',
options: {
url: 'filter'
}
}
```

#### `{RegExp}`

**webpack.config.js**
```js
{
loader: 'html-loader',
options: {
url: // TODO add URL filter method (#158 && #159)
url: /filter/
}
}
```

#### `{Function}`

**webpack.config.js**
```js
{
loader: 'html-loader',
options: {
url (url) {
return /filter/.test(url)
}
}
}
```
Expand Down
25 changes: 18 additions & 7 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import schema from './options.json';
import LoaderError from './lib/Error';

// Loader Defaults
const defaults = {
const DEFAULTS = {
url: true,
import: true,
minimize: false,
Expand All @@ -20,7 +20,11 @@ const defaults = {

export default function loader(html, map, meta) {
// Loader Options
const options = Object.assign(defaults, getOptions(this));
const options = Object.assign(
{},
DEFAULTS,
getOptions(this)
);

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

const template = options.template
options.template = options.template
? typeof options.template === 'string' ? options.template : '_'
: false;

const plugins = [];

if (options.url) plugins.push(urls());
if (options.import) plugins.push(imports({ template }));
if (options.url) {
plugins.push(urls(options));
}

if (options.import) {
plugins.push(imports(options));
}

// TODO(michael-ciniawsky)
// <imports src=""./file.html"> aren't minified (#160)
if (options.minimize) plugins.push(minifier());
Expand All @@ -55,7 +65,7 @@ export default function loader(html, map, meta) {
let imports = messages[1];

// TODO(michael-ciniawsky) revisit
// Ensure to cleanup/reset messages
// HACK Ensure to cleanup/reset messages
// during recursive resolving of imports
messages.length = 0;

Expand All @@ -66,6 +76,7 @@ export default function loader(html, map, meta) {
.map((url) => `import ${url} from '${urls[url]}';`)
.join('\n');
}

// <import src="./file.html">
// => import HTML__IMPORT__${idx} from './file.html';
if (imports) {
Expand All @@ -75,7 +86,7 @@ export default function loader(html, map, meta) {
}

html = options.template
? `function (${template}) { return \`${html}\`; }`
? `function (${options.template}) { return \`${html}\`; }`
: `\`${html}\``;

const result = [
Expand Down
77 changes: 53 additions & 24 deletions src/lib/plugins/url.js
Original file line number Diff line number Diff line change
@@ -1,50 +1,76 @@
/* eslint-disable */
// External URL (Protocol URL)
const TEST_URL = /^\w+:\/\//;
// TODO(michael-ciniawsky)
// extend with custom matchers
// e.g <custom-element custom-src="">
// (`options.url.filter`) (#159)
const MATCH_ATTRS = [
const URL = /^\w+:\/\//;
const ATTRS = [
{ attrs: { src: true } },
{ attrs: { href: true } },
{ attrs: { srcset: true } },
];

// TODO(michael-ciniawsky)
// add filter method for urls (e.g `options.url.filter`) (#158)
const filter = (url, options) => {
return TEST_URL.test(url) || url.startsWith('//');
if (URL.test(url)) {
return true;
}

if (url.startsWith('//')) {
return true;
}

if (typeof options.url === 'string') {
return url.includes(options.url);
}

if (options.url instanceof RegExp) {
return options.url.test(url);
}

if (typeof options.url === 'function') {
return options.url(url);
}

return false
};

export default function(options = {}) {
return function(tree) {
let idx = 0;
const urls = {};

tree.match(MATCH_ATTRS, (node) => {
tree.match(ATTRS, (node) => {
// <tag src="path/to/file.ext">
if (node.attrs.src) {
// Ignore <import>/<include
if (node.tag === 'import' || node.tag === 'include') return node;
// Ignore external && filtered urls
if (filter(node.attrs.src, options)) return node;
// Add url to messages.urls
if (node.tag === 'import' || node.tag === 'include') {
return node;
}

// Ignore external && filtered URLs
if (options.url && filter(node.attrs.src, options)) {
return node;
}

// Add URL to result.messages.urls
urls[`HTML__URL__${idx}`] = node.attrs.src;
// Add content placeholders to HTML

// Add URL content placeholders to HTML
node.attrs.src = '${' + `HTML__URL__${idx}` + '}';

idx++;

return node;
}

// <tag href="path/to/file.ext">
if (node.attrs.href) {
// Ignore external && filtered urls
if (filter(node.attrs.href, options)) return node;
// Add url to messages.urls
// Ignore external && filtered URLs
if (filter(node.attrs.href, options)) {
return node;
}

// Add URL to result.messages.urls
urls[`HTML__URL__${idx}`] = node.attrs.href;
// Add content placeholder to HTML

// Add URL content placeholder to HTML
node.attrs.href = '${' + `HTML__URL__${idx}` + '}';

idx++;
Expand All @@ -53,11 +79,14 @@ export default function(options = {}) {
}
// <tag srcset="path/to/file.ext">
if (node.attrs.srcset) {
// Ignore external && filtered urls
if (filter(node.attrs.srcset, options)) return node;
// Add url to messages.urls
// Ignore external && filtered URLs
if (filter(node.attrs.srcset, options)) {
return node;
}
// Add URL to messages.urls
urls[`HTML__URL__${idx}`] = node.attrs.srcset;
// Add content placeholder to HTML

// Add URL content placeholder to HTML
node.attrs.srcset = '${' + `HTML__URL__${idx}` + '}';

idx++;
Expand All @@ -66,7 +95,7 @@ export default function(options = {}) {
}
});

// Add urls to result.messages
// Add URLs to result.messages
tree.messages.push(urls);

return tree;
Expand Down
7 changes: 6 additions & 1 deletion src/options.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
"type": "object",
"properties": {
"url": {
"type": "boolean"
"anyOf": [
{ "type": "string" },
{ "type": "boolean" },
{ "instanceof": "RegExp" },
{ "instanceof": "Function" }
]
},
"import": {
"type": "boolean"
Expand Down
11 changes: 11 additions & 0 deletions test/fixtures/options/url/filter/fixture.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- Ignore -->
<img src="//file.png">
<img src="//cdn.com/file.png">
<img src="http://cdn.com/file.png">
<img src="https://cdn.com/file.png">
<!-- Transform -->
<img src="./file.png">
<img src="/file.png">
<!-- Filter -->
<img src="./filter/file.png">
<img src="/filter/file.png">
3 changes: 3 additions & 0 deletions test/fixtures/options/url/filter/fixture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import html from './fixture.html';

export default html;
Loading

0 comments on commit 777d46f

Please sign in to comment.