Skip to content

Commit 663b282

Browse files
committed
Improve microfrontend e2e test with real plugin setup with module fed
1 parent 1e1d0fc commit 663b282

File tree

19 files changed

+3570
-331
lines changed

19 files changed

+3570
-331
lines changed

scripts/build/build-test-apps.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ runMain(async () => {
1818
buildApp('test/apps/react-router-v6-app')
1919
buildApp('test/apps/react-heavy-spa')
2020
buildApp('test/apps/react-shopist-like')
21+
buildApp('test/apps/microfrontend')
2122
await buildReactRouterv7App()
2223
await buildExtensions()
2324

test/apps/microfrontend/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
dist
2+
node_modules
3+
.yarn/*

test/apps/microfrontend/app1.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
export function createButton(containerApp: HTMLDivElement, id: string, clickHandler: () => void): HTMLButtonElement {
2+
const button = document.createElement('button')
3+
const appName = containerApp.id
4+
button.id = `${appName}-${id}`
5+
button.textContent = `${appName}-${id}`
6+
button.onclick = clickHandler
7+
containerApp.appendChild(button)
8+
return button
9+
}
10+
11+
export function createAppContainer(id: string, title: string, borderColor: string): HTMLDivElement {
12+
const appContainer = document.createElement('div')
13+
appContainer.id = id
14+
appContainer.style.flex = '1'
15+
appContainer.style.border = `2px solid ${borderColor}`
16+
appContainer.style.padding = '10px'
17+
18+
const appTitle = document.createElement('h2')
19+
appTitle.textContent = title
20+
appContainer.appendChild(appTitle)
21+
22+
return appContainer
23+
}
24+
25+
const containerApp = createAppContainer('app1', 'App 1 (mf-app1-service v1.0.0)', 'blue')
26+
document.body.appendChild(containerApp)
27+
28+
createButton(containerApp, 'fetch-button', () => {
29+
fetch('/ok').then(
30+
() => {
31+
/* empty */
32+
},
33+
() => {
34+
/* empty */
35+
}
36+
)
37+
})
38+
39+
createButton(containerApp, 'xhr-button', () => {
40+
const xhr = new XMLHttpRequest()
41+
xhr.open('GET', '/ok')
42+
xhr.send()
43+
})
44+
45+
createButton(containerApp, 'error-button', () => {
46+
window.DD_RUM.addError(new Error('mf-app1-error'))
47+
})
48+
49+
createButton(containerApp, 'console-error-button', () => {
50+
console.error('mf-app1-console-error')
51+
})
52+
53+
createButton(containerApp, 'runtime-error-button', () => {
54+
throw new Error('mf-app1-runtime-error')
55+
})
56+
57+
createButton(containerApp, 'loaf-button', () => {
58+
const end = performance.now() + 55
59+
while (performance.now() < end) {
60+
// block the handler for ~55ms to trigger a long task
61+
}
62+
})
63+
64+
createButton(containerApp, 'custom-action-button', () => {
65+
window.DD_RUM.addAction('mf-app1-action')
66+
})
67+
68+
createButton(containerApp, 'vital-button', () => {
69+
const ref = window.DD_RUM.startDurationVital('mf-app1-vital')
70+
window.DD_RUM.stopDurationVital(ref)
71+
})
72+
73+
createButton(containerApp, 'view-button', () => {
74+
window.DD_RUM.startView({ name: 'mf-app1-view' })
75+
})

test/apps/microfrontend/app2.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
export function createButton(containerApp: HTMLDivElement, id: string, clickHandler: () => void): HTMLButtonElement {
2+
const button = document.createElement('button')
3+
const appName = containerApp.id
4+
button.id = `${appName}-${id}`
5+
button.textContent = `${appName}-${id}`
6+
button.onclick = () => clickHandler()
7+
containerApp.appendChild(button)
8+
return button
9+
}
10+
11+
export function createAppContainer(id: string, title: string, borderColor: string): HTMLDivElement {
12+
const appContainer = document.createElement('div')
13+
appContainer.id = id
14+
appContainer.style.flex = '1'
15+
appContainer.style.border = `2px solid ${borderColor}`
16+
appContainer.style.padding = '10px'
17+
18+
const appTitle = document.createElement('h2')
19+
appTitle.textContent = title
20+
appContainer.appendChild(appTitle)
21+
22+
return appContainer
23+
}
24+
25+
const containerApp = createAppContainer('app2', 'App 2 (mf-app2-service v0.2.0)', 'green')
26+
document.body.appendChild(containerApp)
27+
28+
createButton(containerApp, 'fetch-button', () => {
29+
fetch('/ok').then(
30+
() => {
31+
/* empty */
32+
},
33+
() => {
34+
/* empty */
35+
}
36+
)
37+
})
38+
39+
createButton(containerApp, 'xhr-button', () => {
40+
const xhr = new XMLHttpRequest()
41+
xhr.open('GET', '/ok')
42+
xhr.send()
43+
})
44+
45+
createButton(containerApp, 'error-button', () => {
46+
window.DD_RUM.addError(new Error('mf-app2-error'))
47+
})
48+
49+
createButton(containerApp, 'console-error-button', () => {
50+
console.error('mf-app2-console-error')
51+
})
52+
53+
createButton(containerApp, 'runtime-error-button', () => {
54+
throw new Error('mf-app2-runtime-error')
55+
})
56+
57+
createButton(containerApp, 'loaf-button', () => {
58+
const end = performance.now() + 55
59+
while (performance.now() < end) {
60+
// block the handler for ~55ms to trigger a long task
61+
}
62+
})
63+
64+
createButton(containerApp, 'custom-action-button', () => {
65+
window.DD_RUM.addAction('mf-app2-action')
66+
})
67+
68+
createButton(containerApp, 'vital-button', () => {
69+
const ref = window.DD_RUM.startDurationVital('mf-app2-vital')
70+
window.DD_RUM.stopDurationVital(ref)
71+
})
72+
73+
createButton(containerApp, 'view-button', () => {
74+
window.DD_RUM.startView({ name: 'mf-app2-view' })
75+
})
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// @ts-ignore The dynamic import keeps shell.ts out of the entry chunk,
2+
void import('./shell')
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "microfrontend-test-app",
3+
"private": true,
4+
"scripts": {
5+
"build": "webpack --config webpack.app1.js && webpack --config webpack.app2.js && webpack --config webpack.shell.js"
6+
},
7+
"devDependencies": {
8+
"@datadog/webpack-plugin": "^3.1.0",
9+
"@module-federation/enhanced": "^2.0.1",
10+
"ts-loader": "9.5.4",
11+
"typescript": "5.9.3",
12+
"webpack": "5.105.2",
13+
"webpack-cli": "^6.0.1"
14+
}
15+
}

test/apps/microfrontend/shell.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
async function initShell() {
2+
// @ts-ignore
3+
await Promise.all([import('app1/app1'), import('app2/app2')])
4+
}
5+
6+
void initShell()

test/apps/microfrontend/tools.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
export function createButton(containerApp: HTMLDivElement, id: string, clickHandler: () => void): HTMLButtonElement {
2+
const button = document.createElement('button')
3+
const appName = containerApp.id
4+
button.id = `${appName}-${id}`
5+
button.textContent = `${appName}-${id}`
6+
button.onclick = clickHandler
7+
containerApp.appendChild(button)
8+
return button
9+
}
10+
11+
export function createAppContainer(id: string, title: string, borderColor: string): HTMLDivElement {
12+
const appContainer = document.createElement('div')
13+
appContainer.id = id
14+
appContainer.style.flex = '1'
15+
appContainer.style.border = `2px solid ${borderColor}`
16+
appContainer.style.padding = '10px'
17+
18+
const appTitle = document.createElement('h2')
19+
appTitle.textContent = title
20+
appContainer.appendChild(appTitle)
21+
22+
return appContainer
23+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES2018",
4+
"module": "esnext",
5+
"lib": ["ES2018", "DOM"],
6+
"moduleResolution": "node",
7+
"esModuleInterop": true,
8+
"skipLibCheck": true
9+
}
10+
}

test/apps/microfrontend/types.d.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// declare module 'app1/app1'
2+
// declare module 'app2/app2'
3+
4+
interface Window {
5+
DD_RUM: {
6+
addError: (error: Error) => void
7+
addAction: (name: string, context?: any) => void
8+
startDurationVital: (name: string) => any
9+
stopDurationVital: (ref: any) => void
10+
startView: (options: { name: string }) => void
11+
}
12+
}

0 commit comments

Comments
 (0)