UNPKG

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