reproduction repository: https://github.com/reaysawa/starter-preact-scss
yarn && yarn dev should work with hot-reloading :heavy_check_mark: yarn add preact@next to upgrade from _10.0.0-beta._0 to _10.0.0-beta._1yarn && yarn dev again, but this time it doesn't render :red_circle: I'll try to fix this one as we have the same issue for our preact gatsby plugin I would like to ship
I fear this has something to do with _self, what we use now to prevent JSON injection @wardpeet.
Also might be worth checking this out: https://twitter.com/dan_abramov/status/1125846420949434368
As @JoviDeCroock correctly mentioned: This is caused by the JSON injection prevention. To get things rendered one could patch the patched React.Children.only to set the _ property:
import 'react-hot-loader/patch';
const originalChildrenOnly = React.Children.only;
React.Children.only = function (children) {
const result = originalChildrenOnly(children);
result._ = result;
return result;
};
But then we would need to patch all other patched methods too. This is a no-go IMHO.
I see two ways of fixing this:
_self set to an object that we share between create-element and diff. From my investigation this would add 11B_self and __self to the same empty object. This would add 5BYes, the second solution has come up to me aswell, this would still prevent JSON injection but I'm a bit reluctant about it all. Given that I'm no security expert whatsoever.
I opened a PR. I'm also not a security expert but it shouldn't differ too much from the original solution as it still bases on object ref equality
Yes difference being that I'd assume there's a way to make a refferentially equal object in JSON vs an object that was made to shape the vnode. I'm probably overthinking this, let's go with it and see what others say :D
The problem is that the equality is now a comparison to an object that isn't externally accessible. Before, it was possible to create a VNode like this:
const vnode = { type: 'div', props: null, children: 'hello world' };
vnode._ = vnode;
A thought: we had originally proposed to implement VNode checking against __proto__===null. That approach provides the same external simplicity as @sventschui's PR, but avoids locking VNodes to an internal "safe" property reference:
const vnode = { type: 'div', props: null, children: 'hello world', __proto__: null };
// in diff():
if (vnode.__proto__!==null) vnode += '';
@developit why did we stray from the proto null approach? (I thought that was the way we added it 馃槢)
Proto null can still be injected on browsers where proto is deprecated.
You mean browsers that did not implement it? As I don't think it will ever go away as it will break the web. it won't work on < ie 10 but it's full of security issues anyway.
The __proto__ approach is also flawed in safari & chrome: JSON.parse('{"__proto__":{"hello":"proto"}}').__proto__ will print {hello: "proto"} in these browsers. Didn't test others
@sventschui the check was:
JSON.parse('{"__proto__":null}').constructor === undefined
Yes I took that away from slack in the meantime, sorry for the misunderstanding. As @JoviDeCroock mentioned, there are other issues with the proto approach 馃槵