/
HTMLPackager.js
104 lines (87 loc) 路 2.48 KB
/
HTMLPackager.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
const Packager = require('./Packager');
const posthtml = require('posthtml');
const path = require('path');
const urlJoin = require('../utils/urlJoin');
// https://www.w3.org/TR/html5/dom.html#metadata-content-2
const metadataContent = new Set([
'base',
'link',
'meta',
'noscript',
'script',
'style',
'template',
'title'
]);
class HTMLPackager extends Packager {
static shouldAddAsset() {
// We cannot combine multiple HTML files together - they should be written as separate bundles.
return false;
}
async addAsset(asset) {
let html = asset.generated.html || '';
// Find child bundles that have JS or CSS sibling bundles,
// add them to the head so they are loaded immediately.
let siblingBundles = Array.from(this.bundle.childBundles)
.reduce((p, b) => p.concat([...b.siblingBundles.values()]), [])
.filter(b => b.type === 'css' || b.type === 'js');
if (siblingBundles.length > 0) {
html = posthtml(
this.insertSiblingBundles.bind(this, siblingBundles)
).process(html, {sync: true}).html;
}
await this.write(html);
}
addBundlesToTree(bundles, tree) {
const head = find(tree, 'head');
if (head) {
const content = head.content || (head.content = []);
content.push(...bundles);
return;
}
const html = find(tree, 'html');
const content = html ? html.content || (html.content = []) : tree;
const index = findBundleInsertIndex(content);
content.splice(index, 0, ...bundles);
}
insertSiblingBundles(siblingBundles, tree) {
const bundles = [];
for (let bundle of siblingBundles) {
if (bundle.type === 'css') {
bundles.push({
tag: 'link',
attrs: {
rel: 'stylesheet',
href: urlJoin(this.options.publicURL, path.basename(bundle.name))
}
});
} else if (bundle.type === 'js') {
bundles.push({
tag: 'script',
attrs: {
src: urlJoin(this.options.publicURL, path.basename(bundle.name))
}
});
}
}
this.addBundlesToTree(bundles, tree);
}
}
function find(tree, tag) {
let res;
tree.match({tag}, node => {
res = node;
return node;
});
return res;
}
function findBundleInsertIndex(content) {
for (let index = 0; index < content.length; index++) {
const node = content[index];
if (node && node.tag && !metadataContent.has(node.tag)) {
return index;
}
}
return 0;
}
module.exports = HTMLPackager;