├── src
├── widget.js
├── widget.ts
├── root.component.tsx
├── root.component.js
├── root.component.test.tsx
├── declarations.d.ts
├── app2.js
└── app2.tsx
├── .eslintrc
├── .prettierignore
├── .1fe.config.ts
├── tsconfig.json
├── vite.config.ts
├── package.json
└── .gitignore
/src/widget.js:
--------------------------------------------------------------------------------
1 | import Root from './app2';
2 | export default Root;
3 |
--------------------------------------------------------------------------------
/src/widget.ts:
--------------------------------------------------------------------------------
1 | import Root from './app2';
2 |
3 | export default Root;
4 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "ts-react-important-stuff",
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | .gitignore
2 | .prettierignore
3 | yarn.lock
4 | yarn-error.log
5 | package-lock.json
6 | dist
7 | coverage
8 | pnpm-lock.yaml
--------------------------------------------------------------------------------
/src/root.component.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | export default function Root() {
3 | return (
4 | My amazing component from app2 is mounted! Hello world
5 | );
6 | }
7 |
--------------------------------------------------------------------------------
/src/root.component.js:
--------------------------------------------------------------------------------
1 | import { jsx as _jsx } from "react/jsx-runtime";
2 | export default function Root() {
3 | return (_jsx("section", { children: "My amazing component from app2 is mounted! Hello world" }));
4 | }
5 |
--------------------------------------------------------------------------------
/.1fe.config.ts:
--------------------------------------------------------------------------------
1 | import { OneFeConfiguration } from '@devhub/cli';
2 | import { getBaseConfig } from '@repo/widget-base-config'; // this is the redistributed package for the organization
3 |
4 | const confiugration: OneFeConfiguration = {
5 | baseConfig: getBaseConfig,
6 | };
7 |
8 | export default confiugration;
9 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "ts-config-single-spa",
3 | "compilerOptions": {
4 | "jsx": "react-jsx",
5 | "declarationDir": "dist",
6 | "skipLibCheck": true,
7 | "target": "esnext",
8 | "emitDeclarationOnly": false
9 | },
10 | "include": ["src/**/*"],
11 | "exclude": ["src/**/*.test.*"]
12 | }
13 |
--------------------------------------------------------------------------------
/src/root.component.test.tsx:
--------------------------------------------------------------------------------
1 | import { render } from "@testing-library/react";
2 | import Root from "./root.component";
3 |
4 | describe("Root component", () => {
5 | it("should be in the document", () => {
6 | const { getByText } = render();
7 | expect(getByText(/Testapp is mounted!/i)).toBeInTheDocument();
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "vite";
2 | import react from "@vitejs/plugin-react";
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | base: "/",
8 | build: {
9 | rollupOptions: {
10 | external: ["react", "lodash"],
11 | input: "src/app2.tsx",
12 | preserveEntrySignatures: "strict",
13 | output: {
14 | format: "systemjs",
15 | entryFileNames: `assets/[name].js`,
16 | chunkFileNames: `assets/[name].js`,
17 | assetFileNames: `assets/[name].[ext]`,
18 | globals: {
19 | lodash: "_",
20 | react: "react"
21 | },
22 | },
23 | },
24 | },
25 | });
26 |
--------------------------------------------------------------------------------
/src/declarations.d.ts:
--------------------------------------------------------------------------------
1 | declare module "*.html" {
2 | const rawHtmlFile: string;
3 | export = rawHtmlFile;
4 | }
5 |
6 | declare module "*.bmp" {
7 | const src: string;
8 | export default src;
9 | }
10 |
11 | declare module "*.gif" {
12 | const src: string;
13 | export default src;
14 | }
15 |
16 | declare module "*.jpg" {
17 | const src: string;
18 | export default src;
19 | }
20 |
21 | declare module "*.jpeg" {
22 | const src: string;
23 | export default src;
24 | }
25 |
26 | declare module "*.png" {
27 | const src: string;
28 | export default src;
29 | }
30 |
31 | declare module "*.webp" {
32 | const src: string;
33 | export default src;
34 | }
35 |
36 | declare module "*.svg" {
37 | const src: string;
38 | export default src;
39 | }
40 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app2",
3 | "type": "module",
4 | "scripts": {
5 | "dev": "vite preview --port 8002",
6 | "build": "1fe-cli --trace --environment integration build",
7 | "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
8 | "format": "prettier --write .",
9 | "check-format": "prettier --check ."
10 | },
11 | "devDependencies": {
12 | "@repo/widget-base-config": "0.0.1",
13 | "@vitejs/plugin-react": "^4.3.4",
14 | "cross-env": "^7.0.3",
15 | "eslint": "9.23.0",
16 | "eslint-config-prettier": "^10.1.1",
17 | "eslint-config-ts-react-important-stuff": "^3.0.0",
18 | "eslint-plugin-prettier": "^5.2.4",
19 | "identity-obj-proxy": "^3.0.0",
20 | "prettier": "^3.5.3",
21 | "pretty-quick": "^3.1.1",
22 | "ts-config-single-spa": "^3.0.0",
23 | "typescript": "5.8.2",
24 | "vite-plugin-single-spa": "^1.0.0"
25 | },
26 | "dependencies": {
27 | "@types/systemjs": "^6.15.1",
28 | "antd": "^5.22.4",
29 | "react": "^18.3.1",
30 | "react-dom": "^18.3.1",
31 | "single-spa": "^5.9.3",
32 | "single-spa-react": "^6.0.2",
33 | "vite": "^6.2.3"
34 | },
35 | "types": "dist/app2.d.ts"
36 | }
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # generateds files
30 | reports
31 |
32 | # node-waf configuration
33 | .lock-wscript
34 |
35 | # Compiled binary addons (https://nodejs.org/api/addons.html)
36 | build/Release
37 |
38 | # Dependency directories
39 | node_modules/
40 | jspm_packages/
41 |
42 | # TypeScript v1 declaration files
43 | typings/
44 |
45 | # Optional npm cache directory
46 | .npm
47 |
48 | # Optional eslint cache
49 | .eslintcache
50 |
51 | # Optional REPL history
52 | .node_repl_history
53 |
54 | # Output of 'npm pack'
55 | *.tgz
56 |
57 | # Yarn Integrity file
58 | .yarn-integrity
59 |
60 | # dotenv environment variables file
61 | .env
62 |
63 | # next.js build output
64 | .next
65 | dist
66 |
67 | # Editor directories and files
68 | .idea
69 | .vscode
70 | *.suo
71 | *.ntvs*
72 | *.njsproj
73 | *.sln
74 | *.sw?
75 | .DS_Store
76 |
--------------------------------------------------------------------------------
/src/app2.js:
--------------------------------------------------------------------------------
1 | import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2 | import { useState, useCallback, useEffect } from 'react';
3 | import { Button } from 'antd';
4 | export default function Root(props) {
5 | useEffect(() => {
6 | props.platform.utils.appLoadTime.end();
7 | }, []);
8 | const [eventBusResult, setEventBusResult] = useState('unchanged');
9 | const [unsubscribeFn, setUnsubscribeFn] = useState(() => () => { });
10 | const listener = useCallback((event) => {
11 | setEventBusResult(JSON.stringify(event));
12 | }, [setEventBusResult]);
13 | return (_jsxs(_Fragment, { children: [_jsx("p", { children: "My component from app2 is mounted!" }), _jsx(Button, { "data-qa": "eventBus.subscribe.btn", onClick: () => {
14 | // @ts-ignore
15 | const unsubFn = props.platform.utils.eventBus.subscribe({
16 | eventName: 'event1',
17 | listener,
18 | });
19 | setEventBusResult('subscribed');
20 | setUnsubscribeFn(() => unsubFn);
21 | }, children: "utils.eventBus.subscribe" }), _jsx(Button, { "data-qa": "eventBus.unsubscribe.btn", onClick: () => {
22 | setEventBusResult('unsubscribed');
23 | unsubscribeFn();
24 | }, children: "utils.eventBus.unsubscribe" }), _jsx("div", { "data-qa": "eventBus.result.container", children: eventBusResult })] }));
25 | }
26 |
--------------------------------------------------------------------------------
/src/app2.tsx:
--------------------------------------------------------------------------------
1 | import { useState, useCallback, useEffect } from 'react';
2 | import { Button } from 'antd';
3 |
4 | type WidgetEvents = {
5 | event1: { param1: string };
6 | };
7 |
8 | export default function Root(props) {
9 | useEffect(() => {
10 | props.platform.utils.appLoadTime.end();
11 | }, []);
12 |
13 | const [eventBusResult, setEventBusResult] = useState('unchanged');
14 | const [unsubscribeFn, setUnsubscribeFn] = useState(() => () => {});
15 |
16 | const listener = useCallback(
17 | (event: any) => {
18 | setEventBusResult(JSON.stringify(event));
19 | },
20 | [setEventBusResult],
21 | );
22 |
23 | return (
24 | <>
25 |
My component from app2 is mounted!
26 |
43 |
52 | {eventBusResult}
53 | >
54 | );
55 | }
56 |
--------------------------------------------------------------------------------