-
-
Notifications
You must be signed in to change notification settings - Fork 8.5k
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
Add new prefer-ideal-image eslint rule #8826
base: main
Are you sure you want to change the base?
Conversation
@slorber I still need to fix linting errors and add documentation for this eslint rule, but just wanted to ask, do you think it would be useful to implement auto-fixing capability for this rule? |
✅ [V2]Built without sensitive environment variables
To edit notification comments on pull requests, go to your Netlify site settings. |
⚡️ Lighthouse report for the deploy preview of this PR
|
packages/eslint-plugin/src/index.ts
Outdated
@@ -16,6 +16,7 @@ export = { | |||
'@docusaurus/string-literal-i18n-messages': 'error', | |||
'@docusaurus/no-html-links': 'warn', | |||
'@docusaurus/prefer-docusaurus-heading': 'warn', | |||
'@docusaurus/prefer-ideal-image': 'warn', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be off by default. Not many use ideal image. It should be off in our own codebase except the website as well.
@Josh-Cena What do you think about this? |
I don't think we need auto-fix, no. It sounds very non-trivial and has a high risk of breaking otherwise valid code. Auto-fixing should never change code behavior. |
db99c65
to
1ffcfec
Compare
@slorber @Josh-Cena Seems like some of the checks are failing for this PR because of the following error:
Anything that needs to be done from my side to fix this? |
1ffcfec
to
240f1b4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks but unfortunately that's not so simple. It is preferable that you open an RFC of the behavior you plan to implement before starting the work because the description of the original issue is not really complete and does not mention any design or edge cases to consider.
prefer-ideal-image: ensures @theme/IdealImage is used instead of img tags
We should allow any string link coming from props, dynamic or hardcoded values:
<img src="https://github.com/xyz.png" />
<img src={`${props.githubUrl}.png`} />
<img src="./xyz.png" />
<img src={useBaseUrl("./xyz.png"} />
const imgSrc = "./xyz.png"
<img src={imgSrc} />
Eventually, add an option to reject relative local links?
The only patterns that IMHO we can safely reject are the usage of images that are required/imported locally:
import imgSrc from './path/to/img.png';
<img src={imgSrc} />
<img src={require("./img.png")}/>
The weird chalk build errors you get are a bug that I will fix.
You can get the real errors by turning disableInDev: false,
in the plugin options
https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-ideal-image#disableInDev
err TypeError: Cannot read properties of undefined (reading 'src')
at fallbackParams (main:8332:43)
at IdealImage.render (main:7750:106)
at d (main:67040:231)
at bb (main:67041:16)
at a.b.render (main:67047:43)
at a.b.read (main:67046:83)
at Object.exports.renderToString (main:67057:138)
at doRender (main:219469:37)
at async render (main:219387:16)
at async /Users/sebastienlorber/Desktop/projects/docusaurus/node_modules/p-map/index.js:57:22
This PR is not ready to merge, not because of the CI failures, but because the behavior implemented is not what we need.
], | ||
invalid: [ | ||
{ | ||
code: "<img src='./path/to/img.png' alt='some alt text' />", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should not be rejected?
code: "<img src='./path/to/img.png' srcset='./path/to/img-480w.jpg 480w, ./path/to/img-800w.png 800w' sizes='(max-width: 600px) 480px, 800px' alt='some alt text' />", | ||
errors: errorsJSX, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should not be rejected?
<img | ||
<Image | ||
className={styles.image} | ||
src={imageURL} | ||
alt={name} | ||
onError={(e) => { | ||
// Image returns 404 if the user's handle changes. We display a | ||
// fallback instead. | ||
e.currentTarget.src = | ||
'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="600" height="600" fill="none" stroke="%2325c2a0" stroke-width="30" version="1.1"><circle cx="300" cy="230" r="115"/><path stroke-linecap="butt" d="M106.81863443903,481.4 a205,205 1 0,1 386.36273112194,0"/></svg>'; | ||
img={{ | ||
src: { | ||
src: imageURL, | ||
preSrc: | ||
'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="600" height="600" fill="none" stroke="%2325c2a0" stroke-width="30" version="1.1"><circle cx="300" cy="230" r="115"/><path stroke-linecap="butt" d="M106.81863443903,481.4 a205,205 1 0,1 386.36273112194,0"/></svg>', | ||
images: [], | ||
}, | ||
preSrc: | ||
'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="600" height="600" fill="none" stroke="%2325c2a0" stroke-width="30" version="1.1"><circle cx="300" cy="230" r="115"/><path stroke-linecap="butt" d="M106.81863443903,481.4 a205,205 1 0,1 386.36273112194,0"/></svg>', | ||
}} | ||
alt={name} | ||
// onError={(e) => { | ||
// // Image returns 404 if the user's handle changes. We display a | ||
// // fallback instead. | ||
// e.currentTarget.src = | ||
// 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="600" height="600" fill="none" stroke="%2325c2a0" stroke-width="30" version="1.1"><circle cx="300" cy="230" r="115"/><path stroke-linecap="butt" d="M106.81863443903,481.4 a205,205 1 0,1 386.36273112194,0"/></svg>'; | ||
// }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that seems overly complicated, using <img>
is fine in this case IMHO
<Image | ||
className={styles.featureImage} | ||
alt={feature.title} | ||
width={Math.floor(feature.image.width)} | ||
height={Math.floor(feature.image.height)} | ||
src={withBaseUrl(feature.image.src)} | ||
img={withBaseUrl(feature.image.src)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the ideal image plugin is not designed to work with SVGs
Eventually we could import the svgs and use them as components instead of using <img src="xyz.svg"/>
like we do atm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the ideal image plugin is not designed to work with SVGs
I had noticed that it only works with JPEGs and PNGs but somehow completely missed out in this case 😅
Eventually we could import the svgs and use them as components instead of using
<img src="xyz.svg"/>
like we do atm
@slorber Should I address this change in this PR?
<img | ||
<Image | ||
alt={translate({message: 'Docusaurus with Keytar'})} | ||
className={styles.heroLogo} | ||
src={useBaseUrl('/img/docusaurus_keytar.svg')} | ||
img={useBaseUrl('/img/docusaurus_keytar.svg')} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the ideal image plugin is not designed to work with SVGs
Eventually we could import the svgs and use them as components instead of using <img src="xyz.svg"/>
like we do atm
<Image | ||
alt={name} | ||
className={clsx('avatar__photo', styles.avatarImg)} | ||
src={avatar} | ||
img={avatar} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideal image is not designed to work with external URLs. <img>
is fine in this case
<img | ||
<Image | ||
alt={name} | ||
className="avatar__photo" | ||
src={`https://unavatar.io/twitter/${handle}?fallback=https://github.com/${githubUsername}.png`} | ||
img={`https://unavatar.io/twitter/${handle}?fallback=https://github.com/${githubUsername}.png`} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideal image is not designed to work with external URLs. <img>
is fine in this case
<img | ||
<Image | ||
className="avatar__photo avatar__photo--xl" | ||
src={`${githubUrl}.png`} | ||
img={`${githubUrl}.png`} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideal image is not designed to work with external URLs. <img>
is fine in this case
<img | ||
src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=353916&theme=light" | ||
<Image | ||
img="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=353916&theme=light" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideal image is not designed to work with external URLs. <img>
is fine in this case
@slorber Apologies for underestimating the complexity of the implementation and misunderstanding the behavior of this eslint rule. I should have discussed the schema and the desired behavior first before implementing this rule 😅 I agree the original issue does lack more details regarding the design and edge cases. Actually, I saw one of the comments on the original issue that mentioned that we could directly link a PR back to this issue; hence I went ahead with implementing this PR.
Sure, it makes sense, as I noticed that the internal implementation of
Any particular reason why we would want to reject relative local links?
Got it 👍. So, do we want to encourage users to use the
Got it 👍
I'll make the appropriate changes in this PR to fulfill the desired behavior of this eslint rule. |
Not a big deal, some eslint rules are simples while others are much more complex. We can continue the design of the feature in this PR.
That's not what I wanted to say. What I mean is that this should be valid because the user could use this component using absolute URLs like a github avatar link. function Avatar({src}) {
return <img src={src}/>
} We can't know if the component is meant to be used with local images (that can be required) so it shouldn't error by default. At most it should be a warning IMHO, but probably default to disabled.
If an image is in the repo, it's probably more optimized to require it instead of using a string path. I think it's good if we emit a warning by default (with option to disable) for these cases: <img src="./xyz.png" />
<img src="/xyz.png" />
const imgSrc = "./xyz.png"
<img src={imgSrc} />
const imgSrc = "/xyz.png"
<img src={imgSrc} />
Yes, by default we should error for these patterns and encourage usage of the import imgSrc from './path/to/img.png';
<img src={imgSrc} />
<img src={require("./img.png")}/>
You mean requiring avif, webp and other similar extensions? I guess it's not really necessary, the Webpack loader will likely already throw an error and we'll likely want to support those extensions in the future.
Thanks I'm not very skilled in writing ESLint plugins, so can't really help to figure out how to check if image was locally required/imported. Maybe @Josh-Cena can guide you? |
Signed-off-by: Devansu <[email protected]>
Signed-off-by: Devansu <[email protected]>
Signed-off-by: Devansu <[email protected]>
Signed-off-by: Devansu <[email protected]>
Signed-off-by: Devansu <[email protected]>
240f1b4
to
78a6a25
Compare
Pre-flight checklist
Motivation
Described in #6472. Basically, this plugin enforces the use of
@theme/IdealImage
component instead of<img>
tags.Test Plan
Added tests using eslint's
RuleTester
utility.Test links
Deploy preview: https://deploy-preview-_____--docusaurus-2.netlify.app/
Related issues/PRs
#6472