Skip to content
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

chore(suite): use structuredClone for deep copying #6071

Closed
wants to merge 4 commits into from

Conversation

dahaca
Copy link
Contributor

@dahaca dahaca commented Aug 22, 2022

Description

Use window.structuredClone() for deep copying

@dahaca dahaca added the code Code improvements label Aug 22, 2022
export const getBitcoinNetwork = (pathOrName: number[] | string) => {
const networks = cloneCoinInfo(bitcoinNetworks);
const networks: BitcoinNetworkInfo[] = window.structuredClone(bitcoinNetworks);
Copy link
Contributor

@Nodonisko Nodonisko Aug 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't be necessary to use window and we should avoid that, because it will break code in other envs like RN or Node

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, this is a no go in connect-code. window is only allowed in connect-web package. I thinking if we could improve tooling to avoid this next time?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tests caught that as expected https://github.com/trezor/trezor-suite/runs/7961088382?check_suite_focus=true#step:7:227 still would be great to improve tsconfig to forbit using of window in ths project

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I apologize, of course -_- 13a81ec

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mroz22 maybe eslint will be better for this kind of stuff

@@ -52,7 +41,7 @@ export const getEthereumNetwork = (pathOrName: number[] | string) => {
};

export const getMiscNetwork = (pathOrName: number[] | string) => {
const networks = cloneCoinInfo(miscNetworks);
const networks: MiscNetworkInfo[] = window.structuredClone(miscNetworks);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you checked output in /lib that this is really correctly transpiled and polyfilled?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

even if it polyfilled correctly you would still need to persuade me that it is good :D

Copy link
Contributor

@Nodonisko Nodonisko Aug 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not? It is better to use build-in api than something DIY.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, it stays as just structuredClone() :(

Copy link
Contributor Author

@dahaca dahaca Aug 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it works in the connect part at all actually because of that

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from the discussion about backporting this to Node v16 (currently available from v17) nodejs/node#40756 (comment) 🤷

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe it's better to wait until we upgrade to a higher version of Node to start using this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is also running in the browser in iframe right? https://caniuse.com/mdn-api_structuredclone It is not supported in all Suite supported browsers. Connect should be supported in even more browsers than Suite.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created a separate util after all and only use it if available as discussed with @Nodonisko c21c178

Copy link
Contributor

@Nodonisko Nodonisko Aug 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems it is not polyfilling correctly so let's better wait

@dahaca dahaca force-pushed the feat/structured-clone branch from 13a81ec to c21c178 Compare August 24, 2022 11:43
@dahaca dahaca requested a review from karliatto as a code owner August 24, 2022 11:43
@@ -0,0 +1,15 @@
export const deepClone = <T>(value: T): T => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are ~ 12 more places where JSON.parse(JSON.stringify... is used, I guess it would be nice to use this util on all those places?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -0,0 +1,15 @@
export const deepClone = <T>(value: T): T => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest little bit restrict values that can be passed, because you can pass anything now I think, but I am not sure how JSON will behave if you will pass object with BigInt or other special types. It will work for structuredClone but JSON could mess it up, so we should limit it only types that will work 100% for both solutions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And now we are back to square 1 from which the conversation has started hehe :D Yeah, makes sense.

Copy link
Member

@karliatto karliatto Aug 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that we should consider that objects are going to be stringified when using JSON.pasrse(JSON.stringify....
I am not worried about current places where it is used (because it is already working) but in potential new uses where we think that this behaves like structuredClone and in in some scenarios it will not.

const appointment = {
    location: 'Prague',
    day: new Date(),
}

const whenStructuredClone = structuredClone(appointment)
whenStructuredClone.day.getDate()
// result -> 25

const whenStringified = JSON.parse(JSON.stringify(appointment))
whenStringified.day.getDate()
// result -> Uncaught TypeError: whenStringified.day.getDate is not a function

And the same for nested objects. And the same behavior can be expected from other objects like BigInt.

Restricting the use to types that will work 100% for both could be a solution but if I am not mistaken I think it should iterate over the whole object and nested potential objects to make sure there is no nested BigInt or other not working type.

Copy link
Contributor

@Nodonisko Nodonisko Aug 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think type like this should do the job:

import { JsonValue } from 'type-fest'

if (typeof structuredClone === 'function') {
clone = structuredClone(value);
} else {
clone = JSON.parse(JSON.stringify(value));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably use some better polyfill than this. There are already available.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never heard of it before, core-js has a polyfill. (I know we are cautious about included new dependencies, but just sharing).

https://github.com/zloirock/core-js#structuredclone

@matejkriz
Copy link
Member

let's wait for Node v17, closing as stale

@matejkriz matejkriz closed this Dec 7, 2022
@Nodonisko
Copy link
Contributor

Agree

@dahaca dahaca mentioned this pull request Jun 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
code Code improvements
Projects
No open projects
Archived in project
Development

Successfully merging this pull request may close these issues.

7 participants