Skip to content

Commit

Permalink
Inject HTML tag if missing (#654)
Browse files Browse the repository at this point in the history
* Inject HTML tag if missing

* Update sibling bundle node insert logic
  • Loading branch information
brandon93s authored and devongovett committed Jan 29, 2018
1 parent 93315f2 commit 5a37322
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 15 deletions.
51 changes: 38 additions & 13 deletions src/packagers/HTMLPackager.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@ 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 {
async addAsset(asset) {
let html = asset.generated.html || '';
Expand All @@ -22,42 +34,44 @@ class HTMLPackager extends Packager {
await this.dest.write(html);
}

getHeadContent(tree) {
let head = find(tree, 'head');
if (!head) {
let html = find(tree, 'html');
head = {tag: 'head'};
html.content.unshift(head);
addBundlesToTree(bundles, tree) {
const head = find(tree, 'head');
if (head) {
const content = head.content || (head.content = []);
content.push(...bundles);
return;
}

if (!head.content) {
head.content = [];
}
const html = find(tree, 'html');
const content = html ? html.content || (html.content = []) : tree;
const index = findBundleInsertIndex(content);

return head;
content.splice(index, 0, ...bundles);
}

insertSiblingBundles(siblingBundles, tree) {
let head = this.getHeadContent(tree);
const bundles = [];

for (let bundle of siblingBundles) {
if (bundle.type === 'css') {
head.content.push({
bundles.push({
tag: 'link',
attrs: {
rel: 'stylesheet',
href: urlJoin(this.options.publicURL, path.basename(bundle.name))
}
});
} else if (bundle.type === 'js') {
head.content.push({
bundles.push({
tag: 'script',
attrs: {
src: urlJoin(this.options.publicURL, path.basename(bundle.name))
}
});
}
}

this.addBundlesToTree(bundles, tree);
}
}

Expand All @@ -71,4 +85,15 @@ function find(tree, tag) {
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;
42 changes: 40 additions & 2 deletions test/html.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ describe('html', function() {
);
});

it('should insert a HEAD element if needed when adding CSS bundles', async function() {
it('should insert sibling bundles before body element if no HEAD', async function() {
let b = await bundle(__dirname + '/integration/html-css-head/index.html');

assertBundleTree(b, {
Expand All @@ -169,7 +169,7 @@ describe('html', function() {

let html = fs.readFileSync(__dirname + '/dist/index.html');
assert(
/<head><link rel="stylesheet" href="[/\\]{1}dist[/\\]{1}[a-f0-9]+\.css"><\/head>/.test(
/<html>\s*<link rel="stylesheet" href="[/\\]{1}dist[/\\]{1}[a-f0-9]+\.css">\s*<body>/.test(
html
)
);
Expand Down Expand Up @@ -210,6 +210,44 @@ describe('html', function() {
assert(/<script src="[/\\]{1}dist[/\\]{1}[a-f0-9]+\.js">/.test(html));
});

it('should insert sibling bundles at correct location in tree when optional elements are absent', async function() {
let b = await bundle(
__dirname + '/integration/html-css-optional-elements/index.html'
);

assertBundleTree(b, {
name: 'index.html',
assets: ['index.html'],
childBundles: [
{
type: 'js',
assets: ['index.js', 'index.css'],
childBundles: [
{
type: 'css',
assets: ['index.css'],
childBundles: []
},
{
type: 'map'
}
]
},
{
type: 'js',
assets: ['other.js']
}
]
});

let html = fs.readFileSync(__dirname + '/dist/index.html');
assert(
/<\/script>\s*<link rel="stylesheet" href="[/\\]{1}dist[/\\]{1}[a-f0-9]+\.css"><h1>Hello/.test(
html
)
);
});

it('should minify HTML in production mode', async function() {
await bundle(__dirname + '/integration/htmlnano/index.html', {
production: true
Expand Down
3 changes: 3 additions & 0 deletions test/integration/html-css-optional-elements/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body {
background: red;
}
3 changes: 3 additions & 0 deletions test/integration/html-css-optional-elements/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script src="other.js"></script>
<h1>Hello world</h1>
<script src="index.js"></script>
2 changes: 2 additions & 0 deletions test/integration/html-css-optional-elements/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
require('./index.css');
alert('Hi');
1 change: 1 addition & 0 deletions test/integration/html-css-optional-elements/other.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
alert('Other');

0 comments on commit 5a37322

Please sign in to comment.