From 5a3732296f8ca1c6c46fc9f8f3de54f67221fa2d Mon Sep 17 00:00:00 2001 From: Brandon Smith Date: Mon, 29 Jan 2018 02:19:53 -0500 Subject: [PATCH] Inject HTML tag if missing (#654) * Inject HTML tag if missing * Update sibling bundle node insert logic --- src/packagers/HTMLPackager.js | 51 ++++++++++++++----- test/html.js | 42 ++++++++++++++- .../html-css-optional-elements/index.css | 3 ++ .../html-css-optional-elements/index.html | 3 ++ .../html-css-optional-elements/index.js | 2 + .../html-css-optional-elements/other.js | 1 + 6 files changed, 87 insertions(+), 15 deletions(-) create mode 100644 test/integration/html-css-optional-elements/index.css create mode 100644 test/integration/html-css-optional-elements/index.html create mode 100644 test/integration/html-css-optional-elements/index.js create mode 100644 test/integration/html-css-optional-elements/other.js diff --git a/src/packagers/HTMLPackager.js b/src/packagers/HTMLPackager.js index 2a6fb069adc..511385d02a3 100644 --- a/src/packagers/HTMLPackager.js +++ b/src/packagers/HTMLPackager.js @@ -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 || ''; @@ -22,27 +34,27 @@ 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', @@ -50,7 +62,7 @@ class HTMLPackager extends Packager { } }); } else if (bundle.type === 'js') { - head.content.push({ + bundles.push({ tag: 'script', attrs: { src: urlJoin(this.options.publicURL, path.basename(bundle.name)) @@ -58,6 +70,8 @@ class HTMLPackager extends Packager { }); } } + + this.addBundlesToTree(bundles, tree); } } @@ -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; diff --git a/test/html.js b/test/html.js index af313a1e94c..eec972ad4a2 100644 --- a/test/html.js +++ b/test/html.js @@ -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, { @@ -169,7 +169,7 @@ describe('html', function() { let html = fs.readFileSync(__dirname + '/dist/index.html'); assert( - /<\/head>/.test( + /\s*\s*/.test( html ) ); @@ -210,6 +210,44 @@ describe('html', function() { assert(/ +

Hello world

+ diff --git a/test/integration/html-css-optional-elements/index.js b/test/integration/html-css-optional-elements/index.js new file mode 100644 index 00000000000..8a604206cf5 --- /dev/null +++ b/test/integration/html-css-optional-elements/index.js @@ -0,0 +1,2 @@ +require('./index.css'); +alert('Hi'); diff --git a/test/integration/html-css-optional-elements/other.js b/test/integration/html-css-optional-elements/other.js new file mode 100644 index 00000000000..69aa795cedd --- /dev/null +++ b/test/integration/html-css-optional-elements/other.js @@ -0,0 +1 @@ +alert('Other');