Skip to content

Commit e35d121

Browse files
committed
Improve microfrontend e2e test with real plugin setup with module fed
1 parent 2d90881 commit e35d121

File tree

21 files changed

+3481
-329
lines changed

21 files changed

+3481
-329
lines changed

LICENSE-3rdparty.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ prod,react-dom,MIT,Copyright (c) Facebook, Inc. and its affiliates.
1313
dev,typedoc,Apache-2.0,TypeStrong
1414
dev,@eslint/js,MIT,Copyright OpenJS Foundation and other contributors, <www.openjsf.org>
1515
dev,@jsdevtools/coverage-istanbul-loader,MIT,Copyright (c) 2015 James Messinger
16+
dev,@module-federation/enhanced,MIT, Copyright (c) 2020 ScriptedAlchemy LLC (Zack Jackson) Zhou Shaw (zhouxiao)
1617
dev,@playwright/test,Apache-2.0,Copyright Microsoft Corporation
1718
dev,@swc/core,Apache-2.0,Copyright (c) SWC Contributors
1819
dev,@types/chrome,MIT,Copyright Microsoft Corporation

eslint.config.mjs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export default tseslint.config(
2727
'test/**/dist',
2828
'test/apps/react-heavy-spa',
2929
'test/apps/react-shopist-like',
30+
'test/apps/microfrontend',
3031
'sandbox',
3132
'coverage',
3233
'rum-events-format',
@@ -469,6 +470,15 @@ export default tseslint.config(
469470
},
470471
},
471472

473+
{
474+
files: ['test/apps/microfrontend/**/*.ts'],
475+
rules: {
476+
// Module Federation remote entries (app1/app1, app2/app2) are resolved at runtime
477+
// and have no static filesystem representation.
478+
'import/no-unresolved': ['error', { ignore: ['^app1/', '^app2/'] }],
479+
},
480+
},
481+
472482
{
473483
files: ['packages/core/src/tools/**/*.ts'],
474484
ignores: [SPEC_FILES],

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: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { createApp } from './common'
2+
3+
createApp('app1', 'App 1 (mfe-app1-service v1.0.0)', 'blue')

test/apps/microfrontend/app2.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { createApp } from './common'
2+
3+
createApp('app2', 'App 2 (mfe-app2-service v0.2.0)', 'green')
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')

test/apps/microfrontend/common.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
function createContainer(id: string, title: string, borderColor: string) {
2+
const container = document.createElement('div')
3+
container.id = id
4+
container.style.flex = '1'
5+
container.style.border = `2px solid ${borderColor}`
6+
container.style.padding = '10px'
7+
8+
const appTitle = document.createElement('h2')
9+
appTitle.textContent = title
10+
container.appendChild(appTitle)
11+
document.body.appendChild(container)
12+
return container
13+
}
14+
15+
function createButton(container: HTMLElement, eventType: string, clickHandler: () => void) {
16+
const button = document.createElement('button')
17+
button.id = `${container.id}-${eventType}`
18+
button.textContent = `${container.id}-${eventType}`
19+
button.onclick = clickHandler
20+
container.appendChild(button)
21+
}
22+
23+
export function createApp(id: string, title: string, borderColor: string) {
24+
const container = createContainer(id, title, borderColor)
25+
26+
createButton(container, 'fetch', () => {
27+
void fetch('/ok')
28+
})
29+
30+
createButton(container, 'xhr', () => {
31+
const xhr = new XMLHttpRequest()
32+
xhr.open('GET', '/ok')
33+
xhr.send()
34+
})
35+
36+
createButton(container, 'error', () => {
37+
window.DD_RUM.addError(new Error(`${id}-error`))
38+
})
39+
40+
createButton(container, 'console-error', () => {
41+
console.error(`${id}-console-error`)
42+
})
43+
44+
createButton(container, 'runtime-error', () => {
45+
throw new Error(`${id}-runtime-error`)
46+
})
47+
48+
createButton(container, 'loaf', () => {
49+
const end = performance.now() + 55
50+
while (performance.now() < end) {
51+
// block the handler for ~55ms to trigger a long task
52+
}
53+
})
54+
55+
createButton(container, 'custom-action', () => {
56+
window.DD_RUM.addAction(`${id}-action`)
57+
})
58+
59+
createButton(container, 'vital', () => {
60+
const ref = window.DD_RUM.startDurationVital(`${id}-vital`)
61+
window.DD_RUM.stopDurationVital(ref)
62+
})
63+
64+
createButton(container, 'view', () => {
65+
window.DD_RUM.startView({ name: `${id}-view` })
66+
})
67+
}
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 Module Federation remote entries
3+
await Promise.all([import('app1/app1'), import('app2/app2')])
4+
}
5+
6+
void initShell()

0 commit comments

Comments
 (0)