Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(plugins/url): add url filter support (options.url) #162

Merged
merged 1 commit into from
Jan 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,40 @@ If your application includes many HTML Components or certain HTML Components are

### `url`

#### `{Boolean}`

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

#### `{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
6 changes: 4 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export default function loader(html, map, meta) {

// HTML URL Plugin
if (options.url) {
plugins.push(urls());
plugins.push(urls(options));
}

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

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

// Reuse HTML AST (PostHTML AST)
// (e.g posthtml-loader) to avoid HTML reparsing
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": {
"anyOf": [
Expand Down
34 changes: 23 additions & 11 deletions src/plugins/url.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
/* eslint-disable */
// External URL (Protocol URL)
const URL = /^\w+:\/\//;
// TODO(michael-ciniawsky)
// extend with custom matchers
// e.g <custom-element custom-src="">
// (`options.url.filter`) (#159)
// Attributes Matcher
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) => {
return URL.test(url) || url.startsWith('//');
const filter = (url, options) => {
if (URL.test(url)) {
return true;
}

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

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 = {}) {
Expand All @@ -30,7 +41,7 @@ export default function (options = {}) {
}

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

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

return node;
}

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

Expand All @@ -72,7 +84,7 @@ export default function (options = {}) {
// <tag srcset="path/to/file.ext">
if (node.attrs.srcset) {
// Ignore external && filtered urls
if (filter(node.attrs.srcset)) {
if (filter(node.attrs.srcset, options)) {
return node;
}

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;
107 changes: 106 additions & 1 deletion test/options/__snapshots__/url.test.js.snap
Original file line number Diff line number Diff line change
@@ -1,6 +1,65 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Options url {Boolean} 1`] = `
exports[`Options url {Boolean} - false 1`] = `
"// HTML Imports


// HTML Exports


// HTML
export default \`<!DOCTYPE html>
<html lang=\\"en\\">
<head>
<meta charset=\\"utf-8\\">
<title>HTML Loader</title>
<!-- Ignore -->
<link href=\\"//file.css\\">
<link href=\\"//cdn.com/file.css\\">
<link href=\\"http://cdn.com/file.css\\">
<link href=\\"https://cdn.com/file.css\\">
<!-- Transform -->
<link href=\\"./file.css\\">
<link href=\\"/file.css\\">
</head>
<body>
<!-- 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\\">

​<picture>
<source srcset=\\"./file.svg\\" type=\\"image/svg+xml\\">
<img src=\\"./file.png\\" alt=\\"Image\\">
</picture>

<video width=\\"320\\" height=\\"240\\" controls=\\"\\">
<source src=\\"./file.mp4\\" type=\\"video/mp4\\">
<source src=\\"./file.ogg\\" type=\\"video/ogg\\">
Your browser does not support the <code>video<code> element.
</code></code></video>

<audio src=\\"./file.mp3\\" autoplay=\\"\\"></audio>

<audio controls=\\"controls\\">
Your browser does not support the <code>audio</code> element.
<source src=\\"./file.wav\\" type=\\"audio/wav\\">
</audio>

<audio src=\\"./file.ogg\\">
<track kind=\\"captions\\" src=\\"./file.en.vtt\\" srclang=\\"en\\" label=\\"English\\">
<track kind=\\"captions\\" src=\\"./file.sv.vtt\\" srclang=\\"sv\\" label=\\"Svenska\\">
</audio>
</body>
</html>
\`"
`;

exports[`Options url {Boolean} - true - (default) 1`] = `
"// HTML Imports
import HTML__URL__0 from './file.css';
import HTML__URL__1 from '/file.css';
Expand Down Expand Up @@ -71,3 +130,49 @@ export default \`<!DOCTYPE html>
</html>
\`"
`;

exports[`Options url {Function} 1`] = `
"// HTML Imports
import HTML__URL__0 from './file.png';
import HTML__URL__1 from '/file.png';


// HTML Exports


// HTML
export default \`<!-- 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=\\"\${HTML__URL__0}\\">
<img src=\\"\${HTML__URL__1}\\">
<!-- Filter -->
<img src=\\"./filter/file.png\\">
<img src=\\"/filter/file.png\\">\`"
`;

exports[`Options url {RegExp} 1`] = `
"// HTML Imports
import HTML__URL__0 from './file.png';
import HTML__URL__1 from '/file.png';


// HTML Exports


// HTML
export default \`<!-- 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=\\"\${HTML__URL__0}\\">
<img src=\\"\${HTML__URL__1}\\">
<!-- Filter -->
<img src=\\"./filter/file.png\\">
<img src=\\"/filter/file.png\\">\`"
`;
52 changes: 51 additions & 1 deletion test/options/url.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import webpack from '../helpers/compiler';

describe('Options', () => {
describe('url', () => {
test('{Boolean}', async () => {
test('{Boolean} - true - (default)', async () => {
const config = {
loader: {
test: /\.html$/,
Expand All @@ -18,5 +18,55 @@ describe('Options', () => {

expect(source).toMatchSnapshot();
});

test('{Boolean} - false', async () => {
const config = {
loader: {
test: /\.html$/,
options: {
url: false,
},
},
};

const stats = await webpack('options/url/fixture.js', config);
const { source } = stats.toJson().modules[1];

expect(source).toMatchSnapshot();
});

test('{RegExp}', async () => {
const config = {
loader: {
test: /\.html$/,
options: {
url: /filter/,
},
},
};

const stats = await webpack('options/url/filter/fixture.js', config);
const { source } = stats.toJson().modules[1];

expect(source).toMatchSnapshot();
});

test('{Function}', async () => {
const config = {
loader: {
test: /\.html$/,
options: {
url(url) {
return /filter/.test(url);
},
},
},
};

const stats = await webpack('options/url/filter/fixture.js', config);
const { source } = stats.toJson().modules[1];

expect(source).toMatchSnapshot();
});
});
});