Skip to content

Commit 888645c

Browse files
refactor: improve message handling (result.messages`)
1 parent 00e5686 commit 888645c

File tree

10 files changed

+188
-119
lines changed

10 files changed

+188
-119
lines changed
File renamed without changes.

src/index.js

Lines changed: 69 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
/* eslint-disable */
2+
import schema from './options.json';
23
import { getOptions } from 'loader-utils';
34
import validateOptions from 'schema-utils';
45

56
import posthtml from 'posthtml';
6-
import urls from './lib/plugins/url';
7-
import imports from './lib/plugins/import';
7+
import urls from './plugins/url';
8+
import imports from './plugins/import';
89
import minifier from 'htmlnano';
910

10-
import schema from './options.json';
11-
import LoaderError from './lib/Error';
11+
import LoaderError from './Error';
1212

1313
// Loader Defaults
14-
const defaults = {
14+
const DEFAULTS = {
1515
url: true,
1616
import: true,
1717
minimize: false,
@@ -20,71 +20,98 @@ 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
2731
const cb = this.async();
2832
const file = this.resourcePath;
2933

30-
// HACK add Module.type
31-
this._module.type = 'text/html';
32-
33-
const template = options.template
34+
options.template = options.template
3435
? typeof options.template === 'string' ? options.template : '_'
3536
: false;
3637

3738
const plugins = [];
3839

3940
if (options.url) plugins.push(urls());
40-
if (options.import) plugins.push(imports({ template }));
41+
if (options.import) plugins.push(imports(options));
4142
// TODO(michael-ciniawsky)
42-
// <imports src=""./file.html"> aren't minified (#160)
43+
// <imports src=""./file.html"> aren't minified (options.template) (#160)
4344
if (options.minimize) plugins.push(minifier());
4445

45-
// Reuse HTML AST (PostHTML AST) if available
46+
// Reuse HTML AST (PostHTML AST)
4647
// (e.g posthtml-loader) to avoid HTML reparsing
47-
if (meta && meta.ast && meta.ast.type === 'posthtml') {
48-
html = meta.ast.root;
48+
if (meta) {
49+
if (meta.ast && meta.ast.type === 'posthtml') {
50+
const { ast } = meta.ast;
51+
52+
html = ast.root;
53+
}
4954
}
5055

5156
posthtml(plugins)
5257
.process(html, { from: file, to: file })
5358
.then(({ html, messages }) => {
54-
let urls = messages[0];
55-
let imports = messages[1];
56-
57-
// TODO(michael-ciniawsky) revisit
59+
if (meta && meta.messages) {
60+
messages = messages.concat(meta.messages)
61+
}
62+
63+
const imports = messages
64+
.filter((msg) => msg.type === 'import' ? msg : false)
65+
.reduce((imports, msg) => {
66+
try {
67+
msg = typeof msg.import === 'function'
68+
? msg.import()
69+
: msg.import
70+
71+
imports += msg;
72+
} catch (err) {
73+
// TODO(michael-ciniawsky)
74+
// revisit
75+
this.emitError(err)
76+
}
77+
78+
return imports
79+
}, '// HTML Imports\n')
80+
81+
const exports = messages
82+
.filter((msg) => msg.type === 'export' ? msg : false)
83+
.reduce((exports, msg) => {
84+
try {
85+
msg = typeof msg.export === 'function'
86+
? msg.import()
87+
: msg.import
88+
89+
exports += msg;
90+
} catch (err) {
91+
// TODO(michael-ciniawsky)
92+
// revisit
93+
this.emitError(err)
94+
}
95+
96+
return exports;
97+
}, '// HTML Exports\n')
98+
99+
// TODO(michael-ciniawsky)
100+
// replace with post5/core
101+
// HACK
58102
// Ensure to cleanup/reset messages
59103
// during recursive resolving of imports
60104
messages.length = 0;
61105

62-
// <img src="./file.png">
63-
// => import HTML__URL__${idx} from './file.png';
64-
if (urls) {
65-
urls = Object.keys(urls)
66-
.map((url) => `import ${url} from '${urls[url]}';`)
67-
.join('\n');
68-
}
69-
// <import src="./file.html">
70-
// => import HTML__IMPORT__${idx} from './file.html';
71-
if (imports) {
72-
imports = Object.keys(imports)
73-
.map((i) => `import ${i} from '${imports[i]}';`)
74-
.join('\n');
75-
}
76-
77106
html = options.template
78-
? `function (${template}) { return \`${html}\`; }`
79-
: `\`${html}\``;
107+
? `// HTML\nexport default function (${options.template}) { return \`${html}\`; }`
108+
: `// HTML\nexport default \`${html}\``;
80109

81110
const result = [
82-
urls ? `// HTML URLs\n${urls}\n` : false,
83-
imports ? `// HTML Imports\n${imports}\n` : false,
84-
`// HTML\nexport default ${html}`,
85-
]
86-
.filter(Boolean)
87-
.join('\n');
111+
`${imports}\n`,
112+
`${exports}\n`,
113+
html,
114+
].join('\n');
88115

89116
cb(null, result);
90117

src/lib/plugins/import.js

Lines changed: 0 additions & 44 deletions
This file was deleted.

src/plugins/import.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/* eslint-disable */
2+
// External URL (Protocol URL)
3+
const URL = /^\w+:\/\//;
4+
const TAGS = [ { tag: 'import' }, { tag: 'include' } ];
5+
// TODO(michael-ciniawsky)
6+
// add filter method for urls (e.g `options.import`) (#158)
7+
const filter = (url) => {
8+
return URL.test(url) || url.startsWith('//');
9+
};
10+
11+
export default function (options = {}) {
12+
return function (ast) {
13+
let idx = 0;
14+
15+
ast.match(TAGS, (node) => {
16+
if (node.attrs && node.attrs.src) {
17+
// Remove <import>/<include> tag
18+
node.tag = false;
19+
20+
// Ignore external && filtered urls
21+
if (filter(node.attrs.src, options)) {
22+
return false;
23+
}
24+
25+
// Add content placeholders to HTML
26+
node.content = options.template
27+
? '${' + `HTML__IMPORT__${idx}(${options.template})` + '}'
28+
: '${' + `HTML__IMPORT__${idx}` + '}';
29+
30+
// Add HTML Import to result.messages
31+
ast.messages.push({
32+
type: 'import',
33+
plugin: 'poshtml-import',
34+
import: `import HTML__IMPORT__${idx} from '${node.attrs.src}';\n`
35+
})
36+
37+
idx++;
38+
}
39+
40+
return node;
41+
});
42+
43+
return ast;
44+
};
45+
}
Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,46 @@
11
/* eslint-disable */
22
// External URL (Protocol URL)
3-
const TEST_URL = /^\w+:\/\//;
3+
const URL = /^\w+:\/\//;
44
// TODO(michael-ciniawsky)
55
// extend with custom matchers
66
// e.g <custom-element custom-src="">
77
// (`options.url.filter`) (#159)
8-
const MATCH_ATTRS = [
8+
const ATTRS = [
99
{ attrs: { src: true } },
1010
{ attrs: { href: true } },
1111
{ attrs: { srcset: true } },
1212
];
1313

1414
// TODO(michael-ciniawsky)
1515
// add filter method for urls (e.g `options.url.filter`) (#158)
16-
const filter = (url, options) => {
17-
return TEST_URL.test(url) || url.startsWith('//');
16+
const filter = (url) => {
17+
return URL.test(url) || url.startsWith('//');
1818
};
1919

20-
export default function(options = {}) {
21-
return function(tree) {
20+
export default function (options = {}) {
21+
return function (ast) {
2222
let idx = 0;
23-
const urls = {};
2423

25-
tree.match(MATCH_ATTRS, (node) => {
24+
ast.match(ATTRS, (node) => {
2625
// <tag src="path/to/file.ext">
2726
if (node.attrs.src) {
2827
// Ignore <import>/<include
29-
if (node.tag === 'import' || node.tag === 'include') return node;
28+
if (node.tag === 'import' || node.tag === 'include') {
29+
return node;
30+
}
31+
3032
// Ignore external && filtered urls
31-
if (filter(node.attrs.src, options)) return node;
32-
// Add url to messages.urls
33-
urls[`HTML__URL__${idx}`] = node.attrs.src;
33+
if (filter(node.attrs.src)) {
34+
return node;
35+
}
36+
37+
// Add HTML URL to result.messages
38+
ast.messages.push({
39+
type: 'import',
40+
plugin: 'poshtml-url',
41+
import: `import HTML__URL__${idx} from '${node.attrs.src}';\n`
42+
})
43+
3444
// Add content placeholders to HTML
3545
node.attrs.src = '${' + `HTML__URL__${idx}` + '}';
3646

@@ -41,9 +51,17 @@ export default function(options = {}) {
4151
// <tag href="path/to/file.ext">
4252
if (node.attrs.href) {
4353
// Ignore external && filtered urls
44-
if (filter(node.attrs.href, options)) return node;
45-
// Add url to messages.urls
46-
urls[`HTML__URL__${idx}`] = node.attrs.href;
54+
if (filter(node.attrs.href)) {
55+
return node;
56+
}
57+
58+
// Add HTML URL to result.messages
59+
ast.messages.push({
60+
type: 'import',
61+
plugin: 'poshtml-url',
62+
import: `import HTML__URL__${idx} from '${node.attrs.href}';\n`
63+
})
64+
4765
// Add content placeholder to HTML
4866
node.attrs.href = '${' + `HTML__URL__${idx}` + '}';
4967

@@ -54,9 +72,17 @@ export default function(options = {}) {
5472
// <tag srcset="path/to/file.ext">
5573
if (node.attrs.srcset) {
5674
// Ignore external && filtered urls
57-
if (filter(node.attrs.srcset, options)) return node;
58-
// Add url to messages.urls
59-
urls[`HTML__URL__${idx}`] = node.attrs.srcset;
75+
if (filter(node.attrs.srcset)) {
76+
return node;
77+
}
78+
79+
// Add HTML URL to result.messages
80+
ast.messages.push({
81+
type: 'import',
82+
plugin: 'poshtml-url',
83+
import: `import HTML__URL__${idx} from '${node.attrs.srcset}';\n`
84+
})
85+
6086
// Add content placeholder to HTML
6187
node.attrs.srcset = '${' + `HTML__URL__${idx}` + '}';
6288

@@ -66,9 +92,6 @@ export default function(options = {}) {
6692
}
6793
});
6894

69-
// Add urls to result.messages
70-
tree.messages.push(urls);
71-
72-
return tree;
95+
return ast;
7396
};
7497
}

test/__snapshots__/loader.test.js.snap

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

33
exports[`Loader Defaults 1`] = `
4-
"// HTML URLs
4+
"// HTML Imports
55
import HTML__URL__0 from './file.png';
6-
7-
// HTML Imports
86
import HTML__IMPORT__0 from './file.html';
97
8+
9+
// HTML Exports
10+
11+
1012
// HTML
1113
export default \`<!DOCTYPE html>
1214
<html lang=\\"en\\">

test/options/__snapshots__/import.test.js.snap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ import HTML__IMPORT__1 from '/2.html';
77
import HTML__IMPORT__2 from './1.html';
88
import HTML__IMPORT__3 from '/2.html';
99
10+
11+
// HTML Exports
12+
13+
1014
// HTML
1115
export default \`<!DOCTYPE html>
1216
<html lang=\\"en\\">

0 commit comments

Comments
 (0)