Repository: Polymer/vulcanize
Pull request #399 (2016-11-16 04:12:39)

Stop moving links with certain rels out of the head tag.
<!--
  Thanks for the PR!

  If this change has a user visible change (including
  bug fixes, new features, etc) please describe the change in
  CHANGELOG.md.

  If the change is an entirely package-internal reshuffling/refactoring
  should the change not be described in the CHANGELOG.

  Consider also updating the README.

  More info: http://keepachangelog.com/en/0.3.0/
 -->

 - [x] CHANGELOG.md has been updated

Links that must remain in the head tag in order to be read by the browser and that have nothing to do with HTML imports are now left alone.  This allows vulcanized web apps that don't use app-shell to specify favicons, web app manifests, and prefetch hints.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index eebdcf0..e02c51a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 
 <!-- New PRs should document their changes here. -->
 
+- Stop moving links with certain rels out of the head tag to avoid breaking
+  favicons, manifests, and other such features.
+
 ## 1.14.11 - 2016-04-11
 - Radically simpler inlining design. Move all imports and scripts into document
   body, replace imports inline.
diff --git a/lib/vulcan.js b/lib/vulcan.js
index d335032..5c4e5e3 100644
--- a/lib/vulcan.js
+++ b/lib/vulcan.js
@@ -182,7 +182,16 @@ Vulcan.prototype = {
       dom5.predicates.hasTagName('link')
     ),
     dom5.predicates.NOT(
-      matchers.polymerExternalStyle
+      dom5.predicates.OR(
+        matchers.polymerExternalStyle,
+        dom5.predicates.hasAttrValue('rel', 'dns-prefetch'),
+        dom5.predicates.hasAttrValue('rel', 'icon'),
+        dom5.predicates.hasAttrValue('rel', 'manifest'),
+        dom5.predicates.hasAttrValue('rel', 'preconnect'),
+        dom5.predicates.hasAttrValue('rel', 'prefetch'),
+        dom5.predicates.hasAttrValue('rel', 'preload'),
+        dom5.predicates.hasAttrValue('rel', 'prerender')
+      )
     )
   ),
 


Test patch:
diff --git a/test/html/default.html b/test/html/default.html
index ab4559a..b722c55 100644
--- a/test/html/default.html
+++ b/test/html/default.html
@@ -11,6 +11,7 @@
 <html lang="en">
 <head>
   <meta charset="UTF-8">
+  <link rel="icon" href="/favicon.ico">
   <link rel="stylesheet" href="imports/regular-style.css">
   <link rel="import" href="imports/simple-import.html">
   <link rel="import" href="imports/simple-import.html">
diff --git a/test/test.js b/test/test.js
index 073c552..6a48832 100644
--- a/test/test.js
+++ b/test/test.js
@@ -313,6 +313,21 @@ suite('Vulcan', function() {
       });
     });
 
+    test('non-import links are left in head', function(done) {
+      var nonImportLinks = preds.AND(
+        preds.hasTagName('link'),
+        preds.NOT(preds.hasAttrValue('rel', 'import'))
+      );
+      process(inputPath, function(err, doc) {
+        if (err) {
+          return done(err);
+        }
+        var head = dom5.query(doc, preds.hasTagName('head'));
+        assert.isAbove(dom5.queryAll(head, nonImportLinks).length, 0);
+        done();
+      });
+    });
+
     test('svg is nested correctly', function(done) {
       process(inputPath, function(err, doc) {
         if (err) {
@@ -796,7 +811,7 @@ suite('Vulcan', function() {
         }
         var links = dom5.queryAll(doc, linkMatcher);
         // one duplicate import is removed
-        assert.equal(links.length, 2);
+        assert.equal(links.length, 3);
         done();
       };
       process('test/html/default.html', callback, options);