Skip to content
This repository has been archived by the owner on Feb 25, 2021. It is now read-only.

Add HTML Block rewriting #1146

Merged
merged 12 commits into from
Jul 23, 2018
Merged

Add HTML Block rewriting #1146

merged 12 commits into from
Jul 23, 2018

Conversation

rynowak
Copy link
Member

@rynowak rynowak commented Jul 18, 2018

/cc @SteveSandersonMS - handing this off for you to do the runtime piece.

Rewrites HTML-only subtrees of the IR in an HTML 'block' node with simple string content.

This will rely on new runtime/rendertree support in order to work E2E.

@rynowak rynowak requested a review from SteveSandersonMS July 18, 2018 00:37
/// <param name="textContent">Content for the new markup text frame.</param>
public void AddMarkupContent(int sequence, string textContent) =>
// TODO stevesa implement me
throw null;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ex dee

@rynowak
Copy link
Member Author

rynowak commented Jul 18, 2018

FYI the test failures are of course expected right now. The rendering tests and E2E tests throw because the RenderTreeBuilder throws.

If you rename the new method on RenderTreeBuilder you'll have to regen the baselines for the runtime codegen tests.

@SteveSandersonMS
Copy link
Member

Thanks @rynowak! This looks perfect.

I've rebased on master (hence the changes to the commit history here now) and will proceed with the runtime bits.

@SteveSandersonMS
Copy link
Member

SteveSandersonMS commented Jul 20, 2018

Still to do:

  • Support UpdateMarkup edit frames in browser-side code
  • Stop assuming that markup frames content will represent exactly 1 HTML element. Even though our Razor compiler does produce markup frames for each top-level HTML element, that wouldn't be the case if we use this mechanism for IHtmlString.

@SteveSandersonMS
Copy link
Member

OK all done now.

@rynowak We should discuss the existence of the new MarkupString type (and why I didn't use HtmlString or IHtmlContent from the HTML abstractions package), but other than that it should be ready to go.

/// <param name="value">The value for the new instance.</param>
public MarkupString(string value)
{
_value = value ?? string.Empty;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this? Is it ever meaningful to have null markup string?

For instance the following is true. ((MarkupString)null).ToString() == ""

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point.

I've now changed it so that MarkupString can hold the value null.

  • If you .ToString() such an instance, you get string.Empty just like HtmlAbstractions' HtmlString.
  • If you renderTreeBuilder.AddContent such an instance, it creates a markup frame whose value is string.Empty, just like if you AddContent((string)null).

So the net effect is that nulls continue to be treated like string.Empty, but now it's possible to observe that null was stored in the MarkupString to avoid losing that info.

if (markupContent == null)
{
throw new ArgumentNullException(nameof(markupContent));
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check non-null here? new MarkupContent(string) is happy to accept null. IMO we should permit both or neither

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. It now just null-coalesces with string.Empty like we do for regular string values.

// The JavaScript-side rendering code does not rely on this behavior. It supports
// inserting markup frames with arbitrary markup (e.g., multiple top-level elements
// or none). This test exists only as an observation of the current behavior rather
// than a promise that we never want to change it.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it's desirable that we change this in the compiler? It would be straightforward to do.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perf-wise yes, the ideal would be for adjacent literal markup frames (and any adjacent literal text frames) to be coalesced.

If you think this is a simple addition that would be neat, but I think it’s also a good improvement as-is.

Note that we shouldn’t treat text literals as markup unless they are coalesced into a markup frame, because text nodes on their own are much cheaper to render than markup frames.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this to #1170

@rynowak
Copy link
Member Author

rynowak commented Jul 22, 2018

We should discuss the existence of the new MarkupString type (and why I didn't use HtmlString or IHtmlContent from the HTML abstractions package), but other than that it should be ready to go.

My assumption is that you wanted to avoid the allocation and the extra references. In particular I think WebEncoders is pretty heavy-weight - this is why I didn't suggest it from the beginning.

@rynowak
Copy link
Member Author

rynowak commented Jul 22, 2018

:shipit: from me. I'm not allowed to make it approved since I created the PR.

@SteveSandersonMS SteveSandersonMS added this to the 0.5.0 milestone Jul 23, 2018
@SteveSandersonMS
Copy link
Member

SteveSandersonMS commented Jul 23, 2018

My assumption is that you wanted to avoid the allocation and the extra references. In particular I think WebEncoders is pretty heavy-weight - this is why I didn't suggest it from the beginning.

Yes, avoiding unnecessary allocations was one reason, the other was that simply referencing Microsoft.AspNetCore.Html.Abstractions suddenly exposes a bunch of new APIs that aren't really applicable. Finally the name HtmlString implies the markup has to be HTML, which is not the case for this feature - SVG is also supported (though that is a minor quibble).

@SteveSandersonMS SteveSandersonMS merged commit 3c4f7b5 into master Jul 23, 2018
@SteveSandersonMS SteveSandersonMS deleted the rynowak/html-block branch July 23, 2018 17:18
SteveSandersonMS pushed a commit to SteveSandersonMS/BlazorMigration that referenced this pull request Nov 27, 2018
* Add HTML Block rewriter

* Baseline updates

* test gaps

* Update some unit tests to represent same behavior as before

* Define Markup frame type. Tests for rendering markup frames into render tree.

* Support markup frames during diffing (retain, insert, update, delete)

* Support markup blocks on WebAssembly

* Support rendering markup frames with server-side execution too

* Support markup blocks with multiple top-level nodes. Support updating markup dynamically.

* Define MarkupString type as a way to insert dynamic markup without needing custom RenderFragment code

* Remove comment

* CR: Better null value handling
# for free to subscribe to this conversation on GitHub. Already have an account? #.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants