From c7818083fff6613fdbced81f96b86fcc987f1d89 Mon Sep 17 00:00:00 2001 From: simonihmig Date: Fri, 10 Dec 2021 13:56:40 +0100 Subject: [PATCH] Append styles imported in JS to end of `document.head` This addresses the issue raised in #1033 ("2. Import app.scss from app.js") that link tags added through imports of CSS in JS get added next to the script entrypoint (at the body's end) rather than to the document's head, causing a FOUC in FastBoot rendered pages. --- packages/core/src/html-placeholder.ts | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/core/src/html-placeholder.ts b/packages/core/src/html-placeholder.ts index 1e04b4c99..b6b2a5360 100644 --- a/packages/core/src/html-placeholder.ts +++ b/packages/core/src/html-placeholder.ts @@ -32,10 +32,14 @@ export default class Placeholder { } } - insert(node: Node) { + insert(node: Node): void { this.end.parentElement.insertBefore(node, this.end); } + appendToHead(node: Node): void { + this.end.ownerDocument.head.appendChild(node); + } + isScript(): boolean { return this.target.tagName === 'SCRIPT'; } @@ -70,12 +74,20 @@ export default class Placeholder { let newTag = this.end.ownerDocument.createElement('link'); newTag.href = href; newTag.rel = 'stylesheet'; - this.insert(newTag); - this.insertNewline(); + + if (this.isScript()) { + // Add dynamic styles from scripts to the bottom of the head, and not to where the script was, + // to prevent FOUC when pre-rendering (FastBoot) + this.appendToHead(newTag); + } else { + // Keep the new style in the same place as the original one + this.insert(newTag); + } + this.insertNewline(newTag as InDOMNode); } - insertNewline() { - this.end.parentElement.insertBefore(this.end.ownerDocument.createTextNode('\n'), this.end); + insertNewline(node: InDOMNode = this.end): void { + node.parentElement.insertBefore(node.ownerDocument.createTextNode('\n'), node); } }