Skip to content

Commit

Permalink
Merge pull request #2 from dario-piotrowicz/main
Browse files Browse the repository at this point in the history
fix: ensure scripts and styles inserted with their entire text content
  • Loading branch information
DylanPiercey authored Sep 16, 2022
2 parents 51650e1 + b5c015e commit 4fe4b5b
Show file tree
Hide file tree
Showing 11 changed files with 83 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Embedded App.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Embedded App.
<script></script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Embedded App.
<script>
scriptValues = ["a", "b"];
</script>
After Script.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Embedded App.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Embedded App. <style></style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Embedded App.
<style>
h1 {
color: red;
}
</style>
After Styles.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h1>H1</h1>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<h1>H1</h1>
<h2>H2</h2>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<h1>H1</h1>
<h2>H2</h2>
<h3>H3</h3>
28 changes: 28 additions & 0 deletions src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ declare const inlineScriptValues: unknown[];

it("stream-text", fixture(["Hello", "World"]));

it("stream-elements", fixture(["<h1>H1</h1>", "<h2>H2</h2>", "<h3>H3</h3>"]));

it(
"blocking-scripts",
fixture([
Expand Down Expand Up @@ -118,3 +120,29 @@ After blocking.`,
},
])
);

it(
"inline-scripts",
fixture([
"Embedded App.",
'<script>scriptValues = ["a',
'", "b"];</script>',
"After Script.",
async (page) => {
assert.deepStrictEqual(await page.evaluate(() => scriptValues), [
"a",
"b",
]);
},
])
);

it(
"inline-styles",
fixture([
"Embedded App. ",
"<style> h1 { colo",
"r: red; } </style>",
" After Styles.",
])
);
36 changes: 32 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ export = function writableDOM(
let scanNode: Node | null = null;
let resolve: void | (() => void);
let isBlocked = false;
let inlineHostNode: Node | null = null;

return {
write(chunk: string) {
doc.write(chunk);

if (pendingText) {
if (pendingText && !inlineHostNode) {
// When we left on text, it's possible more text was written to the same node.
// here we copy in the final text content from the detached dom to the live dom.
(targetNodes.get(pendingText) as Text).data = pendingText.data;
Expand All @@ -42,6 +43,8 @@ export = function writableDOM(
}
},
close() {
appendInlineTextIfNeeded(pendingText, inlineHostNode);

return isBlocked
? new Promise<void>((_) => (resolve = _))
: Promise.resolve();
Expand All @@ -68,6 +71,7 @@ export = function writableDOM(
} else {
while ((node = walker.nextNode())) {
const clone = document.importNode(node, false);
const previousPendingText = pendingText;
if (node.nodeType === Node.TEXT_NODE) {
pendingText = node as Text;
} else {
Expand All @@ -86,10 +90,17 @@ export = function writableDOM(
const parentNode = targetNodes.get(node.parentNode!)!;
targetNodes.set(node, clone);

if (parentNode === target) {
target.insertBefore(clone, nextSibling);
if (isInlineHost(parentNode!)) {
inlineHostNode = parentNode;
} else {
parentNode.appendChild(clone);
appendInlineTextIfNeeded(previousPendingText, inlineHostNode);
inlineHostNode = null;

if (parentNode === target) {
target.insertBefore(clone, nextSibling);
} else {
parentNode.appendChild(clone);
}
}

// Start walking for preloads.
Expand Down Expand Up @@ -178,3 +189,20 @@ function getPreloadLink(node: any) {

return link;
}

function appendInlineTextIfNeeded(
pendingText: Text | null,
inlineTextHostNode: Node | null
) {
if (pendingText && inlineTextHostNode) {
inlineTextHostNode.appendChild(pendingText);
}
}

function isInlineHost(node: Node) {
const { tagName } = node as Element;
return (
(tagName === "SCRIPT" && !(node as HTMLScriptElement).src) ||
tagName === "STYLE"
);
}

0 comments on commit 4fe4b5b

Please sign in to comment.