Skip to content

Commit 48b8ab7

Browse files
Resolve merge conflicts in dynamic-remotes-runtime-environment-variables
2 parents 990380f + dfe19e3 commit 48b8ab7

File tree

18 files changed

+68
-65
lines changed

18 files changed

+68
-65
lines changed

advanced-api/automatic-vendor-sharing/app1/webpack.prod.config.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
const HtmlWebpackPlugin = require('html-webpack-plugin');
22
const { ModuleFederationPlugin, AutomaticVendorFederation } = require('@module-federation/enhanced');
3-
const path = require('path');
43

54
// Production configuration for optimized builds
65
const deps = require('./package.json').dependencies;

advanced-api/automatic-vendor-sharing/app2/webpack.prod.config.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
const HtmlWebpackPlugin = require('html-webpack-plugin');
22
const { ModuleFederationPlugin, AutomaticVendorFederation } = require('@module-federation/enhanced');
3-
const path = require('path');
43

54
// Production configuration for optimized builds
65
const deps = require('./package.json').dependencies;

advanced-api/automatic-vendor-sharing/e2e/checkAutomaticVendorApps.spec.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,7 @@ async function clickElementWithText(page: Page, selector: string, text: string)
1515
await page.click(`${selector}:has-text("${text}")`);
1616
}
1717

18-
async function checkElementBackgroundColor(page: Page, selector: string, expectedColor: string) {
19-
const element = page.locator(selector);
20-
await element.waitFor({ state: 'visible' });
21-
const backgroundColor = await element.evaluate((el) => {
22-
return window.getComputedStyle(el).backgroundColor;
23-
});
24-
expect(backgroundColor).toBe(expectedColor);
25-
}
18+
2619

2720
const appsData = [
2821
{
@@ -42,7 +35,7 @@ const appsData = [
4235
test.describe('Automatic Vendor Sharing E2E Tests', () => {
4336

4437
appsData.forEach((appData) => {
45-
const { host, appNameText, headerText, buttonColor } = appData;
38+
const { host, appNameText, headerText } = appData;
4639

4740
test.describe(`Check ${appNameText}`, () => {
4841
test(`should display ${appNameText} header and subheader correctly`, async ({ page }) => {

advanced-api/dynamic-remotes-runtime-environment-variables/e2e/checkDynamicRemotesRuntimesApps.spec.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ async function openLocalhost(page: Page, port: number) {
1919
// Wait for the page to load but don't wait for networkidle since env loading might be polling
2020
await page.waitForLoadState('load');
2121

22-
// Wait for React to render - either the loading screen or the main content
23-
await page.waitForSelector('body > div', { timeout: 10000 });
22+
// Wait for the root element to be attached. It may not be visible immediately
23+
// (for example, the remote app shows an empty #root while it loads env config),
24+
// so we only wait for the element to exist in the DOM.
25+
await page.waitForSelector('#root', { state: 'attached', timeout: 10000 });
2426

2527
// Log any errors found
2628
if (pageErrors.length > 0) {

advanced-api/dynamic-remotes-runtime-environment-variables/host/src/components/App.js

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,23 @@
1-
import React, { createContext, useCallback, useMemo } from 'react';
1+
import React, { createContext, useMemo } from 'react';
22
import Main from './Main';
33
import useFetchJson from '../hooks/useFetchJson';
44

55
export const EnvContext = createContext();
66

77
const App = () => {
8-
const validateData = useCallback((data) => data && typeof data === 'object', []);
9-
10-
const fallbackData = useMemo(() => ({
11-
API_URL: 'https://fallback.api.com',
12-
REMOTE_URL: 'http://localhost:3001/remoteEntry.js'
8+
// Memoize options to avoid re-triggering fetch on each render in development
9+
const fetchOptions = useMemo(() => ({
10+
maxRetries: 2,
11+
retryDelay: 500,
12+
timeout: 3000,
13+
validateData: (data) => data && typeof data === 'object',
14+
fallbackData: {
15+
API_URL: 'https://fallback.api.com',
16+
REMOTE_URL: 'http://localhost:3001/remoteEntry.js'
17+
}
1318
}), []);
1419

15-
const { data, loading, error, retry } = useFetchJson(
16-
'/env-config.json',
17-
{
18-
maxRetries: 2,
19-
retryDelay: 500,
20-
timeout: 3000,
21-
validateData,
22-
fallbackData
23-
}
24-
);
20+
const { data, loading, error, retry } = useFetchJson('/env-config.json', fetchOptions);
2521

2622
if (loading) {
2723
return (

advanced-api/dynamic-remotes-runtime-environment-variables/host/src/hooks/useFederatedComponent.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { lazy, useEffect, useState, useCallback, useRef } from 'react';
1+
import { lazy, useEffect, useState, useCallback, useRef } from 'react';
22
import { registerRemotes, loadRemote } from '@module-federation/runtime';
33

44
// Enhanced loading function with retry logic

advanced-api/dynamic-remotes-runtime-environment-variables/host/src/hooks/useFetchJson.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -136,20 +136,19 @@ const useFetchJson = (path, options = {}) => {
136136
}, [fetchData]);
137137

138138
useEffect(() => {
139+
// Component may mount twice in React 18 strict mode. Ensure the ref is
140+
// reset so subsequent fetches can update state correctly.
141+
isMountedRef.current = true;
139142
fetchData();
140-
}, [fetchData]);
141143

142-
// Cleanup on unmount
143-
useEffect(() => {
144-
isMountedRef.current = true;
145144
return () => {
146145
isMountedRef.current = false;
147146
fetchStartedRef.current = false; // Reset fetch flag on unmount
148147
if (abortControllerRef.current) {
149148
abortControllerRef.current.abort();
150149
}
151150
};
152-
}, [path]);
151+
}, [fetchData]);
153152

154153
return {
155154
data,

advanced-api/dynamic-remotes-runtime-environment-variables/remote/src/components/WidgetWrapper.js

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
1-
import React, { createContext } from 'react';
1+
import React, { createContext, useMemo } from 'react';
22
import Widget from './Widget';
33
import useFetchJson from '../hooks/useFetchJson';
44

55
export const EnvContext = createContext();
66

77
// Wraps the Widget component with the EnvContext
88
const WidgetWrapper = () => {
9+
// Memoize fetch options to prevent repeated fetching in React strict mode
10+
const fetchOptions = useMemo(() => ({
11+
maxRetries: 3,
12+
retryDelay: 1000,
13+
timeout: 5000,
14+
validateData: (data) => data && typeof data === 'object',
15+
fallbackData: {
16+
API_URL: 'https://remote.fallback.api.com'
17+
}
18+
}), []);
19+
920
const { data, loading, error, retry } = useFetchJson(
1021
`${__webpack_public_path__}env-config.json`,
11-
{
12-
maxRetries: 3,
13-
retryDelay: 1000,
14-
timeout: 5000,
15-
validateData: (data) => data && typeof data === 'object',
16-
fallbackData: {
17-
API_URL: 'https://remote.fallback.api.com'
18-
}
19-
}
22+
fetchOptions
2023
);
2124

2225
if (loading) {

advanced-api/dynamic-remotes-runtime-environment-variables/remote/src/hooks/useFetchJson.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ const useFetchJson = (path, options = {}) => {
5757
const response = await Promise.race([fetchPromise, timeoutPromise]);
5858

5959
if (signal.aborted || !isMountedRef.current) {
60+
setIsLoading(false);
6061
return;
6162
}
6263

@@ -124,18 +125,19 @@ const useFetchJson = (path, options = {}) => {
124125
}, [fetchData]);
125126

126127
useEffect(() => {
128+
// Reset mount flag on each mount. React 18 strict mode mounts components
129+
// twice in development, so without resetting this flag the fetch results
130+
// would be ignored on the second mount.
131+
isMountedRef.current = true;
127132
fetchData();
128-
}, [fetchData]);
129133

130-
// Cleanup on unmount
131-
useEffect(() => {
132134
return () => {
133135
isMountedRef.current = false;
134136
if (abortControllerRef.current) {
135137
abortControllerRef.current.abort();
136138
}
137139
};
138-
}, []);
140+
}, [fetchData]);
139141

140142
return {
141143
data,
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
<html>
22
<body>
33
<div id="root"></div>
4+
<script>
5+
window.app2Url = 'http://localhost:3002';
6+
</script>
47
</body>
58
</html>

0 commit comments

Comments
 (0)