mfeflow 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +126 -2
- package/assets/features/analytics-gtm/feature.json +117 -0
- package/assets/features/analytics-gtm/files/Analytics.tsx +13 -0
- package/assets/features/analytics-gtm/files/ConsentBanner.tsx +47 -0
- package/assets/features/analytics-gtm/files/consent-banner-test.tsx +36 -0
- package/assets/features/analytics-gtm/files/init.ts +26 -0
- package/assets/features/analytics-gtm/files/remote-analytics-test.ts.eta +18 -0
- package/assets/features/analytics-gtm/files/remote-analytics.ts.eta +13 -0
- package/assets/features/analytics-gtm/files/shell-init-test.ts +42 -0
- package/assets/features/ci-github/feature.json +26 -0
- package/assets/features/ci-github/files/ci.md +41 -0
- package/assets/features/ci-github/files/ci.yml +63 -0
- package/assets/features/env-t3/feature.json +378 -0
- package/assets/features/env-t3/files/check-runtime-config.ts +105 -0
- package/assets/features/env-t3/files/env.arktype.ts +12 -0
- package/assets/features/env-t3/files/env.example +1 -0
- package/assets/features/env-t3/files/env.valibot.ts +12 -0
- package/assets/features/env-t3/files/env.zod.ts +12 -0
- package/assets/features/env-t3/files/runtime.ts.eta +30 -0
- package/assets/features/env-t3/files/schema.arktype.ts +8 -0
- package/assets/features/env-t3/files/schema.valibot.ts +8 -0
- package/assets/features/env-t3/files/schema.zod.ts +8 -0
- package/assets/features/git-hooks/feature.json +42 -0
- package/assets/features/git-hooks/files/commitlint.config.js +1 -0
- package/assets/features/git-hooks/files/lefthook.yml +9 -0
- package/assets/features/lint-oxlint/feature.json +60 -0
- package/assets/features/lint-oxlint/files/oxlintrc.json +5 -0
- package/assets/features/lint-oxlint/files/prettierignore +5 -0
- package/assets/features/lint-oxlint/files/prettierrc.json +5 -0
- package/assets/features/telemetry-otel/feature.json +159 -0
- package/assets/features/telemetry-otel/files/init.ts.eta +53 -0
- package/assets/features/telemetry-otel/files/remote-telemetry-test.ts.eta +13 -0
- package/assets/features/telemetry-otel/files/remote-telemetry.ts.eta +11 -0
- package/assets/features/telemetry-otel/files/shell-init-test.ts.eta +36 -0
- package/assets/features/testing/feature.json +202 -0
- package/assets/features/testing/files/handlers.ts +5 -0
- package/assets/features/testing/files/playwright.config.ts +30 -0
- package/assets/features/testing/files/root-vitest.config.ts +6 -0
- package/assets/features/testing/files/sample-handlers-test.ts +16 -0
- package/assets/features/testing/files/sample-remote-test.tsx +12 -0
- package/assets/features/testing/files/sample-shell-test.tsx +11 -0
- package/assets/features/testing/files/sample-smoke-e2e.ts +53 -0
- package/assets/features/testing/files/server.ts +4 -0
- package/assets/features/testing/files/setup.ts +18 -0
- package/assets/features/testing/files/vitest.config.ts +11 -0
- package/assets/features/tsconfig/feature.json +78 -0
- package/assets/features/tsconfig/files/root.tsconfig.json +4 -0
- package/assets/features/tsconfig/files/tsconfig.json +5 -0
- package/assets/features/url-factory/feature.json +30 -0
- package/assets/features/url-factory/files/endpoints.ts +12 -0
- package/assets/templates/monorepo/feature.json +295 -0
- package/assets/templates/monorepo/files/remote/mfe.json.eta +7 -0
- package/assets/templates/monorepo/files/remote/package.json.eta +6 -0
- package/assets/templates/monorepo/files/remote/rsbuild.config.ts.eta +7 -0
- package/assets/templates/monorepo/files/remote/src/bootstrap.tsx.eta +6 -0
- package/assets/templates/monorepo/files/remote/src/env.d.ts.eta +1 -0
- package/assets/templates/monorepo/files/remote/src/exposed/App.tsx.eta +18 -0
- package/assets/templates/monorepo/files/remote/src/index.ts.eta +2 -0
- package/assets/templates/monorepo/files/root/AGENTS.md.eta +17 -0
- package/assets/templates/monorepo/files/root/README.md.eta +52 -0
- package/assets/templates/monorepo/files/root/gitignore.eta +11 -0
- package/assets/templates/monorepo/files/root/nvmrc.eta +1 -0
- package/assets/templates/monorepo/files/root/package.json.eta +9 -0
- package/assets/templates/monorepo/files/root/pnpm-workspace.yaml.eta +7 -0
- package/assets/templates/monorepo/files/root/turbo.json.eta +16 -0
- package/assets/templates/monorepo/files/shell/mfe.json.eta +7 -0
- package/assets/templates/monorepo/files/shell/package.json.eta +6 -0
- package/assets/templates/monorepo/files/shell/rsbuild.config.ts.eta +74 -0
- package/assets/templates/monorepo/files/shell/src/App.tsx.eta +46 -0
- package/assets/templates/monorepo/files/shell/src/bootstrap.tsx.eta +24 -0
- package/assets/templates/monorepo/files/shell/src/env.d.ts.eta +1 -0
- package/assets/templates/monorepo/files/shell/src/index.ts.eta +4 -0
- package/assets/templates/monorepo/files/shell/src/pages/Home.tsx.eta +12 -0
- package/assets/templates/monorepo/files/shell/src/remotes/route-table.tsx.eta +12 -0
- package/assets/templates/monorepo/glue/registry-entry.json.eta +5 -0
- package/assets/templates/monorepo/glue/route.tsx.eta +5 -0
- package/bin/mfeflow.js +4 -0
- package/dist/args.d.ts +68 -0
- package/dist/assets.d.ts +13 -0
- package/dist/catalog.d.ts +24 -0
- package/dist/checks/compat.d.ts +2 -0
- package/dist/checks/config.d.ts +8 -0
- package/dist/checks/env.d.ts +6 -0
- package/dist/checks/index.d.ts +6 -0
- package/dist/checks/plugins.d.ts +4 -0
- package/dist/checks/singletons.d.ts +9 -0
- package/dist/checks/workspace.d.ts +2 -0
- package/dist/cli.d.ts +11 -0
- package/dist/commands/add.d.ts +84 -0
- package/dist/commands/budget.d.ts +56 -0
- package/dist/commands/dev.d.ts +62 -0
- package/dist/commands/doctor.d.ts +141 -0
- package/dist/commands/env-key.d.ts +4 -0
- package/dist/commands/features.d.ts +53 -0
- package/dist/commands/init.d.ts +102 -0
- package/dist/devregistry.d.ts +19 -0
- package/dist/exit.d.ts +31 -0
- package/dist/findings.d.ts +35 -0
- package/dist/glue.d.ts +41 -0
- package/dist/help.d.ts +12 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +4154 -0
- package/dist/inspect.d.ts +57 -0
- package/dist/io.d.ts +10 -0
- package/dist/local.d.ts +28 -0
- package/dist/options.d.ts +7 -0
- package/dist/output.d.ts +157 -0
- package/dist/pipeline.d.ts +7 -0
- package/dist/preset.d.ts +19 -0
- package/dist/proc.d.ts +79 -0
- package/dist/prompter.d.ts +28 -0
- package/dist/report.d.ts +26 -0
- package/dist/runtime.d.ts +17 -0
- package/dist/singletons.d.ts +11 -0
- package/dist/sizes.d.ts +17 -0
- package/dist/system.d.ts +20 -0
- package/dist/version.d.ts +8 -0
- package/dist/write.d.ts +26 -0
- package/package.json +66 -3
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { expect, test } from '@playwright/test';
|
|
3
|
+
|
|
4
|
+
// The remotes the dev registry lists; each one's App carries data-testid="<name>".
|
|
5
|
+
const remotes = fs
|
|
6
|
+
.readdirSync('registry/envs/dev')
|
|
7
|
+
.filter((file) => file.endsWith('.json'))
|
|
8
|
+
.map((file) => file.slice(0, -'.json'.length))
|
|
9
|
+
.toSorted();
|
|
10
|
+
|
|
11
|
+
// With env-t3 the shell fetches /config/runtime-config.json at boot and keeps it on globalThis.
|
|
12
|
+
const hasRuntimeConfig = fs.existsSync('scripts/check-runtime-config.ts');
|
|
13
|
+
|
|
14
|
+
test('the shell loads cleanly, with its runtime config', async ({ page }) => {
|
|
15
|
+
const problems: string[] = [];
|
|
16
|
+
page.on('pageerror', (error) => problems.push(`page error: ${error.message}`));
|
|
17
|
+
page.on('console', (message) => {
|
|
18
|
+
if (message.type() === 'error') problems.push(`console error: ${message.text()}`);
|
|
19
|
+
});
|
|
20
|
+
page.on('requestfailed', (request) =>
|
|
21
|
+
problems.push(
|
|
22
|
+
`request failed: ${request.url()} (${request.failure()?.errorText ?? 'unknown'})`,
|
|
23
|
+
),
|
|
24
|
+
);
|
|
25
|
+
page.on('response', (response) => {
|
|
26
|
+
if (response.status() >= 400 && !response.url().endsWith('/favicon.ico')) {
|
|
27
|
+
problems.push(`${String(response.status())} ${response.url()}`);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
await page.goto('/');
|
|
31
|
+
await expect(page.locator('header')).toBeVisible();
|
|
32
|
+
if (hasRuntimeConfig) {
|
|
33
|
+
await expect
|
|
34
|
+
.poll(() =>
|
|
35
|
+
page.evaluate(() => {
|
|
36
|
+
const config: unknown = Reflect.get(globalThis, '__MFE_RUNTIME_CONFIG__');
|
|
37
|
+
return typeof config === 'object' && config !== null && 'environment' in config
|
|
38
|
+
? config.environment
|
|
39
|
+
: undefined;
|
|
40
|
+
}),
|
|
41
|
+
)
|
|
42
|
+
.toBeTruthy();
|
|
43
|
+
}
|
|
44
|
+
await page.waitForLoadState('networkidle');
|
|
45
|
+
expect(problems).toEqual([]);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
for (const name of remotes) {
|
|
49
|
+
test(`the shell renders ${name}`, async ({ page }) => {
|
|
50
|
+
await page.goto('/');
|
|
51
|
+
await expect(page.getByTestId(name)).toBeVisible();
|
|
52
|
+
});
|
|
53
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { cleanup } from '@testing-library/react';
|
|
2
|
+
import { resetPlatform } from '@mfeflow/testing';
|
|
3
|
+
import { afterAll, afterEach, beforeAll } from 'vitest';
|
|
4
|
+
import { server } from '../mocks/server';
|
|
5
|
+
|
|
6
|
+
beforeAll(() => {
|
|
7
|
+
server.listen({ onUnhandledFrame: 'error' });
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
cleanup();
|
|
12
|
+
resetPlatform();
|
|
13
|
+
server.resetHandlers();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterAll(() => {
|
|
17
|
+
server.close();
|
|
18
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
// One copy of React and Testing Library, also when a package like @mfeflow/testing is linked from another folder.
|
|
5
|
+
resolve: { dedupe: ['react', 'react-dom', '@testing-library/react', '@testing-library/dom'] },
|
|
6
|
+
test: {
|
|
7
|
+
environment: 'jsdom',
|
|
8
|
+
include: ['src/**/*.test.{ts,tsx}'],
|
|
9
|
+
setupFiles: ['./src/test/setup.ts'],
|
|
10
|
+
},
|
|
11
|
+
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tsconfig",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Strict TypeScript 7 presets from @mfeflow/tsconfig, and a typecheck script.",
|
|
5
|
+
"requires": ["core"],
|
|
6
|
+
"files": [
|
|
7
|
+
{
|
|
8
|
+
"to": "tsconfig.json",
|
|
9
|
+
"target": "shell",
|
|
10
|
+
"from": "files/tsconfig.json"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"to": "tsconfig.json",
|
|
14
|
+
"target": "remotes",
|
|
15
|
+
"from": "files/tsconfig.json"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"to": "tsconfig.json",
|
|
19
|
+
"target": "root",
|
|
20
|
+
"from": "files/root.tsconfig.json"
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"dependencies": [
|
|
24
|
+
{
|
|
25
|
+
"name": "@mfeflow/tsconfig",
|
|
26
|
+
"range": "latest",
|
|
27
|
+
"target": "shell",
|
|
28
|
+
"dev": true
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"name": "@mfeflow/tsconfig",
|
|
32
|
+
"range": "latest",
|
|
33
|
+
"target": "remotes",
|
|
34
|
+
"dev": true
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"name": "@mfeflow/tsconfig",
|
|
38
|
+
"range": "latest",
|
|
39
|
+
"target": "root",
|
|
40
|
+
"dev": true
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"name": "typescript",
|
|
44
|
+
"range": "7.0.2",
|
|
45
|
+
"target": "root",
|
|
46
|
+
"dev": true
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"name": "typescript",
|
|
50
|
+
"range": "7.0.2",
|
|
51
|
+
"target": "shell",
|
|
52
|
+
"dev": true
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"name": "typescript",
|
|
56
|
+
"range": "7.0.2",
|
|
57
|
+
"target": "remotes",
|
|
58
|
+
"dev": true
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"scripts": [
|
|
62
|
+
{
|
|
63
|
+
"name": "typecheck",
|
|
64
|
+
"command": "turbo run typecheck",
|
|
65
|
+
"target": "root"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"name": "typecheck",
|
|
69
|
+
"command": "tsc --noEmit",
|
|
70
|
+
"target": "shell"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"name": "typecheck",
|
|
74
|
+
"command": "tsc --noEmit",
|
|
75
|
+
"target": "remotes"
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "url-factory",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Typed endpoint definitions and URL building (@mfeflow/url-factory), src/api/endpoints.ts in every app.",
|
|
5
|
+
"requires": ["core"],
|
|
6
|
+
"files": [
|
|
7
|
+
{
|
|
8
|
+
"to": "src/api/endpoints.ts",
|
|
9
|
+
"target": "shell",
|
|
10
|
+
"from": "files/endpoints.ts"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"to": "src/api/endpoints.ts",
|
|
14
|
+
"target": "remotes",
|
|
15
|
+
"from": "files/endpoints.ts"
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"dependencies": [
|
|
19
|
+
{
|
|
20
|
+
"name": "@mfeflow/url-factory",
|
|
21
|
+
"range": "latest",
|
|
22
|
+
"target": "shell"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "@mfeflow/url-factory",
|
|
26
|
+
"range": "latest",
|
|
27
|
+
"target": "remotes"
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createUrlFactory, defineEndpoints } from '@mfeflow/url-factory';
|
|
2
|
+
|
|
3
|
+
export const endpoints = defineEndpoints({
|
|
4
|
+
health: { service: 'api', path: '/health' },
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
const services: Record<string, string> = { api: '/api' };
|
|
8
|
+
|
|
9
|
+
export const apiUrl = createUrlFactory(endpoints, (service) => {
|
|
10
|
+
const base = services[service];
|
|
11
|
+
return base === undefined ? undefined : new URL(base, location.origin).toString();
|
|
12
|
+
});
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "The shell, the remotes, the registry and the workspace around them.",
|
|
5
|
+
"files": [
|
|
6
|
+
{
|
|
7
|
+
"to": "package.json",
|
|
8
|
+
"target": "root",
|
|
9
|
+
"from": "files/root/package.json.eta",
|
|
10
|
+
"template": true
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"to": "pnpm-workspace.yaml",
|
|
14
|
+
"target": "root",
|
|
15
|
+
"from": "files/root/pnpm-workspace.yaml.eta",
|
|
16
|
+
"template": true
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"to": "turbo.json",
|
|
20
|
+
"target": "root",
|
|
21
|
+
"from": "files/root/turbo.json.eta",
|
|
22
|
+
"template": true
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"to": ".gitignore",
|
|
26
|
+
"target": "root",
|
|
27
|
+
"from": "files/root/gitignore.eta",
|
|
28
|
+
"template": true
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"to": ".nvmrc",
|
|
32
|
+
"target": "root",
|
|
33
|
+
"from": "files/root/nvmrc.eta",
|
|
34
|
+
"template": true
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"to": "README.md",
|
|
38
|
+
"target": "root",
|
|
39
|
+
"from": "files/root/README.md.eta",
|
|
40
|
+
"template": true
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"to": "AGENTS.md",
|
|
44
|
+
"target": "root",
|
|
45
|
+
"from": "files/root/AGENTS.md.eta",
|
|
46
|
+
"template": true
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"to": "registry/envs/dev/.gitkeep",
|
|
50
|
+
"target": "root",
|
|
51
|
+
"content": ""
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"to": "registry/envs/staging/.gitkeep",
|
|
55
|
+
"target": "root",
|
|
56
|
+
"content": ""
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"to": "registry/envs/prod/.gitkeep",
|
|
60
|
+
"target": "root",
|
|
61
|
+
"content": ""
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"to": "package.json",
|
|
65
|
+
"target": "shell",
|
|
66
|
+
"from": "files/shell/package.json.eta",
|
|
67
|
+
"template": true
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"to": "mfe.json",
|
|
71
|
+
"target": "shell",
|
|
72
|
+
"from": "files/shell/mfe.json.eta",
|
|
73
|
+
"template": true
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"to": "rsbuild.config.ts",
|
|
77
|
+
"target": "shell",
|
|
78
|
+
"from": "files/shell/rsbuild.config.ts.eta",
|
|
79
|
+
"template": true
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"to": "src/env.d.ts",
|
|
83
|
+
"target": "shell",
|
|
84
|
+
"from": "files/shell/src/env.d.ts.eta",
|
|
85
|
+
"template": true
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"to": "src/index.ts",
|
|
89
|
+
"target": "shell",
|
|
90
|
+
"from": "files/shell/src/index.ts.eta",
|
|
91
|
+
"template": true
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"to": "src/bootstrap.tsx",
|
|
95
|
+
"target": "shell",
|
|
96
|
+
"from": "files/shell/src/bootstrap.tsx.eta",
|
|
97
|
+
"template": true
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"to": "src/App.tsx",
|
|
101
|
+
"target": "shell",
|
|
102
|
+
"from": "files/shell/src/App.tsx.eta",
|
|
103
|
+
"template": true
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"to": "src/remotes/route-table.tsx",
|
|
107
|
+
"target": "shell",
|
|
108
|
+
"from": "files/shell/src/remotes/route-table.tsx.eta",
|
|
109
|
+
"template": true
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"to": "package.json",
|
|
113
|
+
"target": "remotes",
|
|
114
|
+
"from": "files/remote/package.json.eta",
|
|
115
|
+
"template": true
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"to": "mfe.json",
|
|
119
|
+
"target": "remotes",
|
|
120
|
+
"from": "files/remote/mfe.json.eta",
|
|
121
|
+
"template": true
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"to": "rsbuild.config.ts",
|
|
125
|
+
"target": "remotes",
|
|
126
|
+
"from": "files/remote/rsbuild.config.ts.eta",
|
|
127
|
+
"template": true
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"to": "src/env.d.ts",
|
|
131
|
+
"target": "remotes",
|
|
132
|
+
"from": "files/remote/src/env.d.ts.eta",
|
|
133
|
+
"template": true
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"to": "src/index.ts",
|
|
137
|
+
"target": "remotes",
|
|
138
|
+
"from": "files/remote/src/index.ts.eta",
|
|
139
|
+
"template": true
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"to": "src/bootstrap.tsx",
|
|
143
|
+
"target": "remotes",
|
|
144
|
+
"from": "files/remote/src/bootstrap.tsx.eta",
|
|
145
|
+
"template": true
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"to": "src/exposed/App.tsx",
|
|
149
|
+
"target": "remotes",
|
|
150
|
+
"from": "files/remote/src/exposed/App.tsx.eta",
|
|
151
|
+
"template": true
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"to": "src/pages/Home.tsx",
|
|
155
|
+
"target": "shell",
|
|
156
|
+
"from": "files/shell/src/pages/Home.tsx.eta",
|
|
157
|
+
"template": true
|
|
158
|
+
}
|
|
159
|
+
],
|
|
160
|
+
"dependencies": [
|
|
161
|
+
{
|
|
162
|
+
"name": "turbo",
|
|
163
|
+
"range": "2.11.10",
|
|
164
|
+
"target": "root",
|
|
165
|
+
"dev": true
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"name": "@mfeflow/runtime",
|
|
169
|
+
"range": "latest",
|
|
170
|
+
"target": "shell"
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"name": "@module-federation/enhanced",
|
|
174
|
+
"range": "2.9.2",
|
|
175
|
+
"target": "shell"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"name": "react",
|
|
179
|
+
"range": "19.3.1",
|
|
180
|
+
"target": "shell"
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"name": "react-dom",
|
|
184
|
+
"range": "19.3.1",
|
|
185
|
+
"target": "shell"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"name": "@mfeflow/rsbuild",
|
|
189
|
+
"range": "latest",
|
|
190
|
+
"target": "shell",
|
|
191
|
+
"dev": true
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"name": "@rsbuild/core",
|
|
195
|
+
"range": "2.3.0",
|
|
196
|
+
"target": "shell",
|
|
197
|
+
"dev": true
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
"name": "@types/node",
|
|
201
|
+
"range": "26.6.6",
|
|
202
|
+
"target": "shell",
|
|
203
|
+
"dev": true
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"name": "@types/react",
|
|
207
|
+
"range": "19.3.0",
|
|
208
|
+
"target": "shell",
|
|
209
|
+
"dev": true
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"name": "@types/react-dom",
|
|
213
|
+
"range": "19.3.0",
|
|
214
|
+
"target": "shell",
|
|
215
|
+
"dev": true
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
"name": "@module-federation/enhanced",
|
|
219
|
+
"range": "2.9.2",
|
|
220
|
+
"target": "remotes"
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"name": "react",
|
|
224
|
+
"range": "19.3.1",
|
|
225
|
+
"target": "remotes"
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
"name": "react-dom",
|
|
229
|
+
"range": "19.3.1",
|
|
230
|
+
"target": "remotes"
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
"name": "@mfeflow/rsbuild",
|
|
234
|
+
"range": "latest",
|
|
235
|
+
"target": "remotes",
|
|
236
|
+
"dev": true
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
"name": "@rsbuild/core",
|
|
240
|
+
"range": "2.3.0",
|
|
241
|
+
"target": "remotes",
|
|
242
|
+
"dev": true
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
"name": "@types/node",
|
|
246
|
+
"range": "26.6.6",
|
|
247
|
+
"target": "remotes",
|
|
248
|
+
"dev": true
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
"name": "@types/react",
|
|
252
|
+
"range": "19.3.0",
|
|
253
|
+
"target": "remotes",
|
|
254
|
+
"dev": true
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
"name": "@types/react-dom",
|
|
258
|
+
"range": "19.3.0",
|
|
259
|
+
"target": "remotes",
|
|
260
|
+
"dev": true
|
|
261
|
+
}
|
|
262
|
+
],
|
|
263
|
+
"scripts": [
|
|
264
|
+
{
|
|
265
|
+
"name": "dev",
|
|
266
|
+
"command": "turbo run dev",
|
|
267
|
+
"target": "root"
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
"name": "build",
|
|
271
|
+
"command": "turbo run build",
|
|
272
|
+
"target": "root"
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
"name": "dev",
|
|
276
|
+
"command": "rsbuild dev",
|
|
277
|
+
"target": "shell"
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
"name": "build",
|
|
281
|
+
"command": "rsbuild build",
|
|
282
|
+
"target": "shell"
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
"name": "dev",
|
|
286
|
+
"command": "rsbuild dev",
|
|
287
|
+
"target": "remotes"
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
"name": "build",
|
|
291
|
+
"command": "rsbuild build",
|
|
292
|
+
"target": "remotes"
|
|
293
|
+
}
|
|
294
|
+
]
|
|
295
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="@rsbuild/core/types" />
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
|
|
3
|
+
export default function App() {
|
|
4
|
+
const [clicks, setClicks] = useState(0);
|
|
5
|
+
return (
|
|
6
|
+
<section data-testid="<%= it.app.name %>">
|
|
7
|
+
<h2><%= it.app.name %></h2>
|
|
8
|
+
<button
|
|
9
|
+
type="button"
|
|
10
|
+
onClick={() => {
|
|
11
|
+
setClicks(clicks + 1);
|
|
12
|
+
}}
|
|
13
|
+
>
|
|
14
|
+
Clicked {clicks} times
|
|
15
|
+
</button>
|
|
16
|
+
</section>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Guidance for coding agents working in this repo.
|
|
4
|
+
|
|
5
|
+
- Package manager: pnpm (via corepack). Never npm or yarn. Versions live in the `catalog` of
|
|
6
|
+
`pnpm-workspace.yaml`; add dependencies there and reference them as `catalog:`.
|
|
7
|
+
- `pnpm dev` runs the shell and every remote. `pnpm build` builds all of them. `mfeflow dev` does the same with
|
|
8
|
+
per-app logs and picks up new remotes without a restart.
|
|
9
|
+
- Before finishing: `mfeflow doctor` (and `mfeflow validate`, `mfeflow check-compat`, `mfeflow budget` after a build) must exit 0.
|
|
10
|
+
- TypeScript 7, strict. Relative imports have no file extension (`./plan`, not `./plan.js`).
|
|
11
|
+
- Each remote is deployed on its own. A remote must not import from another remote or from
|
|
12
|
+
the shell; talk through the registry, events or URLs.
|
|
13
|
+
- A remote's public surface is `src/exposed/`. Everything else is private to it.
|
|
14
|
+
- Add apps and features with the `mfeflow` CLI (`mfeflow add remote <name>`, `mfeflow features`).
|
|
15
|
+
`mfeflow.json` is the CLI's record of the project; do not edit the file hashes by hand.
|
|
16
|
+
- Shared singletons (react, react-dom, `@mfeflow/runtime`) are provided by the shell. Do not
|
|
17
|
+
bundle your own copy.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# <%= it.scope.slice(1) %>-platform
|
|
2
|
+
|
|
3
|
+
A React micro-frontend platform made with [mfeflow](https://github.com/mfeflow/mfeflow):
|
|
4
|
+
one shell and independently deployable remotes, loaded at runtime through Module Federation.
|
|
5
|
+
|
|
6
|
+
```
|
|
7
|
+
apps/shell the host: routes, layout, registry loading
|
|
8
|
+
apps/<remote> one micro-frontend each, exposing ./App
|
|
9
|
+
registry/envs which build of each remote every environment serves
|
|
10
|
+
mfeflow.json what the CLI generated; `mfeflow add` reads and updates it
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Run it
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
pnpm install
|
|
17
|
+
pnpm dev
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`pnpm dev` starts the shell on http://localhost:4300 and every remote on its own port
|
|
21
|
+
(see `registry/envs/dev`). The shell reads that dev registry and renders the remotes.
|
|
22
|
+
|
|
23
|
+
`mfeflow dev` does the same with a prefixed, coloured log per app, and it follows the project:
|
|
24
|
+
add a remote with `mfeflow add remote checkout` and it starts, and the shell lists it, without a restart.
|
|
25
|
+
Use a remote you already run elsewhere with `mfeflow dev --remote checkout=http://localhost:3001`,
|
|
26
|
+
or run a few apps with `--only shell,catalog`. Ctrl+C stops everything.
|
|
27
|
+
|
|
28
|
+
## Change it
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
mfeflow add remote checkout # a new remote, its registry files and its shell route
|
|
32
|
+
mfeflow add <feature> # see `mfeflow features`
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Check it
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
mfeflow doctor # singletons, compatibility, config, drift; --fix repairs the safe ones
|
|
39
|
+
mfeflow validate # mfeflow.json, every mfe.json and every registry entry
|
|
40
|
+
mfeflow check-compat # each remote's shared ranges against its shell
|
|
41
|
+
mfeflow budget # after `pnpm build`: first-load JS per shell and remote
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
All of them take `--json` and exit non-zero on errors, so they can run in CI. `mfeflow budget` checks each remote's entry
|
|
45
|
+
against the 10 KB a remote may add; set `budget.baselineKb` in `mfeflow.json` (your pages built as one app) to check
|
|
46
|
+
the shell against baseline + 32 KB too.
|
|
47
|
+
|
|
48
|
+
## Before you deploy
|
|
49
|
+
|
|
50
|
+
`registry/envs/staging` and `registry/envs/prod` point at `example.com`. Replace the hosts
|
|
51
|
+
with where you serve each remote (the shell expects `/mfe/<name>/` on its own origin).
|
|
52
|
+
The shell loads the registry from `/registry/index.json`, so serve one per environment.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
22
|