├── 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 | --------------------------------------------------------------------------------