Skip to content

Commit b206400

Browse files
committed
fix: inject inline script and styles more eagerly
1 parent 226e81a commit b206400

File tree

4 files changed

+49
-27
lines changed

4 files changed

+49
-27
lines changed

.changeset/seven-days-admire.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"writable-dom": patch
3+
---
4+
5+
Allow inline script/style tags to be injected without waiting for a nextSibling or final flush. (Checks if last flush ended with the closing tag).

src/__tests__/__snapshots__/inline-scripts.expected.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,24 @@ Embedded App.
1919
<script>
2020
scriptValues = ["a", "b"];
2121
</script>
22-
After Script.
2322
```
2423

2524
# Step 3
2625

2726
```html
2827
Embedded App.
2928
<script>
30-
scriptValues = ["a", "b"];
29+
scriptValues = ["a", "b"];scriptValues = ["a", "b"];
30+
</script>
31+
After Script.
32+
```
33+
34+
# Step 4
35+
36+
```html
37+
Embedded App.
38+
<script>
39+
scriptValues = ["a", "b"];scriptValues = ["a", "b"];
3140
</script>
3241
After Script.
3342
```

src/__tests__/__snapshots__/inline-styles.expected.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ Embedded App.
1919
<style>
2020
h1 { color: red; }
2121
</style>
22+
```
23+
24+
# Step 3
25+
26+
```html
27+
Embedded App.
28+
<style>
29+
h1 { color: red; } h1 { color: red; }
30+
</style>
2231
After Styles.
2332
```
2433

src/index.ts

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,17 @@ export = function writableDOM(
5757
const walker = doc.createTreeWalker(root);
5858
const targetNodes = new WeakMap<Node, Node>([[root, target]]);
5959
const targetFragments = new WeakMap<ParentNode, DocumentFragment>();
60+
const isIncomplete = (node: ParentNode) =>
61+
!(resolve || node.nextSibling || /<\/\w+>$/.test(curChunk));
6062
let appendedTargets = new Set<ParentNode>();
6163
let scanNode: Node | null = null;
6264
let resolve: void | (() => void);
6365
let isBlocked = false;
66+
let curChunk = "";
6467

6568
return {
6669
write(chunk: string) {
70+
curChunk = chunk;
6771
doc.write(chunk);
6872
walk();
6973
},
@@ -99,41 +103,35 @@ export = function writableDOM(
99103
walker.currentNode = startNode;
100104
} else {
101105
if (startNode.nodeType === NodeType.TEXT_NODE) {
102-
if (isInlineScriptOrStyleTag(startNode.parentNode!)) {
103-
if (resolve || walker.nextNode()) {
104-
targetNodes
105-
.get(startNode.parentNode!)!
106-
.appendChild(owner.importNode(startNode, false));
107-
walker.currentNode = startNode;
108-
}
109-
} else {
106+
if (!isInlineScriptOrStyleTag((node = startNode.parentNode!))) {
110107
(targetNodes.get(startNode) as Text).data = (startNode as Text).data;
108+
} else if (!isIncomplete(node)) {
109+
targetNodes
110+
.get(node)!
111+
.appendChild(owner.importNode(startNode, false));
111112
}
112113
}
113114

114115
while ((node = walker.nextNode())) {
116+
const parentNode = node.parentNode!;
115117
if (
116-
!resolve &&
117118
node.nodeType === NodeType.TEXT_NODE &&
118-
isInlineScriptOrStyleTag(node.parentNode!)
119+
isInlineScriptOrStyleTag(parentNode) &&
120+
isIncomplete(parentNode)
119121
) {
120-
if (walker.nextNode()) {
121-
walker.currentNode = node;
122-
} else {
123-
break;
124-
}
122+
break;
125123
}
126124

127-
const parentNode = targetNodes.get(node.parentNode!) as ParentNode;
125+
const cloneParent = targetNodes.get(parentNode) as ParentNode;
128126
const clone = owner.importNode(node, false);
129-
let insertParent: ParentNode = parentNode;
127+
let insertParent: ParentNode = cloneParent;
130128
targetNodes.set(node, clone);
131129

132-
if (parentNode.isConnected) {
133-
appendedTargets.add(parentNode);
134-
(insertParent = targetFragments.get(parentNode)!) ||
130+
if (cloneParent.isConnected) {
131+
appendedTargets.add(cloneParent);
132+
(insertParent = targetFragments.get(cloneParent)!) ||
135133
targetFragments.set(
136-
parentNode,
134+
cloneParent,
137135
(insertParent = owner.createDocumentFragment()),
138136
);
139137
}
@@ -248,10 +246,11 @@ function getPreloadLink(node: any, owner: Document) {
248246
return link;
249247
}
250248

251-
function isInlineScriptOrStyleTag(node: Node) {
252-
const { tagName } = node as Element;
249+
function isInlineScriptOrStyleTag(
250+
node: ParentNode,
251+
): node is HTMLScriptElement | HTMLStyleElement {
253252
return (
254-
(tagName === "SCRIPT" && !(node as HTMLScriptElement).src) ||
255-
tagName === "STYLE"
253+
(node as Element).tagName === "STYLE" ||
254+
((node as Element).tagName === "SCRIPT" && !(node as HTMLScriptElement).src)
256255
);
257256
}

0 commit comments

Comments
 (0)