Skip to content
This repository was archived by the owner on Sep 30, 2024. It is now read-only.

Use mutation events for injections mounts too#3191

Merged
felixfbecker merged 6 commits intomasterfrom
inject-on-mutation-events
Apr 3, 2019
Merged

Use mutation events for injections mounts too#3191
felixfbecker merged 6 commits intomasterfrom
inject-on-mutation-events

Conversation

@felixfbecker
Copy link
Contributor

@felixfbecker felixfbecker commented Apr 3, 2019

#2909 used a mutation observer for code view detection, but still called the inject* functions on every mutation event. It turns out ReactDOM.render() is not idempotent and triggered mutation events in Firefox, resulting in an infinite loop of mutation events.
The solution is to only re-render the mounts when a node was added to the DOM that should contain a mount, which means the render only happens once.

To accomplish that, this PR changes all get*Mount functions to receive a container. The mount getter needs to check if the mount belongs into the container, if yes get or create the mount inside, otherwise return null.
The mount getters are then called with addedNodes from mutation events.

This necessitates other changes:

  • We can't use React context for telemetry anymore, see Stop using React context API #3180. This refactors the webapp to use props instead (also renames eventLogger to telemetryService for consistency / easier passing).
  • The HoverOverlayContainer component had unneeded code in it (portals, hover overlay mount container container) that I removed
  • componentWillUnmount() and handling Subscriptions was missing in some places

Fixes #3180
Fixes #3166

Test plan:

  • GitHub
  • GHE
  • Gitlab
  • Phabricator
  • Bitbucket

x (Chrome, Firefox)

@felixfbecker felixfbecker added bug An error, flaw or fault that produces an incorrect or unexpected result, or behavior. browser-extension labels Apr 3, 2019
@felixfbecker felixfbecker requested a review from lguychard April 3, 2019 11:25
@felixfbecker felixfbecker requested a review from dadlerj as a code owner April 3, 2019 11:25
Copy link
Contributor

@lguychard lguychard left a comment

Choose a reason for hiding this comment

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

Code changes LGTM.

Could we add a unit test in code_intelligence.test.tsx that reproduces the issue we ran into? Something like this:

    test('only renders elements if their mount locations have been emitted in mutations', async () => {
        const { services } = await integrationTestContext()
        const mutations = new Subject<MutationRecordLike[]>()
        const globalDebugMount = createTestElement()
        const getGlobalDebugMount: MountGetter = container => (container === globalDebugMount ? globalDebugMount : null)
        subscriptions.add(
            handleCodeHost({
                mutations: mutations.pipe(startWith([{ addedNodes: [document.body], removedNodes: [] }])),
                codeHost: {
                    name: 'test',
                    check: () => true,
                    getGlobalDebugMount,
                },
                extensionsController: createMockController(services),
                showGlobalDebug: true,
                ...createMockPlatformContext(),
            })
        )
        // Simulate the MutationObserver firing after each React render (this happens on FF)
        RENDER.mockImplementation(() => {
            mutations.next([{ addedNodes: [], removedNodes: [] }])
        })
        // Simulate mount being added to the DOM
        mutations.next([{ addedNodes: [globalDebugMount], removedNodes: [] }])
        expect(elementRenderedAtMount(globalDebugMount)).not.toBeUndefined()
    })

})
)
// Render command palette
if (codeHost.getCommandPaletteMount) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Potential bug here: if the MountGetter is not precise enough (for example if its selector is too generic) and returns non-null results for several addedNodes, we could render several elements.

This is hypothetical, I'd estimate the likelihood of it actually happening to be pretty low.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can you give an example? Which selector do you mean, the one that gets the container or the one that checks the preexisting element?

Copy link
Contributor

Choose a reason for hiding this comment

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

Consider this:

const getCommandPaletteMount: MountGetter = (container: HTMLElement): HTMLElement | null => {
  const headerElement = querySelectorOrSelf(container, '.aui-header-primary .aui-nav')
  if (!headerElement) {
   return null
  }
 
...
}

If '.aui-header-primary .aui-nav' matches for n separate added nodes, we will inject the command palette n times.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, the functions will have to ensure that doesn't happen 👍

@felixfbecker felixfbecker force-pushed the inject-on-mutation-events branch from faac923 to 1c039a3 Compare April 3, 2019 13:26
@felixfbecker felixfbecker modified the milestones: 3.4, 3.3 Apr 3, 2019
lguychard and others added 2 commits April 3, 2019 16:06
Co-Authored-By: felixfbecker <felix.b@outlook.com>
Co-Authored-By: felixfbecker <felix.b@outlook.com>
@felixfbecker felixfbecker merged commit f515ed1 into master Apr 3, 2019
@felixfbecker felixfbecker deleted the inject-on-mutation-events branch April 3, 2019 14:13
@sentry
Copy link

sentry bot commented Apr 3, 2019

Sentry issue: BROWSER-EXTENSION-Q5

@sentry
Copy link

sentry bot commented Apr 3, 2019

Sentry issue: BROWSER-EXTENSION-NB

@sentry
Copy link

sentry bot commented Apr 3, 2019

Sentry issue: BROWSER-EXTENSION-PZ

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

browser-extension bug An error, flaw or fault that produces an incorrect or unexpected result, or behavior.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants