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

Add component diffing on event responses. #167

Merged
merged 1 commit into from
May 3, 2024
Merged

Conversation

richard-to
Copy link
Collaborator

@richard-to richard-to commented Apr 28, 2024

This change is gated by a flag called enable_component_tree_diffs. When enabled, the full component tree will not be returned in event responses. Instead only the changed component fields will be returned to the frontend. The frontend will then apply the diff to update its copy of the component tree.

A few notes:

  • Wasn't sure how to add unit tests for typescript. Is there a framework we're using?
  • I'd like to run the playwright tests with the diff flag enabled and without it enabled (right now it's enabled by default in the test). Haven't looked into this too much yet. Seems like there's a way to do it
    • Passing in a different config but that would lead to a lot of duplication (so probably rule this out)
    • Seems like we could pass in some environment variable to enable/disable the flag. Then we'd need to update the CI to run the tests twice.

Ref #62, #84

@wwwillchen
Copy link
Collaborator

Here's an example for a TS unit test:

import {EditorService} from '../services/editor_service';

ng_test_library(
name = "dev_tools_tests_lib",
srcs = glob(["*_spec.ts"]),
deps = [
":dev_tools",
"//mesop/web/src/editor",
"//mesop/web/src/services",
],
)
ng_web_test_suite(
name = "unit_tests",
deps = [
":dev_tools_tests_lib",
],
)

@wwwillchen
Copy link
Collaborator

Re: running w/ tests on and off - I think the environmental variable idea would work, you can also look at https://playwright.dev/docs/test-parameterize#introduction for some other ideas of how to parameterize test.

Also, I'd recommend adding some e2e tests with reasonably complex trees, multiple levels in the tree, different types of components & mutations (e.g. adding/deleting children) because most of our e2e tests are quite simple (usually 1 component with minimal hierarchy and mutations).

@wwwillchen wwwillchen self-requested a review April 29, 2024 06:50
Copy link
Collaborator

@wwwillchen wwwillchen left a comment

Choose a reason for hiding this comment

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

Left some comments. Overall, this is looking quite promising - great work!

mesop/protos/ui.proto Outdated Show resolved Hide resolved
mesop/protos/ui.proto Outdated Show resolved Hide resolved
mesop/runtime/context.py Show resolved Hide resolved
mesop/server/server.py Show resolved Hide resolved
mesop/server/server.py Outdated Show resolved Hide resolved
mesop/server/server.py Outdated Show resolved Hide resolved
mesop/web/src/services/channel.ts Outdated Show resolved Hide resolved
componentDiff !== undefined &&
this.rootComponent !== undefined
) {
// Angular does not update the UI if we apply the diff on the root
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's try to avoid copying the proto, which can be quite expensive.

I think we can solve this by modifying Shell's onRender function (

onRender: (rootComponent, componentConfigs) => {
) with:

this.changeDetectorRef.detectChanges();

We do this for markdown:

this.changeDetectorRef.detectChanges();

angular docs: https://angular.io/api/core/ChangeDetectorRef#detectchanges

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I tested this out. But I was getting weird behavior in the chat widget case. The streaming text wasn't showing updates as the text was being generated. So I kept the current copy behavior for now. I'll try again later.

mesop/component_helpers/helper.py Show resolved Hide resolved
mesop/component_helpers/helper.py Outdated Show resolved Hide resolved
@richard-to
Copy link
Collaborator Author

Re: running w/ tests on and off - I think the environmental variable idea would work, you can also look at https://playwright.dev/docs/test-parameterize#introduction for some other ideas of how to parameterize test.

Also, I'd recommend adding some e2e tests with reasonably complex trees, multiple levels in the tree, different types of components & mutations (e.g. adding/deleting children) because most of our e2e tests are quite simple (usually 1 component with minimal hierarchy and mutations).

Thanks for the pointer to the typescript tests. That worked for me.


Haven't got a chance to look into the Playwright flag stuff yet. Also haven't added more complex e2e examples, but agreed that it would be good to have them. Will get to those later this week.

@@ -62,9 +83,24 @@ def node_slot_children_count(self) -> int | None:
def set_current_node(self, node: pb.Component) -> None:
self._current_node = node

def set_previous_node_from_current_node(self) -> None:
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think this method is being called anywhere? I tried running your PR locally, but I don't actually see any component diffs happening, I think because this method isn't actually being used.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Doh, good catch. Looks like a regression when I added the reset_nodes method. It was supposed to call set_previous_node_from_current_node there.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I patched your CL but I still don't see any component diffs. If you check the Chrome DevTools console logs, the protos received from the server are logged there. I don't see any component diffs in the proto.

Copy link
Collaborator Author

@richard-to richard-to May 3, 2024

Choose a reason for hiding this comment

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

Ok, I think I got it working now 🤞🏾. Turns I didn't catch it because I was manually testing on the chat app which does the streaming response. But with the non-streaming response events it was not returning a diff. So basically the diff was not working on the first loop since previous node was not being set.

So that's the one thing I haven't figured out yet. I had to add back the original trace_mode loop code rather than existing early. However, I'm not sure why that works. I'm probably missing something pretty subtle.

Copy link
Collaborator

Choose a reason for hiding this comment

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

SGTM, we can debug this some more later.

@richard-to richard-to force-pushed the diff branch 2 times, most recently from d726a39 to c92fa7d Compare May 1, 2024 18:08
@richard-to
Copy link
Collaborator Author

Added an e2e test to better test more complex diffing scenarios.

This change is gated by a flag called `enable_component_tree_diffs`.
When enabled, the full component tree will not be returned in event
responses. Instead only the changed compnent fields will be returned
to the frontend. The frontend will then apply the diff to update its
copy of the component tree.
Copy link
Collaborator

@wwwillchen wwwillchen left a comment

Choose a reason for hiding this comment

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

LGTM - great job!

@richard-to richard-to merged commit a77be98 into google:main May 3, 2024
3 checks passed
@richard-to richard-to deleted the diff branch May 4, 2024 17:10
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.

2 participants