-
Notifications
You must be signed in to change notification settings - Fork 13
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
feat: fixed dimensions efficiency #1386
Conversation
}): JSX.Element => { | ||
const iframeRef = useRef<HTMLIFrameElement>(null) | ||
|
||
// we do not know what is being sent in passed props, so for stable reference, memoize using JSON representation | ||
const propsToPassNonMemoizedJSON = JSON.stringify(propsToPassNonMemoized) | ||
const propsToPass: any = useMemo( |
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.
I removed this as I think it was unnecessary extra memoization, though it's not strictly related to the goal of the ticket.
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.
I've tested this in dashboard with both visualization and custom plugin items and it works.
In both cases we have fixed dimensions for the dashboard items (they are saved as part of the dashboard "layout") so for us the most important thing is that a resize of the window or the single dashboard item (edit mode) does not trigger unnecessary renders of the plugin content which is likely fetching data.
The analytics data doesn't change when only the dashboard item dimensions change.
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.
Code looks functional 👍 thanks @edoardo for testing!
there would be problems if you switched the plugin from having fixed height/width to having autoresized dimensions
I think that's an okay tradeoff, and okay to do a slight "breaking change" since we consider the plugins experimental
Before approving, any reason height
and width
are still passed as props to the plugin? Removing those would simplify some of the propsToPass
logic
Other thoughts unrelated to this particular PR:
- Maybe unrelated functionally, but I recommend allowing the
height
andwidth
props to take strings too -- I think a relatively common use case will be to use values like100%
or50vh
as values for those... I thinknumber | string
as a type should work and be backwards compatible, since{ width: 100 }
will usepx
by default 🤔 - Some cleanup in the Plugin Loader would be good too -- I've noticed one prop update can cause 3 rerenders, I think due to the
setState
calls inreceivePropsFromParent
Thanks @KaiVandivier 🙏
I left them in there because I thought it was more logical given that app-platform logic expects them (https://github.com/dhis2/app-platform/blob/master/shell/src/PluginLoader.js#L173-L179), but yes we don't need to pass them ever and the first part of the logical check (e.g.
This is partly because with the resized height/width it will be pixels, so I guess it was easier conceptually to keep them the same, but that's not relevant now. The other issue is that, at least for me, the iframe does not interpret a number without a unit (e.g. you need to specify "500px" or "50vw" (this might be browser dependent, but in general putting "height: 500" gets interpreted as "height: 500px" and that is not happening when I define an iframe): I thought it would be easier to just have the definition be a number, but seems fair to expect that people would want to define the dimensions in other non-pixel units, so sure we could address that within this ticket. I've added in some logic to check if the dimension is a number without a unit, and if it is append 'px'; otherwise, return the original string (FYI: I confirmed that a number with percentage sign
Yes. There's definitely room for improvement 😄🫠 |
Thanks @KaiVandivier
Huh. For me that does not work, and it's not converted to px directly in the code 🤔
I don't really remember why I put them in |
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.
Nice! 🙂 One last thing then:
services/plugin/src/Plugin.tsx
Outdated
height?: string | ||
width?: string |
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.
Allow number
as a prop type?
height?: string | |
width?: string | |
height?: number | string | |
width?: number | string |
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.
I don't know? I thought that it was more standard to define dimension as a string in the sense that it's supposed to include the unit: https://developer.mozilla.org/en-US/docs/Web/CSS/dimension
Are we seeing this as a compromise implementation? For example, update the prop type to take number, but not update the component documentation, such that we don't "advertise" this?
I guess that could be okay, as we probably don't want to promote numbers, since we're now relying on the iframe + browser implementation to convert 500
to 500px
.
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.
I don't actually see it as a compromise implementation; my intention is to match the behavior of the HTML iframe
height
attribute, which is a bit different than CSS requirements
It's a little hard to get formal documentation on what the accepted values actually are for iframe.height, but MDN at least indicates it can be a number, and the autocomplete in VSCode indicates it can be a number or a string
Out of curiosity, when passing just 500
to the height
attribute and it didn't work to get converted to px
in the browser styles, was it formatted as a string? I wonder if that makes a difference...
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 mdn iframe reference says it’s a number (in pixels), but then the example shows a string-representation of a number, so I don't know at this point. It works for me to pass a number, a string-representation of a number, or a string with px
or another unit specified. I don't really know what the limits are so I'll just update the type definition and leave the docs alone.
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#height
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.
Why not update the docs? I think it makes sense to reflect the actual API
Does it still seem like a compromise to you? It seems standard to me since it mimics the iframe.height
types, and based on our testing, seems well-supported -- I'm not sure why a number didn't work in one of your tests, but it seems a bit like a fluke
# [3.11.0](v3.10.6...v3.11.0) (2024-09-10) ### Features * fixed dimensions efficiency ([#1386](#1386)) ([2b07a14](2b07a14))
🎉 This PR is included in version 3.11.0 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
# [3.11.0-alpha.1](v3.10.4-alpha.1...v3.11.0-alpha.1) (2024-11-26) ### Bug Fixes * **cacheable-section:** synchronously flush recording state for UI consistency ([04bc604](04bc604)) * add endpoint to text plain matchers ([#1390](#1390)) ([de8fbec](de8fbec)) * expand FetchErrorDetails type ([#1389](#1389)) ([78ad0b3](78ad0b3)) * handle alert returned async by parentAlertsAdd [LIBS-695] ([#1388](#1388)) ([bba9c23](bba9c23)) * **cacheable-section:** stable references to avoid loops [LIBS-642] ([#1385](#1385)) ([31562e9](31562e9)) * update plugin sizing definition ([#1383](#1383)) ([38c09b9](38c09b9)) * **deps:** remove cli-app-scripts peer dep [LIBS-587] ([#1379](#1379)) ([9e22e88](9e22e88)) * **deps:** update cli-app-scripts for package/types race condition ([dee6795](dee6795)) ### Features * fixed dimensions efficiency ([#1386](#1386)) ([b56ad2d](b56ad2d)) * upgrade app-runtime React version to v18 ([#1387](#1387)) ([0e4a3d5](0e4a3d5))
Implements LIBS-673
Key features
This PR cleans up some communication of height/width and related functions for resetting those dimensions to improve performance.
Description
When we discussed the api, we decided that:
This PR attempts to improve the implementation to separate fixed height/width (props) from resizedHeight/resizedWidth (in state, for plugins that do not provide a dimension and hence indicate that there should be autoresizing)
Checklist
Known issues
In issue of simplicity, I am just updating app-runtime. The implementation in app-shell could also be cleaned up to improve some logic (https://github.com/dhis2/app-platform/blob/master/shell/src/PluginLoader.js#L173-L179).
At the moment, since I have updated the memoization to exclude checking for changes on height/width, there would be problems if you switched the plugin from having fixed height/width to having autoresized dimensions. I think that it is unlikely that one would update the component in that way (🤷♂️), and the extra implementation to handle this would defeat the purpose of stopping the communication of height/width for fixed-dimension plugins. This might be something we could revisit if there are objections?
In approaching this, I decided to be relatively minimal, though I do wonder if we should consider how we want to keep plugin logic aligned between app-runtime and app-platform aligned going forward.