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

Monkey Function v2 #174

Merged
merged 38 commits into from
Jun 30, 2020
Merged

Monkey Function v2 #174

merged 38 commits into from
Jun 30, 2020

Conversation

balazsbajorics
Copy link
Contributor

Fixes #149

Problem:
The antd Date Picker, once inserted, is not selectable on the Canvas.

Fix:
The problem was that the date picker didn't get the proper data-uid so we couldn't find it in the DOM. The reason why it didn't get that uid was that the existing monkey funciton implementation didn't cover the following case:

const ComponentA = (props) => <ComponentB>Hello</ComponentB>
const ComponentB = (props) => <div>{props.children}</div>

const App = (props) => <div><ComponentA data-uid="cica" /></div>

The above code would turn into the following DOM:

<div><div>Hello</div></div>

But what we want is this DOM:

<div><div data-uid="cica">Hello</div></div>

After poking at the monkey system I realized that this case was not supported at a conceptual level: the mokney would only run if there was already a data-uid to begin with, AND it would use the data-uid found at the time React.createElement is called. The latter is important and wrong because the entire monkey is built around the idea that we switch out the props of root elements before we give them to React. If we bind an old value of data-uid to an element, then later when we try to switch it, this switching will have no effect if we are not reading the latest of props['data-uid'].

Commit Details:

  • Rewrote the monkey patcher
  • Added a suite of unit tests specifically testing various monkey edge cases. Please let me know if I missed something here!
  • Used remaining goat blood to paint the shrine

Important Note
Unfortunately this PR increases the render counts :(
I believe the reason is that I am wrapping exotic components into a wrapper component, adds one more render count to each exotic component (fragments, memos, context, etc).
The bigger picture problem is that the monkey is (and always was) also monkeying our own UI code, but the previous version of the monkey was written in a way that it would instantly bail out if it did not find a data-uid whereas the new monkey aggressively wraps things because it anticipates a data-uid that only arrives halfway through the reconciliation (this is the fix for the original issue).

I believe the solution for the performance going forward is to figure out a way to disable the monkey for our own UI components, but I did not want to further bloat this Pr by the solution to that. I think technically the easiest solution (which would require a lot of labor unfortunately) would be to create a new pragma function that disables the monkey. We would need to add this pragma to every file that contains editor UI (all the inspector, navigator, filebrowser etc source files)

editor/package.json Outdated Show resolved Hide resolved
expect(errorsReportedSpyEnabled.length).toBe(0)
expect(errorsReportedSpyDisabled.length).toBe(0)
if (errorsReportedSpyEnabled.length > 0) {
throw new Error(`Canvas Tests, Spy Enabled: Errors reported: ${errorsReportedSpyEnabled}`)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this will still fail the test if there are errors, but it will also helpfully print those errors so it is easier to debug a test

@@ -59,8 +59,8 @@ describe('React Render Count Tests - ', () => {
)

const renderCountAfter = renderResult.getNumberOfRenders()
expect(renderCountAfter - renderCountBefore).toBeGreaterThan(720) // if this breaks, GREAT NEWS but update the test please :)
expect(renderCountAfter - renderCountBefore).toBeLessThan(740)
expect(renderCountAfter - renderCountBefore).toBeGreaterThan(855) // if this breaks, GREAT NEWS but update the test please :)
Copy link
Contributor

Choose a reason for hiding this comment

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

Oh my :/

Copy link
Contributor

Choose a reason for hiding this comment

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

Does that tie to a similar change in performance?

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 see a ~10 percent decrease in dragging FPS, but it is the local not-quite-production environment, so maybe the real difference is smaller.
in any case, we definitely should follow this up by disabling the monkey on the editor UI

Copy link
Member

Choose a reason for hiding this comment

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

I've created #181 and moved it into todo.

Copy link
Contributor

@seanparsons seanparsons left a comment

Choose a reason for hiding this comment

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

Nice enumeration of the test cases.

Co-authored-by: RheeseyB <1044774+Rheeseyb@users.noreply.github.com>

return realCreateElement(type, newProps)
} else {
const mangledChildren = React.Children.map(p.children, (child) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

We need to first check if the "children" is a single element or an array, otherwise we can break the element

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 believe react.children.map takes care of that

Copy link
Contributor

Choose a reason for hiding this comment

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

Nah unfortunately it doesn't. This was something that caused us a lot of pain with antd when we discovered this issue facebook/react#13355

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ughhh. fixed!

`)
})

it('works with a silly render prop', () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

So so horrible! Great job catching and covering this one

balazsbajorics and others added 9 commits June 30, 2020 12:13
* store the entire module object as the codeResultCache

* new transformCssNodeModule that runs the css append as a side effect of require

* evalresult contains a module instead of it being a module
* fix color picker's state

* Update color-picker.tsx

* fix dirty state name and type
@balazsbajorics
Copy link
Contributor Author

@Rheeseyb I updated the PR, could you take another look?

@@ -155,7 +155,7 @@
"@testing-library/react": "9.1.4",
"@testing-library/react-hooks": "2.0.1",
"@types/chai": "3.5.1",
"@types/chroma-js": "1.4.3",
"@types/chroma-js": "2.0.0",
Copy link
Contributor

Choose a reason for hiding this comment

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

?

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 think github is having a glitch. this is on master

Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like merging master fixed.

@balazsbajorics balazsbajorics merged commit b66f74d into master Jun 30, 2020
@balazsbajorics balazsbajorics deleted the fix/monkey-oh branch June 30, 2020 14:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Date picker is not selectable after insertion
6 participants