-
Notifications
You must be signed in to change notification settings - Fork 55
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
[Eslint-plugin] Add require-media-dimensions
rule
#323
Conversation
e2c1592
to
0e27f8b
Compare
|
||
const {docsUrl, polarisComponentFromJSX} = require('../utilities'); | ||
|
||
const POLARIS_MEDIA_COMPONENTS = ['Image']; |
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.
Thoughts on embedding this in the library itself as opposed to specifying it via the mediaElements
option on the consumer-end?
One advantage of the current approach is that we're able to analyze the import specifier and look at the source to ensure that it's actually from @shopify/polaris
and not an Image
component defined somewhere else which I imagine could cause problems for consumers.
// Require width and height attributes on media elements (temporarily disabled). | ||
'@shopify/require-media-dimensions': 'off', |
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.
When is a good time to turn this on?
enforce-media-dimensions
rulerequire-media-dimensions
rule
} | ||
|
||
const elementName = elementType(node.openingElement); | ||
const hasWidthProp = hasProp(node.openingElement.attributes, 'width'); |
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.
How will this handle scenarios where props are not explicitly passed to the component, such as:
const imgProps = {width: 600, height: 400};
return <img {...imgProps} />
There may be cases where we want to conditionally change what the values are set to that would make this approach useful, but it doesn't seem like the current linting setup would handle them. If this is a known limitation of the plugin that's okay but we should document it.
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.
Good catch! We can actually account for this, I'll work on a patch.
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.
Hm, probably best to not go down the rabbit hole of trying to account for all the possible ways the props can be dynamically passed to the component.
I wonder if we can work around an expected convention though like:
"the spread identifier must be a simple variable defined within the scope of the component for the lint rule to recognize its presence".
This'll make it easier to lookup and provide a site for these conditional props to be stored, otherwise the AST can get really complex when one starts to consider expressions like ...someObject.someOtherObject.imgProps
, ...getImgProps()
, ...getObject().someObject.imgProps
etc.
What are your thoughts on having such constraint around dynamic prop assignment vs not supporting it at all?
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 spread identifier must be a simple variable defined within the scope of the component
So long as this scope includes simple variables that have been imported that should be fine. For example, we want to be able to handle this use-case:
// image-props.js
export default { height: 100, width: 200 }
// component.js
import imageProps from './image-props';
function Component() {
return <img {..imageProps} />
That likely captures enough of our use case that it'd be acceptable, however it'd still be worth publishing a beta release with this new rule and testing it out in shopify/web
to see what the impact is.
Closing this. I don't want this to become a dumping ground for anybody in the org. If a team wants a new eslint rule then they can maintain their own package rather than trying to shoehorn everything into |
Description
There's a ton of unnecessary layout shifts that happen in the admin and other frontend apps across the org, a lot of which happen in bursts (when one or more individual layout shifts occur in rapid succession with less than 1-second in between each shift and a maximum of 5 seconds for the total window duration — see linked video). A common culprit for this is not specifying explicit dimension attributes for media elements.
Rendering media elements like
img
andvideo
in the browser without explicitly specifyingwidth
andheight
attributes often would cause an unexpected page movement/jump during load which could interrupt a user's current flow and potentially result in unintended actions which in some cases could be costly — this scenario is called a layout shift.However, when
width
andheight
attributes are specified upfront, modern browsers are able to compute an aspect ratio and reserve the right amount of space while the media loads, leaving only a paint task once the media is ready.In this video (slowed for illustrative purposes), you'll notice that the layout shifts significantly 4 times in about 2 seconds, which is a lot.
This rule is simply one step towards the right direction of minimizing these jumps — it enforces the presence of width and height attributes on standard media elements (
img
,video
), the PolarisImage
component, and provides an avenue to specify custom components and elements that should be analyzed for violations.There's still a lot that needs to be done to be able to really contain these shifts like exposing interfaces to specify media dimensions for compound components and components that render other media components like
EmptyState
,Thumbnail
etc.Type of change
@shopify/eslint-plugin
Minor: New feature (non-breaking change which adds functionality)Checklist