WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit 555ac49

Browse files
authored
Merge pull request #73 from WICG/noamr-patch-4
Enhance patching explainer with current thinking
2 parents 11d026e + 1c4ac62 commit 555ac49

File tree

1 file changed

+49
-31
lines changed

1 file changed

+49
-31
lines changed

patching-explainer.md

Lines changed: 49 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,32 @@ It is similar to calling `document.write()`, scoped to an node.
3232
The most atomic form of patching is opening a container node for writing, creating a `WritableStream` for it.
3333
This can be done with an API as such:
3434
```js
35-
const writable = elementOrShadowRoot.streamHTML();
35+
const writable = elementOrShadowRoot.streamHTMLUnsafe({runScripts: true});
3636
byteOrTextStream.pipeTo(writable);
3737
```
3838

3939
A few details about one-off patching:
40-
- Trying to patch an element that is currently being patched would abort the original stream.
41-
- Replacing the contents of an existing script would only execute the script if the original contents were empty (equivalent to `innerHTML` behavior).
40+
- Streams do not abort each other. It is the author's responsibility to manage conflicts between multiple streams.
41+
- Unlike contextual fragments, when `runScripts` is true, classic scripts in the stream can block the parser until they are fetched. This makes the streaming parser behave more similarly to the main parser.
42+
- Only the unsafe variant can run scripts.
43+
- This describes `streamHTML`, but also `streamAppendHTML`, `streamPrependHTML`, `streamBeforeHTML`, `streamAfterHTML`, and `streamReplaceWithHTML` variants are proposed.
4244

4345
To account for HTML sanitation, this API would have an "Unsafe" version and would accept a sanitizer in its option, like [`setHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/setHTML):
4446
```js
4547
byteOrTextStream.pipeTo(elementOrShadowRoot.streamHTML({sanitizer}));
46-
byteOrTextStream.pipeTo(elementOrShadowRoot.streamHTMLUnsafe({sanitizer}));
48+
byteOrTextStream.pipeTo(elementOrShadowRoot.streamHTMLUnsafe({sanitizer, runScripts}));
4749
```
4850

49-
Also see detailed discussion at https://github.com/whatwg/html/issues/11669, will amend this explainer once that's settled.
51+
Since user-space sanitizers like DOMPurify are not well suited for streaming, TrustedTypes only allows streaming with either sanitation or by giving it a "free pass", by blessing parser options:
52+
```js
53+
// This would fail if there is a default policy with `createHTML`
54+
element.streamHTMLUnsafe({sanitizer, runScripts});
55+
56+
// This would "bless" the parser options for streaming.
57+
element.streamHTMLUnsafe(trustedSourcePolicy.createParserOptions({sanitizer, runScripts});
58+
```
59+
60+
Also see detailed discussion at https://github.com/whatwg/html/issues/11669.
5061
5162
## Interleaved patching
5263
@@ -57,50 +68,57 @@ parses its content as raw text, finds the target element using attributes, and r
5768
<section contentname=gallery>Loading...</section>
5869

5970
<!-- later -->
60-
<template contentmethod="replace-children"><section contentfor=gallery>Actual gallery content<section></template>
71+
<template contentmethod="replace-children"><section contentname=gallery>Actual gallery content<section></template>
6172
```
6273
6374
A few details about interleaved patching:
6475
- Templates with a valid `contentmethod` are not attached to the DOM.
6576
- If the patching element is not a direct child of `<body>`, the outlet has to have a common ancestor with the patching element's parent.
6677
- The patch template has to be in the same tree (shadow) scope as the outlet.
67-
- `contentmethod` can be `replace-children`, `replace` (which replaces the entire element), `append`, or `prepend`.
78+
- `contentmethod` can be `replace-children`, or `append`. `replace-children` is the basic one that allows replacing a placeholder with its contents,
79+
while `append` allows for multiple patches that are interleaved in the same HTML stream to accumulate.
80+
- Interleaved patching works together with one-off patching. When a `<template contentmethod>` appears inside a stream, it is applied, resolving `contentname` from the stream target.
6881
6982
## Avoiding overwriting with identical content
7083
7184
Some content might need to remain unchanged in certain conditions. For example, displaying a chat widget in all pages but the home, but not reloading it between pages.
7285
For this, both the outlet and the patch can have a `contentrevision` attribute. If those match, the content is not applied.
7386
74-
## Reflection
75-
76-
Besides applying a patch, there should be a few ways to reflect about the current status of patching and receive events/callbacks when a patch is underway.
77-
78-
### CSS reflection
79-
See https://github.com/w3c/csswg-drafts/issues/12579 and https://github.com/w3c/csswg-drafts/issues/12578.
87+
## Potential enhancement - streaming to non-element ranges
88+
See discussion in https://github.com/WICG/declarative-partial-updates/issues/6 and https://github.com/WICG/webcomponents/issues/1116.
8089
81-
Suggesting to add a couple of pseudo-classes: `:updating` and `:pending`, that reflect the patching status of an element, in addition to a pseudo-class that reflects that an element's parser state is open (regardless of patching).
90+
It has been a common request to stream not just by replacing the whole contents of an element or appending to it, but also by replacing an arbitrary range.
91+
This is connected with other use cases for addressing arbitrary ranges in the page.
92+
Use cases for this can be replcing some `<meta>` tags in the `<head>`, replacing multiple rows in a table, or replacing an element similar to the `replaceWith` method.
8293
83-
### JS status
94+
To achieve these use cases, the direction is to use addressable comments as per https://github.com/WICG/webcomponents/issues/1116, and use two comments as a "range", equivalent to an element with a `contentname` attribute.
8495
85-
Suggesting to give nodes a nullable `currentPatch` attribute that reflects the current status of a patch and allows aborting it.
86-
In addition, suggesting to fire a `patch` event on an element when a patch on it is invoked, allowing the listener to abort the patch or inject a `TransformStream` to it.
96+
Very initial example:
8797
88-
## Sanitation & Content Security
89-
90-
Since patching is a new API for setting HTML, it should be designed carefully in terms of XSS and the existing mitigations.
91-
As far as the HTML sanitizer go, it should be made sure that the different new APIs support passing a sanitizer, and that the sanitizer implementation works correctly when the parser content is streamed rather than set directly. See https://github.com/WICG/sanitizer-api/issues/190.
92-
Note that the HTML sanitizer works closely with the HTML parser, so it shouldn't need additional buffering/streaming support as part of the API.
93-
94-
In addition, [Trusted types](https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API) would need streaming support in its policy, potentially by injecting a `TransformStream` into the patch. See https://github.com/w3c/trusted-types/issues/594.
95-
96-
## Enhancement - JS API for interleaved patching
97-
In addition to invoking interleaved patching as part of the main response, allow parsing an HTML stream and extracting patches from it into an existing element:
98-
```js
99-
const writable = documentOrElementOrShadowTree.patchInterleaved()
100-
const writable = documentOrElementOrShadowTree.patchInterleavedUnsafe()
98+
```html
99+
<table contentname="data">
100+
<tr><td>static data
101+
<tr><td>static data
102+
103+
<?marker name=dyn-start?>
104+
<tr><td>dynamic data 1
105+
<tr><td>dynamic data 2
106+
<?marker name=dyn-end?>
107+
</table>
108+
109+
<!-- stuff.... -->
110+
111+
<!-- This would replace the children only between the dyn-start and dyn-end markers, leaving the static data alone. -->
112+
<template contentmethod="replace-children" contentmarkerstart="dyn-start" contentmarkerend="dyn-end">
113+
<table contentname=data>
114+
<tr><td>dynamic data 3
115+
<tr><td>dynamic data 4
116+
<tr><td>dynamic data 5
117+
</table>
118+
</template>
119+
</body>
101120
```
102121
103-
When calling `patchInterleaved`, discovered patches are applied to the target container node, and the rest of the HTML is discarded.
104122
105123
## Potential enhancement - patch contents from URL
106124

0 commit comments

Comments
 (0)