Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix unsafeHTML #703

Merged
merged 6 commits into from
Dec 20, 2018
Merged

Fix unsafeHTML #703

merged 6 commits into from
Dec 20, 2018

Conversation

ruphin
Copy link
Contributor

@ruphin ruphin commented Dec 16, 2018

This fixes #702 - and adds a regression test for this case.

Unfortunately fixing the problem requires keeping a cache for previously rendered HTMLTemplateElements and DocumentFragments, so we can compare vs the current Part.value. Without this there is no way to check if the part rendered another value after the previous unsafeHTML render. This means there is some additional memory overhead, but I don't see how it can be avoided.

I added a cache for HTMLTemplateElement to ensure the same input string is never parsed twice. Previously, this directive would build duplicate templates if the same input was used across multiple instances. This will generally speed up execution, depending on how often similar strings are used. This also obviates the need for an 'isPrimitive' check.

@googlebot
Copy link

So there's good news and bad news.

👍 The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so. Everything is all good there.

😕 The bad news is that it appears that one or more commits were authored or co-authored by someone other than the pull request submitter. We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that here in the pull request.

Note to project maintainer: This is a terminal state, meaning the cla/google commit status will not change from this state. It's up to you to confirm consent of all the commit author(s), set the cla label to yes (if enabled on your project), and then merge this pull request when appropriate.

@justinfagnani
Copy link
Collaborator

Oops... I tried to push a change I med to this PR, but I accidentally brought in too many commits. Sorry. I'll clean it up

@googlebot
Copy link

CLAs look good, thanks!

Copy link
Collaborator

@justinfagnani justinfagnani left a comment

Choose a reason for hiding this comment

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

@ruphin thanks! I made a change to this PR that only keeps around the previous empty DocumentFragment as a way to check that the previous value was rendered by the directive, not something else. This will save memory from not keeping the template.

@justinfagnani justinfagnani merged commit dc87ca9 into lit:master Dec 20, 2018
@ruphin
Copy link
Contributor Author

ruphin commented Dec 20, 2018

I think it's reasonable to only take primitive values to avoid having to cache Templates, but I'm not sure if it's a good idea to not have any template caching at all. With this implementation, each instance of unsafeHTML will cause a new template parse, regardless if the same content has been parsed previously. This can be a huge hidden performance leak that may not be immediately obvious to users.

Something like this seems somewhat reasonable:

const content = [
  { visible: true, html: '<div></div>' },
  { visible: false, html: '<div></div>' },
  { visible: true, html: '<div></div>' },
  { visible: false, html: '<div></div>' },
  { visible: true, html: '<div>Something interesting</div>' },
  { visible: false, html: '<div>Unique content</div>' },
  { visible: false, html: '<div></div>' },
  { visible: true, html: '<div></div>' }
];

html`${content.map(item => item.visible ? unsafeHTML(item.html) : '')}`

This implementation will re-parse each <div></div> string on the first render, and re-parse them each consecutive render where visible has been toggled. I suspect the main use case for unsafeHTML is to render lists of content that is served from back-ends, which may have a decent amount of repetition. Do we want to optimise for memory usage or for performance here?

@justinfagnani
Copy link
Collaborator

Interesting. I think we should open a unsafeHTML performance issue to discuss this.

My first instinct is that re-rendering the same HTML across alternating updates isn't likely to be a common case, and someone doing that amount of perf-critical low-level HTML management isn't really taking advantage of lit-html at that point and should do something custom like write their own directive or hand lit-html a DOM node that they manually manage.

neuronetio pushed a commit to neuronetio/lit-html that referenced this pull request Dec 2, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Alternating unsafeHTML and regular string not working
3 participants