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

Rendering a TemplateResult stored in a MobX store does not work #4565

Open
Artur- opened this issue Feb 27, 2024 · 3 comments
Open

Rendering a TemplateResult stored in a MobX store does not work #4565

Artur- opened this issue Feb 27, 2024 · 3 comments

Comments

@Artur-
Copy link
Contributor

Artur- commented Feb 27, 2024

Which package(s) are affected?

Lit Core (lit / lit-html / lit-element / reactive-element)

Description

It would be expected that this snippet

class TestStore {
  tpl: TemplateResult | undefined = undefined;

  constructor() {
    makeAutoObservable(this);
  }
}
const testStore = new TestStore();
testStore.tpl = html`Hello`;
render(testStore.tpl, document.body);

Would render hello to the document body, in the same way as

const tpl: TemplateResult | undefined = undefined;
tpl = html`Hello`;
render(tpl, document.body);

but instead it fails with

Uncaught Error: Internal Error: expected template strings to be an array
with a 'raw' field. Faking a template strings array by
calling html or svg like an ordinary function is effectively
the same as calling unsafeHtml and can lead to major security
issues, e.g. opening your code up to XSS attacks.
If you're using the html or svg tagged template functions normally
and still seeing this error, please file a bug at
https://github.com/lit/lit/issues/new?template=bug_report.md
and include information about your build tooling, if any.

Reproduction

As above

Workaround

Not sure what a sensible workaround would be. Excluding only the template that is somewhere deep inside a mobx object does not seem feasible

Is this a regression?

No or unsure. This never worked, or I haven't tried before.

Affected versions

lit-html 3.1.2

Browser/OS/Node environment

Chrome 121.0.6167.160

@sorvell
Copy link
Member

sorvell commented Feb 27, 2024

Fix

makeAutoObservable(this, {tpl: observable.shallow}); (example)

More Info

MobX is making the tpl property of the store into a getter/setter which does not return the actual lit TemplateResult. The strings array on the TemplateResult must be a template literal as is returned by lit's html function.

I'm not very familiar with MobX so there may be other fixes, but by default makeAutoObserveable makes the object "deeply" observable, which is causing the strings property of the TemplateResult to no longer contain its raw property, which lit requires. Making the tpl property only shallowly observed obserable.shallow prevents this. Alternatively, it looks like you can also just make the entire object not deeply observe via by setting {deep: false} as the third argument, see the mobx docs.

Also, you may wan to consider using lit-mobx which provides a set of tools for integrating mobx and lit.

@Artur-
Copy link
Contributor Author

Artur- commented Feb 28, 2024

The downside of those workarounds is that they either affect all other values in the store (breaking something else) or require configuration per property in the store. In this demo case it is just tpl but in real life, it is nested inside four arrays and three objects or something similar. If you forget to configure the property, then it will fail at runtime. This is why I was looking for other potential solutions

@justinfagnani
Copy link
Collaborator

Proxies break all kinds of maps, this isn't unusual to lit-html. Unless you're the only owner of a reference to the object, via the proxy, then you will have two objects - the original and the proxy - going around your app that act as different keys in maps and sets and are different for referential equality.

I'm not sure if the MobX advice on turning an observable into a plain object will work: https://mobx.js.org/observable-state.html#converting-observables-back-to-vanilla-javascript-collections Even if it did, that would be cumbersome to remember to do. The best bet is to not make template results observable. They're immutable anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: No status
Development

No branches or pull requests

3 participants