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

feat(store-devtools): provide the ability to connect extension outside of Angular zone #3970

Merged
merged 2 commits into from
Jul 28, 2023

Conversation

arturovt
Copy link
Contributor

This commit updates the extension connection setup and wraps it with runOutsideAngular to prevent running change detection too frequently. This ensures that change detection is only triggered when all asynchronous actions have been processed.

Closes #3839

@netlify
Copy link

netlify bot commented Jul 24, 2023

Deploy Preview for ngrx-io ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit 62a86bf
🔍 Latest deploy log https://app.netlify.com/sites/ngrx-io/deploys/64c3e1dae80a2c00081bce95
😎 Deploy Preview https://deploy-preview-3970--ngrx-io.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

Copy link
Member

@timdeschryver timdeschryver left a comment

Choose a reason for hiding this comment

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

It seems like with this change importing an existing state throws an error.
This should be resolved first, or this should be added to the docs.

reducer.ts:75  ERROR Error: Action '[Auth/API] Login Redirect' running outside NgZone. https://ngrx.io/guide/store/configuration/runtime-checks#strictactionwithinngzone
    at inNgZoneAssert_reducer.ts:11:13
    at serialization_reducer.ts:24:23
    at immutability_reducer.ts:11:23
    at utils.ts:139:14
    at computeNextEntry (reducer.ts:72:17)
    at recomputeStates (reducer.ts:122:9)
    at reducer.ts:533:24
    at StoreDevtools.liftedStateSubscription.liftedAction$.pipe.state (devtools.ts:96:38)
    at scanInternals.js:14:21
    at OperatorSubscriber._this._next (OperatorSubscribe
[state.txt](https://github.com/ngrx/platform/files/12147326/state.txt)
r.js:33:21)
handleError @ core.mjs:10072
computeNextEntry @ reducer.ts:75
recomputeStates @ reducer.ts:122
(anonymous) @ reducer.ts:533
StoreDev
[state.txt](https://github.com/ngrx/platform/files/12147295/state.txt)
tools.liftedStateSubscription.liftedAction$.pipe.state @ devtools.ts:96

You can reproduce this by running the example app and importing my export.

npx nx serve example-app

@arturovt
Copy link
Contributor Author

@timdeschryver thanks for checking, I haven't imported the state and haven't checked that case, I'll have a look. It actually should keep functioning seamlessly w/o breaking changes, so I'd fix it.

Copy link
Member

@timdeschryver timdeschryver left a comment

Choose a reason for hiding this comment

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

LGTM.
@arturovt could this change an existing's app behavior (does this have any caveats to it)?

@arturovt
Copy link
Contributor Author

arturovt commented Jul 27, 2023

@timdeschryver I'll post my thoughts aloud so we can discuss the concerns which I think about:

  • this change may cause breaking issues in unit tests that implicitly depend on a specific number and sequence of change detections to pass their assertions. However, I am not sure if someone is unit testing the Redux plugin, which is available only in the browser. This means that we might eliminate the reason for this to be a breaking change.
  • the DevtoolsExtension (which has the createChangesObservable method) is not exposed publicly to end users through the NgRx API, which means I'm not sure if someone would explicitly subscribe to createChangesObservable and be affected by the fact that subscriber events would be coming from outside the Angular zone.
  • the StoreDevtools is exposed publicly. Its public properties, which may be read by end users, are liftedState and state. The state basically pipes the liftedState. The liftedState is obtained from liftedStateSubject.asObservable(), where liftedStateSubject always calls its next within the Angular zone, since we call enterNgZone() previously.

Wdyt?

@timdeschryver
Copy link
Member

@arturovt thanks for the elaborate answer.

  • I would assume no projects are using devtools to unit test their components (I don't think this will break e2e tests)
  • I also assume no projects are interacting with the devtools within their "user code".

The question was more about if this change could break existing application because the result of this change is that it won't trigger the CD as much as before.
But, that's probably not the case, since most of the apps turn devtools off in production.

The other thing I was thinking about are applications that don't rely on NgZone.

@arturovt
Copy link
Contributor Author

Apps which have the NgZone noopped won’t be affected since NgZone class is substituted with NoopNgZone which does nothing (just invokes callbacks directly).

@brandonroberts
Copy link
Member

I do think that there is a possibility of this being an unexpected change in behavior from those who are including the Devtools in production, which I know there are cases of this out there.

That being said, we always recommend not doing this, so we could be covered in that case.

@arturovt
Copy link
Contributor Author

@brandonroberts following what you said, can we also have a console.warn for production that logs smth like "Plugin is not recommended to be used in production"?

@brandonroberts
Copy link
Member

brandonroberts commented Jul 27, 2023

I don't think that's necessary, but we could add that to the docs to be more clear.

The other option would be to have this behind a flag, such as:

provideStoreDevtools({
  ngZone: 'enabled' | 'noop'
});

And have it default to enabled for now, and you can change it to noop. In the future, we flip it to noop by default. That way, we keep existing behavior as-is for now, while allowing the new behavior going forward.

@timdeschryver
Copy link
Member

I like that suggestion @brandonroberts 👍

@arturovt
Copy link
Contributor Author

Alright, so I should re-work the changes and add a new config property?

@brandonroberts
Copy link
Member

@arturovt yes

@arturovt arturovt force-pushed the fix/3839 branch 2 times, most recently from 4dfbae7 to 6e181f8 Compare July 27, 2023 17:07
modules/store-devtools/src/config.ts Outdated Show resolved Hide resolved
modules/store-devtools/src/devtools.ts Outdated Show resolved Hide resolved
modules/store-devtools/src/devtools.ts Outdated Show resolved Hide resolved
modules/store-devtools/src/devtools.ts Outdated Show resolved Hide resolved
modules/store-devtools/src/extension.ts Outdated Show resolved Hide resolved
modules/store-devtools/src/extension.ts Outdated Show resolved Hide resolved
modules/store-devtools/src/extension.ts Outdated Show resolved Hide resolved
@brandonroberts brandonroberts added the Needs Cleanup Review changes needed label Jul 28, 2023
@arturovt arturovt force-pushed the fix/3839 branch 2 times, most recently from e0ac856 to e738780 Compare July 28, 2023 15:12
…of Angular

This commit updates the extension connection setup and wraps it with `runOutsideAngular`
to prevent running change detection too frequently. This ensures that change detection is
only triggered when all asynchronous actions have been processed.

Closes ngrx#3839
@markostanimirovic markostanimirovic changed the title fix(store-devtools): reduce CD cycles by listening message outside of Angular feat(store-devtools): provide the ability to connect extension outside of Angular zone Jul 28, 2023
Copy link
Member

@markostanimirovic markostanimirovic left a comment

Choose a reason for hiding this comment

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

LGTM 👍 Thanks @arturovt!

@markostanimirovic markostanimirovic merged commit 1ee80e5 into ngrx:main Jul 28, 2023
5 checks passed
@arturovt arturovt deleted the fix/3839 branch July 28, 2023 16:53
@timdeschryver
Copy link
Member

Thanks @arturovt !

@alex-okrushko
Copy link
Member

Thanks for the fix @arturovt !
I ran into this issue myself, and when debugging I noticed it led back to ngrx/store-devtools 😱

@brandonroberts @markostanimirovic @timdeschryver I think it would make sense to have runOutsideAngular be enabled by default. I know it's a "change in behavior" but it's fixing something that should not have been there to begin with - app shouldn't rely on arbitrary change detection triggers outside of the app.

@brandonroberts
Copy link
Member

Thanks for the fix @arturovt ! I ran into this issue myself, and when debugging I noticed it led back to ngrx/store-devtools 😱

@brandonroberts @markostanimirovic @timdeschryver I think it would make sense to have runOutsideAngular be enabled by default. I know it's a "change in behavior" but it's fixing something that should not have been there to begin with - app shouldn't rely on arbitrary change detection triggers outside of the app.

Agreed. We can possibly land this change as part of the 17.x release and do a migration for existing apps also to keep the current behavior.

@markostanimirovic
Copy link
Member

Thanks for the fix @arturovt ! I ran into this issue myself, and when debugging I noticed it led back to ngrx/store-devtools 😱

@brandonroberts @markostanimirovic @timdeschryver I think it would make sense to have runOutsideAngular be enabled by default. I know it's a "change in behavior" but it's fixing something that should not have been there to begin with - app shouldn't rely on arbitrary change detection triggers outside of the app.

Sounds good to me 👍

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.

Remove dev tools event listener from zone.js detection
5 participants