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

Merge React 18 feature branch #3050

Merged
merged 13 commits into from
May 24, 2023
Merged

Conversation

JamesBurnside
Copy link
Member

@JamesBurnside JamesBurnside commented May 15, 2023

What

Merge of base PRs:

Why

Merge short term solution for react 18, see #2939 & #1900.

How Tested

Selfhosting and bug bashes.

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

github-actions bot commented May 15, 2023

Calling bundle size is decreased✅.

  • Current size: 9813746
  • Base size: 9815637
  • Diff size: -1891

@github-actions
Copy link
Contributor

github-actions bot commented May 15, 2023

CallWithChat bundle size is decreased✅.

  • Current size: 10227599
  • Base size: 10228351
  • Diff size: -752

@github-actions
Copy link
Contributor

github-actions bot commented May 15, 2023

Chat bundle size is increased❗.

  • Current size: 9873045
  • Base size: 9872844
  • Diff size: 201

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

},
"devDependencies": {
"@babel/cli": "~7.16.0",
"@babel/core": "~7.16.0",
"@microsoft/api-documenter": "~7.12.11",
"@microsoft/api-extractor": "~7.18.0",
"@types/jest": "~26.0.22",
"@types/react": "^16.9.49",
"@types/react": "18.2.0",
Copy link
Member

Choose a reason for hiding this comment

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

Do we need to run react 16 compatibility test by any chance?
BTW, why not use ^ to get latest update for react 18

Copy link
Member Author

Choose a reason for hiding this comment

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

This should be pinned to the same as react so this should be whatever react is. Really they should probably all be ~ or ^ but we don't have good repo-wide guidenence on what developers should choose. Should we set a standard now and update guidence in the wiki?

Copy link
Member Author

Choose a reason for hiding this comment

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

And yeah we will need that, I have something cooking up on the side but haven't had time for it, will be similar to the typescript check
image

Copy link
Member

Choose a reason for hiding this comment

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

Yea, would be nice to always get latest bit of the current compatible version, cause it might be something unexpected happening there (very rare though) then we can catch it earlier than our customer (cause customers prefer those "^" for versions)

Copy link
Member Author

Choose a reason for hiding this comment

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

I will keep this change for a separate PR, made a bug for it for tracking Bug 3279379: [Web] Repo should be consistent and have guidence on using a pinned dep version vs ^ or ~

"build:watch": "",
"copy-northstar": "cpx \"../northstar-wrapper/dist/dist-esm/**/*\" dist/dist-esm/northstar-wrapper/src --clean",
Copy link
Member

Choose a reason for hiding this comment

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

Just out of curiosity, why do we need to do this copy and paste?

Copy link
Member Author

Choose a reason for hiding this comment

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

We need the webpack output from the build. Currently our meta package rebuilds everything itself and hence tsc doesn't use the webpack output. This was the simplest way I found to have the webpack bits in the final npm package (but very open if you find a way to instead have tsc grab the webpack output instead of retranspiling the src code, pointing tsconfig straight at the dist output wasn't working :/)

Copy link
Member

Choose a reason for hiding this comment

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

Yea.. within the internal packages, it will try to use src folder instead (and that's why we use copy-preprocess), btw, I guess doing copy-northstar in the end means we want it to be packaged and consumed by customer, but our own build process doesn't need it?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah that's correct, it does mean we have gaps where parts of our build system is using the webpack output and other parts just directly grabs the n* code from the northstar-wrapper/node_modules :/

@@ -1,8 +1,19 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import * as northStar from '@fluentui/react-northstar';
import {
Copy link
Member

Choose a reason for hiding this comment

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

Any concerns that we don't do import * ? is it for treeshaking

Copy link
Member Author

Choose a reason for hiding this comment

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

The question is why we would do * at all. We don't want to allow exports from n* so we want to keep this to a minimal set such that we don't allow developers to accidentally introduce new reliances on northstar

Copy link
Member

Choose a reason for hiding this comment

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

So this is just what we are wrapping up? if someone were to add to this list would anything else need to be done or would it just auto pull it at build time?

Copy link
Member Author

Choose a reason for hiding this comment

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

Nothing needs done it will automatically work - but actually wish it didn't just work. Someone should not be adding to this list. We want to get further away from n* not be more reliant on it

Copy link
Member

Choose a reason for hiding this comment

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

Are we saying we developers could import NorthStar component from our package? I guess we don't expose them as a public api right?

Copy link
Member Author

Choose a reason for hiding this comment

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

nope, just internal developers to this repo, not npm package users

@@ -3,36 +3,43 @@
"version": "1.5.1-beta.4",
"private": "true",
"description": "Package to wrap the Fluent NorthStar UI library, for short-term React 18 compatibility",
"module": "dist/dist-esm/index.js",
Copy link
Member

Choose a reason for hiding this comment

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

I guess we will generate both esm and cjs code in our npm package? How much bigger our npm packages will be in the end

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, cjs is needed for anything that runs in node as it is still lagging behind on the esm support. Really, production builds of sites should always be using the esm output as it supports tree shaking and cjs should only be used for node if at all.
Re: size of the npm package, do we care? the package will be slightly bigger, but the npm dependencies will be far smaller as it no longer needs to pull in all of n* and all its dependencies

Copy link
Member

Choose a reason for hiding this comment

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

Yea... I agree with production build should always use esm, but still there would be some app living in cjs world for some legacy reasons, so we might still want to support that well

For npm package, that is just a question out of curiosity, I did receive a feedback from webchat team asking about the npm package size, but it shouldn't matter too much in the end

Copy link
Member Author

Choose a reason for hiding this comment

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

True, and we do support cjs, we just don't optimize any bundles. However anyone using this in cjs will actually receive a benefit because they don't have to rollup the entire n* library, the small pieces needed are now directly bundled by us so smaller package overall (unless of course they use both us and n* in their app and are bundling using cjs, then some n* parts will be bundled twice)

"scripts": {
"build": "tsc",
"build": "rushx build:esm && rushx build:cjs",
"build:esm": "tsc && webpack -c ./webpack.esm.config.js && rushx api-extractor",
Copy link
Member

Choose a reason for hiding this comment

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

If that is esm, will webpack bundle them into one file or several files like all the other packages?

Copy link
Member Author

Choose a reason for hiding this comment

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

Still one file, but a file that has treeshaking support (treeshaking can still strip out unused exports in the same file)

Copy link
Member

Choose a reason for hiding this comment

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

Lets open a work item to validate that later including find a solution for treeshaking localization part

Copy link
Member

@emlynmac emlynmac left a comment

Choose a reason for hiding this comment

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

Just some questions, but looks good!

@@ -87,7 +87,7 @@ test.describe('Vertical gallery resizing tests', async () => {
await waitForSelector(page, dataUiId(IDS.verticalGalleryVideoTile));

// check initial tile number to be correct.
expect(await page.locator(dataUiId(IDS.verticalGalleryVideoTile)).count()).toBe(2);
await waitForSelectorCount(page, dataUiId(IDS.verticalGalleryVideoTile), 2);
Copy link
Member

Choose a reason for hiding this comment

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

So do we no longer need to expect things?

Copy link
Member Author

Choose a reason for hiding this comment

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

in this case nope, it's updated to instead wait for the correct count and fails if the condition isn't met. Change here allows two things:

  • the count is now waited for (so can be in subsequent render passes)
  • the action will now screenshot on a failure

Copy link
Member

Choose a reason for hiding this comment

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

So previous one will be waiting for dataUiId(IDS.verticalGalleryVideoTile), if that is showing up, it will start counting the number

But the current behavior would be wait until it is 2 count, and failed it that is not (and take screenshot I guess?)

Copy link
Member

Choose a reason for hiding this comment

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

I am good with this one, this might miss some "delay render"(like first second it renders one element, but later render 2 elements which meet the condition) issues, but also allow use to get more stable UI snapshot

It could have either make our pipeline faster or slower, would like to see the final number when we have this in main

Copy link
Member Author

Choose a reason for hiding this comment

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

I believe the previous one actually did no waiting, it just immediately checked what was rendered. We now instead wait for the condition to become true because the resize observer kicks in after mounting so the tiles we show changes across a couple render passes

@@ -45,7 +45,7 @@ afterAll(() => {
console.error = consoleError;
});

describe('storybook snapshot tests', () => {
describe.skip('storybook snapshot tests', () => {
Copy link
Member

Choose a reason for hiding this comment

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

Maybe storybook 7 works?

@github-actions
Copy link
Contributor

@@ -1,8 +1,19 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import * as northStar from '@fluentui/react-northstar';
import {
Copy link
Member

Choose a reason for hiding this comment

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

So this is just what we are wrapping up? if someone were to add to this list would anything else need to be done or would it just auto pull it at build time?

};

/** @private */
const AnnouncerContext = React.createContext<AnnouncerContextType>({
Copy link
Member

Choose a reason for hiding this comment

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

Just thinking about your LIME investigation (still sad no margaritas) is there any concern about more contexts? even though this is more a N* thing?

Copy link
Member Author

Choose a reason for hiding this comment

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

I will leave this to a later discussion. This doesn't add a new provider, just moves it from an external package into our codebase

@@ -123,7 +123,7 @@ export const MessageStatusIndicator = (props: MessageStatusIndicatorProps): JSX.
calloutProps={{ ...calloutProps }}
styles={hostStyles}
>
{strings.sendingAriaLabel && <LiveMessage message={strings.sendingAriaLabel} aria-live="polite" />}
{strings.sendingAriaLabel && <LiveMessage message={strings.sendingAriaLabel} ariaLive="polite" />}
Copy link
Member

Choose a reason for hiding this comment

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

Small thing but did we do any announcer testing here? we have had bugs around this component in the past not announcing states

Copy link
Member Author

Choose a reason for hiding this comment

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

Just the testing done here: #3005. Confirmed the DOM shows the same behavior as before

@@ -10,7 +10,8 @@
"@internal/calling-stateful-client": ["calling-stateful-client/src"],
"@internal/chat-stateful-client": ["chat-stateful-client/src"],
"@internal/react-components": ["react-components/src"],
"@internal/react-composites": ["react-composites/src"]
"@internal/react-composites": ["react-composites/src"],
"@internal/northstar-wrapper": ["northstar-wrapper/src"]
Copy link
Member

Choose a reason for hiding this comment

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

This is for preprocess version, do we preprocess northstar as well?

Copy link
Member Author

Choose a reason for hiding this comment

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

There's no conditional compiles for n* wrapper package, and given we should not be introducing new usage of this library there shouldn't be in future so stable vs beta didn't need supported in this package

Copy link
Member Author

Choose a reason for hiding this comment

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

(so I guess this line isn't needed? I just copy-pasted anywhere @internal packages were referenced)

@@ -0,0 +1,66 @@
// Copyright (c) Microsoft Corporation.
Copy link
Member

Choose a reason for hiding this comment

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

The reason why we have these files is because it's not exportable from northstar, I guess?

Copy link
Member Author

Choose a reason for hiding this comment

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

See here: #3005. The component we used has react 16 as peer dependency but it is a tiny package so we are just taking the code from it directly

act(() => {
root.update(<TestComponent {...updatedArgs} />);
});
rerender(<TestComponent {...updatedArgs} />);
Copy link
Member

Choose a reason for hiding this comment

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

This is the new format from new react test package?

Copy link
Member

Choose a reason for hiding this comment

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

Sry the render one

Copy link
Member

Choose a reason for hiding this comment

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

Ohh, you mentioned react 18 change its way to render components

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah newer syntax with the newer testing library. the render blocks don't need to be in act blocks

@@ -16,4 +16,9 @@ const params = Object.fromEntries(urlSearchParams.entries());
initializeFileTypeIcons();
initializeIconsForUITests();

ReactDOM.render(params.fakeChatAdapterArgs ? <FakeAdapterApp /> : <LiveTestApp />, document.getElementById('root'));
const domNode = document.getElementById('root');
Copy link
Member

Choose a reason for hiding this comment

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

Yay, with this code piece, I guess we are good to use newest CRA to create projects!

Copy link
Member Author

Choose a reason for hiding this comment

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

We are!

@@ -98,7 +98,7 @@ export class MockCallAdapter implements CallAdapter {
throw Error('createStreamView not implemented');
}
disposeStreamView(): Promise<void> {
throw Error('disposeStreamView not implemented');
return Promise.resolve();
Copy link
Member

Choose a reason for hiding this comment

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

why do we need an implementation here now? is there one needed for createView as well?

Copy link
Member Author

Choose a reason for hiding this comment

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

One of the tests called it as the tile logic now completes its unmount before the test finishes

Copy link
Member

Choose a reason for hiding this comment

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

ahhh okay that makes sense

@@ -12,23 +12,67 @@ import { ChatAdapter, ChatComposite } from '../../../src';
* The added chat composites are hidden, but tests can interact with them programmatically.
*/
export const HiddenChatComposites = (props: { adapters: ChatAdapter[] }): JSX.Element => {
const [hiddenCompositesProps, setHiddenCompositesProps] = useState<HiddenChatCompositesProps[]>([]);
Copy link
Member

Choose a reason for hiding this comment

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

maybe dumb question but what is the reason for the hidden composites again? just to send messages in the tests? (wont block this PR on this but would love to know why we have these)

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah just to send messages and read receipts. They don't really have to be hidden tbh, and I wonder if we could replace them with just adapter uses and fire off read events and messages and such through the adapter interface

Copy link
Member

Choose a reason for hiding this comment

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

yeah could be a interesting refactoring of the tests. I don't think its anything worth blocking this over though since are already using this.

@@ -87,13 +87,13 @@ test.describe('Height gallery resizing tests', async () => {
await waitForSelector(page, dataUiId(IDS.horizontalGalleryVideoTile));

// check initial tile number to be correct.
expect(await page.locator(dataUiId(IDS.horizontalGalleryVideoTile)).count()).toBe(2);
await waitForSelectorCount(page, dataUiId(IDS.horizontalGalleryVideoTile), 2);
Copy link
Member

Choose a reason for hiding this comment

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

love this refactoring

Copy link
Member

Choose a reason for hiding this comment

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

Did we always have this CSS when the box has focus? I thought the underline just turned blue

Copy link
Member Author

Choose a reason for hiding this comment

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

I believe you already asked this one 😉 #3045 (comment)

Copy link
Member

Choose a reason for hiding this comment

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

I did and totally missed it! that makes sense to me. I am also just remembering the CSS as it turns out!

// Wait for indicator to show up
await waitForAndHideTypingIndicator(page, APP_UNDER_TEST_ROOT_SELECTOR);
// Stop typing and send a message
await stopTypingAndSendMessageFromHiddenChatComposite(page, chatRemoteParticipant);
await typeAndSendMessageFromHiddenChatComposite(page, chatRemoteParticipant, 'I agree!');
Copy link
Member

Choose a reason for hiding this comment

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

Looks like we are typing 'I agree' for twice and I guess this is changing the test behaivor?

Copy link
Member Author

Choose a reason for hiding this comment

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

The logic for how the hidden composite is hidden has changed. We now no longer render it entirely whereas before we just marked visibility as hidden. This is because react is much better now and hooks like triggering read receipts get triggered when the composite is hidden now. Because we unmount anything typed and not sent it lost, so I've updated the functions to by type* and typeAndSend*

Copy link
Member

Choose a reason for hiding this comment

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

Could be a work item not to use hidden composite but adapter/clients

return;
// wait for messages to have loaded
await waitForSelector(page, dataUiId('chat-composite-message'));
// sleep for 100ms to give time for the messagethread hook to send the read receipt
Copy link
Member

Choose a reason for hiding this comment

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

Maybe we need a hidden element in html to notify that "I have successfully sent the read receipt at what time point"

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah :/ Would be nice to use the adapter and not composites for these actually and use adapter interface to send the read receipt

Copy link
Member

Choose a reason for hiding this comment

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

Noticed there is a focus change here, is it by designed?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep see here: #3045 (comment)

@@ -9,6 +9,7 @@
"@internal/acs-ui-common": ["../../../packages/acs-ui-common/src"],
"@internal/calling-stateful-client": ["../../../packages/calling-stateful-client/src"],
"@internal/chat-stateful-client": ["../../../packages/chat-stateful-client/src"],
"@internal/northstar-wrapper": ["../../../packages/northstar-wrapper/src"],
Copy link
Member

Choose a reason for hiding this comment

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

Maybe dumb question but do we want to be creating this linking for the samples? I thought we avoided the internal imports?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good question! We avoid imports in the code to make sure we only use publicly available exports so that when we migrate the code to the samples nothing breaks. But internally it needs to reference the packlets for quicker building (doesn't have to first build the downstream packlets) and for hot reloading

@github-actions
Copy link
Contributor

@JamesBurnside JamesBurnside merged commit b618b2a into main May 24, 2023
30 checks passed
@JamesBurnside JamesBurnside deleted the feature/react-18-short-term-support branch May 24, 2023 23:51
JamesBurnside added a commit that referenced this pull request May 25, 2023
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.

None yet

4 participants