[Image][Performance] Fast Image with Auth Token Header Caching#12648
[Image][Performance] Fast Image with Auth Token Header Caching#12648Beamanator merged 18 commits intoExpensify:mainfrom
Conversation
|
CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅ |
|
@aldo-expensify Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
|
I have read the CLA Document and I hereby sign the CLA |
aldo-expensify
left a comment
There was a problem hiding this comment.
Please commit suggestion to fix linter errors
|
@thomas-coldwell can you retroactively sign your commits? please We will also need you to complete the PR Author steps:
Thanks! Asked here about it: #10792 (comment) |
|
Will get those sorted now @aldo-expensify cheers! |
15bc0dc to
df2ded5
Compare
Signed-off-by: Thomas Coldwell <31568400+thomas-coldwell@users.noreply.github.com>
Signed-off-by: Thomas Coldwell <31568400+thomas-coldwell@users.noreply.github.com>
Co-authored-by: Aldo Canepa Garay <87341702+aldo-expensify@users.noreply.github.com> Signed-off-by: Thomas Coldwell <31568400+thomas-coldwell@users.noreply.github.com>
df2ded5 to
98c2590
Compare
|
Looks like we need to have a think about how this should work on Desktop and Web (inc. mWeb) before this PR is merged cc @Beamanator |
|
Yo @thomas-coldwell so correct me if I'm wrong but I had two assumptions in regard to web / desktop:
|
|
Hey @Beamanator you are correct - there is no implementation of |
|
Sorry I am going OOO, so I won't be able to take this. Please re-assign. |
|
🚀 Deployed to staging by @Beamanator in version: 1.2.31-0 🚀
|
|
@thomas-coldwell Seems like this PR has introduced a deploy blocker. Looking into this. I will prepare a revert of this PR if the solution is not obvious. |
Revert "Merge pull request #12648 from margelo/@thomas/fast-image-cac…
There was a problem hiding this comment.
Since this was reverted and I studied the logic a bit, I'll leave a review to help the next PR
I have a question about the name FastImage
Why was it decided to call App's component FastImage instead of simply Image
Due to the differences in platform code, some confusion and quirks exists
onLoadis called with one parameter structure inFastImageand another inreact-native(web) Image
(FastImage onLoad | RN onLoad)FastImagehas different static methods exposed and methods likepreloadacceptsourceand evensourcearray, while in RN it's just auri: string
When I see FastImage I would assume all the react-native-fast-image options are available to this component, but since our FastImage implementation for web/desktop so far is only a core Image component they won't work
I think it a possible improvement for a follow up PR is to
- use a simple name like
ImageorAppImagefor the component - add a specific
propTypes.jsinterface that implement only the minimum props we use
This way we can declare the source we support ATM is number | string | { urI: string, headers: object } e.g. nothing conflicting with the differences between source structure between FastImage and regular Image
I think the change is necessary, because
- we might or might not update
react-native-fast-imagewith (full) support forweb - it might take time or not be a priority to apply these updates to
react-native-fast-image - so a clean interface of exactly what we use would be helpful in maintaining the cross platform App Image component
| */ | ||
| downloadAttachment(sourceURL) { | ||
| fileDownload(sourceURL, this.props.originalFileName); | ||
| fileDownload(this.props.isAuthTokenRequired ? addEncryptedAuthTokenToURL(sourceURL) : sourceURL, this.props.originalFileName); |
There was a problem hiding this comment.
@Beamanator
We can update fileDownload to also work with headers.
Not sure whether any backend handling would need to be updated
making fileDownload work with headers is not as important as images, because it's used a lot less often
on the other hand the logic would be cleaner and allow automatic cache usage
| } | ||
|
|
||
| render() { | ||
| const headers = this.props.isAuthTokenRequired ? chatAttachmentTokenHeaders() : undefined; |
There was a problem hiding this comment.
IMO it might be better to forward isAuthTokenRequired to the Image and let the Image run this logic instead of having it repeat for any subtype of Image we have
| export default withOnyx({ | ||
| session: {key: ONYXKEYS.SESSION}, | ||
| })(ImageWithSizeCalculation); |
There was a problem hiding this comment.
As pointed out in another comment - this is unused
|
|
||
| let encryptedAuthToken = ''; | ||
| Onyx.connect({ | ||
| key: ONYXKEYS.SESSION, | ||
| callback: session => encryptedAuthToken = lodashGet(session, 'encryptedAuthToken', ''), | ||
| }); |
There was a problem hiding this comment.
@Beamanator
This is not the "React Way" to deal with global or storage state
It's a bit of an antipattern actually because it doesn't integrate with component lifecycle - only a re-render would cause users of chatAttachmentTokenHeaders to re-evaluate, but the change in ONYXKEYS.SESSION would not trigger a re-render, unless the component is also subscribed to session
The "React Way" is to capture this with withOnyx so the component is subscribed to session and re-evaluates headers the moment they change
To keep it simple the withOnyx can be applied on the core Image (FastImage) component and let it perform the logic from this file
I know we use the static Onyx.connect logic for other cases, but we should distinct the cases that really need it and the cases that can use withOnyx instead
Another bad thing about the static pattern is that it is static - we can't lazy load it and the connection stays forever, while using the "React Way" would free resources
- the connection can be initiated only when needed
- the connection is released when the component is no longer mounted
There was a problem hiding this comment.
Gooooood points, I overlooked those lifecycle points & didn't think about lazy loading / freeing resources, I'll definitely keep those in mind in the future! Next round will not do this this way ;D
|
🚀 Deployed to staging by @Beamanator in version: 1.2.32-0 🚀
|
|
cc @thomas-coldwell, thanks for the review @kidroca |
|
For the next round of QA, @Beamanator @aldo-expensify can we get a regression test suite from Testrail to ensure nothing breaks! |
|
🚀 Deployed to production by @luacmartins in version: 1.2.32-2 🚀
|
|
🚀 Deployed to production by @luacmartins in version: 1.2.32-2 🚀
|
|
@kidroca thanks for the review, I'll also request your review on the follow-up PR when it's ready :D 🙏
I thought It looks like we currently often use standard react native component names when we customize them, and if we want to directly use a react native component (like @thomas-coldwell When the follow-up PR is ready can you please tag me & request a review from @kidroca as well please? 👍 |
|
Hey @kidroca @Beamanator thanks for those points!
I'll link the follow-up PR here shortly and make sure you are both set to review it :) |
|
Just addressing the issue on Android that caused this PR to be reverted and hoping you might be able to provide a bit more context around this. The issue originated from the fact that As a result the initial width/height for the thumbnail component (specifically in the case of a PDF thumbnail) style will always be zero and this is never updated or corrected by the I will continue to see what can be solved on the |
|
Innnteresting findings @thomas-coldwell ! I just found in our back-end code, we currently use PHP's getfilesize function to try to get the file size (here, for internal employees). And because this doesn't actually work for @thomas-coldwell what I'm planning to try next is:
|
|
Cool I followed steps 1 & 2, tested with the old code, things looked good! I hard-coded to 30px by 30px in the test which is why it turned out so small, but I will tweak it so it looks fine & I'll test on other platforms to make sure it doesn't break anything while we're waiting for the next version of @thomas-coldwell 's PR Screen.Recording.2022-12-02.at.3.35.22.PM.mov |
|
@Beamanator the code to proceed the upload is same for OldDot as well, right. does it parse receipts too? we should probably try to avoid manipulating that flow now if that is the case. |
|
@vitHoracek here's the draft PR: https://github.com/Expensify/Web-Expensify/pull/35730 the code is only used when adding comments to reports, so I don't think it parses receipts 'n such, but feel free to comment on that PR if you have concerns! I'm still working on testing that it doesn't break things :D |
|
@Beamanator no problem, I trust you :D just wanted to raise this |
|
Thanks @Beamanator and @mountiny - great that this change server-side does ensure a non-zero width and height. I will get the changes in for the Fast Image |
|
That would be very helpful, thanks @thomas-coldwell ! |
|
Here's the draft PR @Beamanator - just travelling atm, but started doing some digging on the revert issue #13304 😃 |
|
Thanks @thomas-coldwell ! Will respond in that new PR 👍 |
Details
This PR combines the draft PR from @Szymon20000 #11009 for adding fast image and the PoC auth token PR from @Beamanator #12146 to properly cache images using fast image with the auth token being passed in the headers rather than the URL.
Fixed Issues
#10792
$ GH_LINK
PROPOSAL: GH_LINK_ISSUE(COMMENT)
Tests
QA Steps
PR Author Checklist
### Fixed Issuessection aboveTestssectionQA stepssectiontoggleReportand notonIconClick)src/languages/*filesWaiting for Copylabel for a copy review on the original GH to get the correct copy.STYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)/** comment above it */thisproperly so there are no scoping issues (i.e. foronClick={this.submit}the methodthis.submitshould be bound tothisin the constructor)thisare necessary to be bound (i.e. avoidthis.submit = this.submit.bind(this);ifthis.submitis never passed to a component event handler likeonClick)StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)Avataris modified, I verified thatAvataris working as expected in all cases)PR Reviewer Checklist
The reviewer will copy/paste it into a new comment and complete it after the author checklist is completed
### Fixed Issuessection aboveTestssectionQA stepssectiontoggleReportand notonIconClick).src/languages/*filesWaiting for Copylabel for a copy review on the original GH to get the correct copy.STYLE.md) were followedAvatar, I verified the components usingAvatarhave been tested & I retested again)/** comment above it */thisproperly so there are no scoping issues (i.e. foronClick={this.submit}the methodthis.submitshould be bound tothisin the constructor)thisare necessary to be bound (i.e. avoidthis.submit = this.submit.bind(this);ifthis.submitis never passed to a component event handler likeonClick)StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)Avataris modified, I verified thatAvataris working as expected in all cases)Screenshots
Web
Mobile Web - Chrome
Mobile Web - Safari
Desktop
iOS
Android