Skip to content

Commit

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

#### `{Boolean}`

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

#### `{String}`

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

#### `{RegExp}`

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

#### `{Function}`

**webpack.config.js**
```js
{
loader: 'html-loader',
options: {
import (url) {
return /filter/.test(url)
}
}
}
```
Expand Down
28 changes: 20 additions & 8 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,21 @@ 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 }));

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

// HTML IMPORT Plugin
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 +66,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 +77,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 +87,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
51 changes: 38 additions & 13 deletions src/lib/plugins/import.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,56 @@
/* eslint-disable */
// External URL (Protocol URL)
const TEST_URL = /^\w+:\/\//;
// External URL (Protocol)
const URL = /^\w+:\/\//;
const TAGS = [
{ tag: 'import' },
{ tag: 'include' }
]

// TODO(michael-ciniawsky)
// add filter method for urls (e.g `options.import`) (#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.import === 'string') {
return url.includes(options.import);
}

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

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

return false;
};

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

// HTML Imports
const imports = {};

tree.match([{ tag: 'import' }, { tag: 'include' }], (node) => {
tree.match(TAGS, (node) => {
if (node.attrs && node.attrs.src) {
// Remove <import>/<include> tag
node.tag = false;

// TODO(michael-ciniawky)
// add warning about invalid use of external urls within <import> (#?)
// Ignore external && filtered URLs
if (filter(node.attrs.src, options)) {
return;
}

// Ignore external && filtered urls
if (filter(node.attrs.src, options)) return;
// Add url to messages.imports
// Add URL to result.messages.imports
imports[`HTML__IMPORT__${idx}`] = node.attrs.src;
// Add content placeholders to HTML

// Add URL content placeholders to HTML
node.content = options.template
? '${' + `HTML__IMPORT__${idx}(${options.template})` + '}'
: '${' + `HTML__IMPORT__${idx}` + '}';
Expand All @@ -36,7 +61,7 @@ export default function(options = {}) {
return node;
});

// Add imports to result.messages
// Add HTML Imports to result.messages
tree.messages.push(imports);

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 @@ -5,7 +5,12 @@
"type": "boolean"
},
"import": {
"type": "boolean"
"anyOf": [
{ "type": "string" },
{ "type": "boolean" },
{ "instanceof": "RegExp" },
{ "instanceof": "Function" }
]
},
"template": {
"type": [ "boolean", "string" ]
Expand Down
18 changes: 18 additions & 0 deletions test/fixtures/options/import/filter/fixture.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!-- Ignore -->
<import src="//file.html"></import>
<import src="//cdn.com/file.html"></import>
<import src="http://cdn.com/file.html"></import>
<import src="https://cdn.com/file.html"></import>
<!-- Transform -->
<import src="./1.html"></import>
<import src="/2.html"></import>
<!-- Filter (Ignore) -->
<import src="./filter/1.html"></import>
<import src="/filter/2.html"></import>
<!-- Transform -->
<include src="./1.html"></include>
<include src="/2.html"></include>
<!-- Filter (Ignore) -->
<include src="./filter/1.html"></include>
<include src="/filter/2.html"></include>

3 changes: 3 additions & 0 deletions test/fixtures/options/import/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;
114 changes: 113 additions & 1 deletion test/options/__snapshots__/import.test.js.snap
Original file line number Diff line number Diff line change
@@ -1,6 +1,31 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Options import {Boolean} 1`] = `
exports[`Options import {Boolean} - false 1`] = `
"// HTML
export default \`<!DOCTYPE html>
<html lang=\\"en\\">
<head>
<meta charset=\\"utf-8\\">
<title>HTML Loader</title>
</head>
<body>
<!-- Ignore -->
<import src=\\"//file.html\\"></import>
<import src=\\"//cdn.com/file.html\\"></import>
<import src=\\"http://cdn.com/file.html\\"></import>
<import src=\\"https://cdn.com/file.html\\"></import>
<!-- Transform -->
<import src=\\"./1.html\\"></import>
<import src=\\"/2.html\\"></import>
<include src=\\"./1.html\\"></include>
<include src=\\"/2.html\\"></include>
</body>
</html>
\`"
`;
exports[`Options import {Boolean} - true - default 1`] = `
"// HTML Imports
import HTML__IMPORT__0 from './1.html';
import HTML__IMPORT__1 from '/2.html';
Expand Down Expand Up @@ -28,5 +53,92 @@ export default \`<!DOCTYPE html>
\${HTML__IMPORT__3}
</body>
</html>
\`"
`;
exports[`Options import {Function} 1`] = `
"// HTML Imports
import HTML__IMPORT__0 from './1.html';
import HTML__IMPORT__1 from '/2.html';
import HTML__IMPORT__2 from './1.html';
import HTML__IMPORT__3 from '/2.html';
// HTML
export default \`<!-- Ignore -->
<!-- Transform -->
\${HTML__IMPORT__0}
\${HTML__IMPORT__1}
<!-- Filter (Ignore) -->
<!-- Transform -->
\${HTML__IMPORT__2}
\${HTML__IMPORT__3}
<!-- Filter (Ignore) -->
\`"
`;
exports[`Options import {RegExp} 1`] = `
"// HTML Imports
import HTML__IMPORT__0 from './1.html';
import HTML__IMPORT__1 from '/2.html';
import HTML__IMPORT__2 from './1.html';
import HTML__IMPORT__3 from '/2.html';
// HTML
export default \`<!-- Ignore -->
<!-- Transform -->
\${HTML__IMPORT__0}
\${HTML__IMPORT__1}
<!-- Filter (Ignore) -->
<!-- Transform -->
\${HTML__IMPORT__2}
\${HTML__IMPORT__3}
<!-- Filter (Ignore) -->
\`"
`;
exports[`Options import {String} 1`] = `
"// HTML Imports
import HTML__IMPORT__0 from './1.html';
import HTML__IMPORT__1 from '/2.html';
import HTML__IMPORT__2 from './1.html';
import HTML__IMPORT__3 from '/2.html';
// HTML
export default \`<!-- Ignore -->
<!-- Transform -->
\${HTML__IMPORT__0}
\${HTML__IMPORT__1}
<!-- Filter (Ignore) -->
<!-- Transform -->
\${HTML__IMPORT__2}
\${HTML__IMPORT__3}
<!-- Filter (Ignore) -->
\`"
`;
Loading

0 comments on commit db40c7e

Please sign in to comment.