-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Remove no-danger from recommended rules #636
Conversation
Using `dangerouslySetInnerHTML` is already very explicit and there are some things you actually can't do w/out it. I don't think I'd say that using it isn't "recommended".
Just out of curiosity, what can't you do without it? I think it should be recommended, but maybe with a warning level of |
imo warnings aren't particularly useful - they just train people to ignore console output. Ideally things are either off or errors. |
I see them more as an awareness feature - in this case "reconsider what In any case, I think improving the error message here is critical and in I doubt there are many use cases for needing |
Put simply, you can't tell React not to escape something. It's great to escape things by default, but the ability to opt-out of escaping when you need to is absolutely critical. I've used <script>console.log(true && 'hello')</script> It's also needed when using 3rd-party DOM string manipulation libraries inside React, like Mustache (which already produces escaped output) or Markdown. When you render some HTML, you've gotta have a way to stick it in your component w/out further escaping it. Also agree w @ljharb that warnings aren't useful. It's either an error or it's not, and this one is definitely not. |
When you say "render JS strings", do you mean, put an actual script block in the page, or show the literal text Is it that common to use "not jsx" inside React components? |
I might also point out that an example of using Markdown w React is found on the React homepage (see the last example). |
@ljharb I mean putting an actual Side note: we couldn't actually have this conversation here on GitHub unless there were a way for them to opt-out of escaping all the special HTML characters we're using ... :P |
The markdown/template approach is a good point, and this is one of our most common use cases for setting innerHTML. I can't believe that adding an actual script block to the page inside a React component is a common use case, and either way, I can't conceive of how it's not a horrific one. At Airbnb we have a component that manually escapes safe HTML tags so that we don't need to set inner HTML, but so content with HTML can be used without exposing us to XSS. This seems like the usual solution for the template solution too (eg https://github.com/rexxars/react-markdown and similar approaches). I don't have a strong opinion on whether it should be included in the recommended config or not - but I'm only partially convinced that it's a good thing to allow, primarily by the templating use case. |
I never said it was common, but when I do use it I can do some really cool stuff: Anyway, my point about this conversation still holds. Somewhere, on some server, GitHub is "dangerously setting inner HTML" which is what's allowing us to have this conversation. |
I have a few thoughts
I'd absolutely remove this from the recommended rules. |
Every use case for dangerouslySetInnerHTML can be achieved more safely by transforming the intended content to VDOM first and rendering it as children. <script>{`console.log(true && 'hello')`}</script> For markdown, convert md -> ast -> vdom, or md -> html -> vdom. Last step can be done easily using the native DOMParser, after which converting DOM to VDOM is cake. Just my 2¢! 😊 |
Just throwing my hat in there as another heavy user of On the subject of recommended rules, I agree with @mjackson when he says:
Linting is generally used to help us avoid mistakes/typeos and guide us to using better "accepted" practices. In this case it's unlikely that you would use this API by mistake and I think that the name of this API is explicit enough to guide people to not use it if they don't have to. Just my thoughts. |
(to Kent's point though, I have definitely seen a lot of people use dangerouslySetInnerHTML for server rendering use cases) |
@developit You know I love you, but did you run that code? renderToString(<script>console.log(true && "hello")</script>) => <script>console.log(true && 'hello')</script> :P |
It's about a billion pounds more cake than just trusting developers to use an API with the word "dangerous" in the name correctly, and on the sever you don't have a browser environment to let you cheat on the parsing. |
I love cake 😄. I didn't mean to say it's always better to parse, just safer since it's an inactive DOM. @mjackson - ah I totally misunderstood what you were getting at there, yes. |
Yet another user here with this issue. Everyone has already stated the case better than I. (My specific scenario is rendering content from WordPress' API in React views on the server. These include all manners of tags, but it's trusted content despite the dangerous name) |
Recommended rules are supposed to cover the common use cases, not the uncommon ones. It's completely expected and acceptable that if you deviate from a linter rule for a good reason, you use an inline eslint comment to override it. The criteria for being a "recommended rule" is not "it's sometimes useful", it's "in the majority case, having the rule is more helpful than not". Certainly the name "dangerous" makes it unlikely you'd use it by mistake, unless of course you copied and pasted a code example from somewhere on the internet - in which case the linter catching it, and requiring you to explicitly indicate that you did, in fact, intend to do that via an eslint comment - is a good thing. To restate: "there's a use case" is utterly irrelevant when discussing whether something belongs in a recommended linter config or a style guide. The only thing that matters is "in the majority case, having the rule is more helpful than not." |
I use it to render SVG's that are exported from AI or sketch. I can control the fill other CSS properties directly in my style sheets. Here is an example.
(I did this on my phone so I may have messed up somewhere) |
Having the no-danger rule as part of the "recommended" set is misleading, Jordan. You're telling people that using a sometimes-necessary piece of the API is not recommended. That makes no sense. |
Again, I don't feel strongly about this specific rule being or not being in the "recommended" set. However, there's tons of "sometimes necessary" things that are generally discouraged. Sometimes being necessary in no way guarantees that a thing should be commonly recommended. |
Would you "generally discourage" making a website with user-generated content? Or "generally discourage" using Markdown? That's what makes no sense to me. |
I don't have a strong feeling about this but we use it four times in our application because we needed to interact with an API built for JS written years ago. We know we shouldn't use it and will remove it eventually. |
Linting seems to exist to catch mistakes. There are use cases for using set state in It would be incredibly surprising to me if somebody accidentally rendered unescaped HTML with React. That's why I think it doesn't make sense to have it as a linting rule at all, let alone as a recommended one. It's not catching mistakes, it's just a nuisance. |
That's the sentiment I'm worried about. Is there another way to do what you want to do? Then yes, you should probably do that. But there are times when you must use it. |
Recommending a rule isn't telling the consumer they have to use that rule. If her/his application needs that API to operate, they can easily turn off the linting rule. I also don't feel strongly about this, but I think this is super useful to newcomers to React who blindly consume the recommended ruleset of this plugin. I do, however, feel strongly about updating the error message to include why this may be a bad idea if there is a better way to solve her/his problem. Regardless if this is recommended or not, I think the error message should include: |
Totally agree with @mjackson regarding the explicit naming. We e.g. are in the process of rewriting parts of a legacy monolith to react. Naturally we have APIs returning old html content that needs to be rendered unescaped. I guess a lot of people (hopefully) start off by converting small parts of their existing architecture and are dealing with these kinds of "problems".
If anyone insists what about |
Someone suggested defaulting to a warn level, is that a happy medium here? |
Well, Also, like @evcohen suggested, the current error message is not very helpful and can be greatly improved. (NB: There is a similar issue about |
Just adding my 2¢ to what has already been said. I use componentDidUpdate() {
this._output.innerHTML = marked(this.props.markdown);
} |
@mjackson I personally think that this whole api is offensive and too opinionated. As others have said every templating language out there has the ability to output unescaped html for a reason. I still personally think facebook/react#6253 or similar is needed in React for things like @rileybracken's issue with SVG's. Yes unescaped html needs to be explicit by why is it frowned upon? There are many legitimate use cases, all mentioned above. I've personally built a CMS with React, and let me tell you it wouldn't be possible without this API. |
@yannickcr Any further objections here? @ljharb said a few times that he doesn't feel too strongly about it, and you've said you're not against removing it. I, for one, feel pretty strongly that So, can we merge? |
@DylanPiercey it's a recommended config. It's supposed to be opinionated. If you don't like the opinions (whether they recommend turning this particular rule on or not), then it's pretty easy - don't use the recommended options, and configure it yourself. |
@ljharb, Sorry I wasn't meaning to call out the linting options for being opinionated, I was referring the the |
@mjackson Yes, it will be merged. But I consider this as a breaking change (not a big one, but still) so it will only be in the next major version (no ETA yet). |
@ljharb do you have your build set to fail on eslint errors or not? I'm always motivated to fix warnings so that I don't have to skim through a lot of cruft to find errors. If someone doesn't have that motivation it's probably because nothing is forcing them to fix the errors in the first place. |
@ljharb I find warnings very useful for rules like |
If you're a good dev and you know what you're doing, you'll just /* eslint-disable no-danger */
const Div = props => <div {...props}
dangerouslySetInnerHTML={props.innerHTML && {__html: props.innerHTML}}
/>
/* eslint-enable no-danger */
// look ma, no errors!
const takeThatESLint = <Div innerHTML={`<script src="myEvilScript.js" />`} /> So I really don't see what this rule will save anyone from that the well-named |
Using
dangerouslySetInnerHTML
is already very explicit and there are some things you actually can't do w/out it. I don't think I'd say that using it isn't "recommended". It's totally ok if you use it the way it's intended to be used.