├── .editorconfig ├── .eslintrc.json ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .vscode ├── extensions.json └── settings.json ├── LICENSE ├── README.md ├── angular.json ├── apps ├── .gitkeep ├── react-mfe-e2e │ ├── .eslintrc.json │ ├── cypress.json │ ├── project.json │ ├── src │ │ ├── fixtures │ │ │ └── example.json │ │ ├── integration │ │ │ └── app.spec.ts │ │ └── support │ │ │ ├── app.po.ts │ │ │ ├── commands.ts │ │ │ └── index.ts │ └── tsconfig.json ├── react-mfe │ ├── .babelrc │ ├── .browserslistrc │ ├── .eslintrc.json │ ├── jest.config.ts │ ├── project.json │ ├── src │ │ ├── app │ │ │ ├── app.module.scss │ │ │ ├── app.spec.tsx │ │ │ ├── app.tsx │ │ │ └── nx-welcome.tsx │ │ ├── assets │ │ │ ├── .gitkeep │ │ │ └── icons │ │ │ │ └── react-icon.svg │ │ ├── custom-router.tsx │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main.tsx │ │ ├── polyfills.ts │ │ └── styles.scss │ ├── tsconfig.app.json │ ├── tsconfig.json │ └── tsconfig.spec.json ├── shell-e2e │ ├── .eslintrc.json │ ├── cypress.json │ ├── project.json │ ├── src │ │ ├── fixtures │ │ │ └── example.json │ │ ├── integration │ │ │ └── app.spec.ts │ │ └── support │ │ │ ├── app.po.ts │ │ │ ├── commands.ts │ │ │ └── index.ts │ └── tsconfig.json └── shell │ ├── .browserslistrc │ ├── .eslintrc.json │ ├── jest.config.js │ ├── project.json │ ├── src │ ├── assets │ │ ├── .gitkeep │ │ └── icons │ │ │ ├── icon-72x72.png │ │ │ ├── twitter-logo.png │ │ │ └── twitter.jpg │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── first-app │ │ ├── app-routing.module.ts │ │ ├── app.component.html │ │ ├── app.component.scss │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── home │ │ │ ├── home.component.html │ │ │ ├── home.component.scss │ │ │ ├── home.component.spec.ts │ │ │ └── home.component.ts │ │ └── use-case │ │ │ ├── use-case.component.html │ │ │ ├── use-case.component.scss │ │ │ ├── use-case.component.spec.ts │ │ │ └── use-case.component.ts │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── second-app │ │ ├── app-routing.module.ts │ │ ├── app.component.html │ │ ├── app.component.scss │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── home │ │ │ ├── home.component.html │ │ │ ├── home.component.scss │ │ │ ├── home.component.spec.ts │ │ │ └── home.component.ts │ │ └── use-case │ │ │ ├── use-case.component.html │ │ │ ├── use-case.component.scss │ │ │ ├── use-case.component.spec.ts │ │ │ └── use-case.component.ts │ ├── styles.scss │ └── test-setup.ts │ ├── tsconfig.app.json │ ├── tsconfig.editor.json │ ├── tsconfig.json │ └── tsconfig.spec.json ├── babel.config.json ├── decorate-angular-cli.js ├── jest.config.js ├── jest.preset.js ├── libs ├── .gitkeep └── microapp │ ├── .browserslistrc │ ├── .eslintrc.json │ ├── jest.config.js │ ├── ng-package.json │ ├── package.json │ ├── project.json │ ├── src │ ├── index.ts │ ├── lib │ │ ├── headless │ │ │ └── index.ts │ │ ├── loader │ │ │ └── index.ts │ │ ├── messaging │ │ │ ├── event-messaging.ts │ │ │ └── index.ts │ │ ├── routing │ │ │ ├── angular │ │ │ │ ├── index.ts │ │ │ │ ├── micro-app-location-strategy.ts │ │ │ │ ├── micro-app-name.token.ts │ │ │ │ ├── micro-app-routing-state.ts │ │ │ │ ├── micro-app-routing.module.ts │ │ │ │ └── micro-app-url-handling-strategy.ts │ │ │ ├── index.ts │ │ │ └── javascript.ts │ │ └── state │ │ │ └── index.ts │ └── test-setup.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ ├── tsconfig.lib.prod.json │ └── tsconfig.spec.json ├── nx.json ├── package-lock.json ├── package.json ├── tools ├── generators │ └── .gitkeep └── tsconfig.tools.json └── tsconfig.base.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "ignorePatterns": ["**/*"], 4 | "plugins": ["@nrwl/nx"], 5 | "overrides": [ 6 | { 7 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 8 | "rules": { 9 | "@nrwl/nx/enforce-module-boundaries": [ 10 | "error", 11 | { 12 | "enforceBuildableLibDependency": true, 13 | "allow": [], 14 | "depConstraints": [ 15 | { 16 | "sourceTag": "*", 17 | "onlyDependOnLibsWithTags": ["*"] 18 | } 19 | ] 20 | } 21 | ] 22 | } 23 | }, 24 | { 25 | "files": ["*.ts", "*.tsx"], 26 | "extends": ["plugin:@nrwl/nx/typescript"], 27 | "rules": {} 28 | }, 29 | { 30 | "files": ["*.js", "*.jsx"], 31 | "extends": ["plugin:@nrwl/nx/javascript"], 32 | "rules": {} 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | yarn-error.log 34 | testem.log 35 | /typings 36 | 37 | # System Files 38 | .DS_Store 39 | Thumbs.db 40 | 41 | .angular 42 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Add files here to ignore them from prettier formatting 2 | 3 | /dist 4 | /coverage 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "angular.ng-template", 4 | "nrwl.angular-console", 5 | "esbenp.prettier-vscode", 6 | "firsttris.vscode-jest-runner", 7 | "dbaeumer.vscode-eslint" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.colorCustomizations": { 3 | "activityBar.activeBackground": "#2f7c47", 4 | "activityBar.activeBorder": "#422c74", 5 | "activityBar.background": "#2f7c47", 6 | "activityBar.foreground": "#e7e7e7", 7 | "activityBar.inactiveForeground": "#e7e7e799", 8 | "activityBarBadge.background": "#422c74", 9 | "activityBarBadge.foreground": "#e7e7e7", 10 | "sash.hoverBorder": "#2f7c47", 11 | "statusBar.background": "#215732", 12 | "statusBar.foreground": "#e7e7e7", 13 | "statusBarItem.hoverBackground": "#2f7c47", 14 | "statusBarItem.remoteBackground": "#215732", 15 | "statusBarItem.remoteForeground": "#e7e7e7", 16 | "titleBar.activeBackground": "#215732", 17 | "titleBar.activeForeground": "#e7e7e7", 18 | "titleBar.inactiveBackground": "#21573299", 19 | "titleBar.inactiveForeground": "#e7e7e799", 20 | "commandCenter.border": "#e7e7e799" 21 | }, 22 | "peacock.color": "#215732" 23 | } 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2021-2022 intauria GmbH 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # @angular-architects/microapp 2 | 3 | This library support Micro App frontend development. 4 | 5 | - [@angular-architects/microapp](#angular-architectsmicroapp) 6 | - [Supported features](#supported-features) 7 | - [Roadmap](#roadmap) 8 | - [Setup](#setup) 9 | - [Install `node_module`](#install-node_module) 10 | - [Shell](#shell) 11 | - [Micro App](#micro-app) 12 | - [Routing](#routing) 13 | - [Deeplinking from Shell to Micro App](#deeplinking-from-shell-to-micro-app) 14 | - [Experimental string-based Deeplinking from Shell to Micro App](#experimental-string-based-deeplinking-from-shell-to-micro-app) 15 | 16 | ## Supported features 17 | 18 | - Multi Router support in the same window object 19 | - Support for Angular 13+ 20 | - Messaging API based on CustomEvents 21 | - influenced by RxJS and NgRx Action Creators 22 | - Deep Linking across different Micro Apps 23 | 24 | ## Roadmap 25 | 26 | - Named router outlets w/i an Angular app 27 | - Support for different versions and environment configs 28 | - Headless shell infrastructure 29 | - Cross tech support 30 | - React, Vue, AngularJS 31 | - Distributed State Management 32 | 33 | ## Setup 34 | 35 | ### Install `node_module` 36 | 37 | ``` 38 | npm install @angular-architects/microapp 39 | ``` 40 | 41 | ### Shell 42 | ```typescript 43 | @NgModule({ 44 | declarations: [AppComponent], 45 | imports: [ 46 | BrowserModule, 47 | MicroAppRoutingModule.forShell({ name: 'shell' }), 48 | AppRoutingModule 49 | ], 50 | bootstrap: [AppComponent], 51 | }) 52 | export class AppModule {} 53 | ``` 54 | 55 | ### Micro App 56 | ```typescript 57 | @NgModule({ 58 | declarations: [AppComponent], 59 | imports: [ 60 | BrowserModule, 61 | MicroAppRoutingModule.forMicroApp({ name: 'microapp' }), 62 | AppRoutingModule 63 | ], 64 | bootstrap: [AppComponent], 65 | }) 66 | export class AppModule {} 67 | ``` 68 | 69 | ### Routing 70 | 71 | Use normal Angular `route` definitions and the `routerLink` Directive. 72 | 73 | #### Deeplinking from Shell to Micro App 74 | ```html 75 | Deeplink from Shell to Micro App -> mypath 76 | ``` 77 | 78 | #### Experimental string-based Deeplinking from Shell to Micro App 79 | ```html 80 | Deeplink string from Shell to Micro App -> mypath 81 | ``` 82 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "projects": { 4 | "microapp": "libs/microapp", 5 | "react-mfe": "apps/react-mfe", 6 | "react-mfe-e2e": "apps/react-mfe-e2e", 7 | "shell": "apps/shell", 8 | "shell-e2e": "apps/shell-e2e" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intauria/microapp/78d2edb5a39dbef96345d232c16a1ef0a3e1e9fd/apps/.gitkeep -------------------------------------------------------------------------------- /apps/react-mfe-e2e/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:cypress/recommended", "../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /apps/react-mfe-e2e/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileServerFolder": ".", 3 | "fixturesFolder": "./src/fixtures", 4 | "integrationFolder": "./src/integration", 5 | "modifyObstructiveCode": false, 6 | "supportFile": "./src/support/index.ts", 7 | "pluginsFile": false, 8 | "video": true, 9 | "videosFolder": "../../dist/cypress/apps/react-mfe-e2e/videos", 10 | "screenshotsFolder": "../../dist/cypress/apps/react-mfe-e2e/screenshots", 11 | "chromeWebSecurity": false 12 | } 13 | -------------------------------------------------------------------------------- /apps/react-mfe-e2e/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": "apps/react-mfe-e2e", 3 | "sourceRoot": "apps/react-mfe-e2e/src", 4 | "projectType": "application", 5 | "targets": { 6 | "e2e": { 7 | "executor": "@nrwl/cypress:cypress", 8 | "options": { 9 | "cypressConfig": "apps/react-mfe-e2e/cypress.json", 10 | "devServerTarget": "react-mfe:serve:development" 11 | }, 12 | "configurations": { 13 | "production": { 14 | "devServerTarget": "react-mfe:serve:production" 15 | } 16 | } 17 | }, 18 | "lint": { 19 | "executor": "@nrwl/linter:eslint", 20 | "outputs": ["{options.outputFile}"], 21 | "options": { 22 | "lintFilePatterns": ["apps/react-mfe-e2e/**/*.{js,ts}"] 23 | } 24 | } 25 | }, 26 | "tags": [], 27 | "implicitDependencies": ["react-mfe"] 28 | } 29 | -------------------------------------------------------------------------------- /apps/react-mfe-e2e/src/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io" 4 | } 5 | -------------------------------------------------------------------------------- /apps/react-mfe-e2e/src/integration/app.spec.ts: -------------------------------------------------------------------------------- 1 | import { getGreeting } from '../support/app.po'; 2 | 3 | describe('react-mfe', () => { 4 | beforeEach(() => cy.visit('/')); 5 | 6 | it('should display welcome message', () => { 7 | // Custom command example, see `../support/commands.ts` file 8 | cy.login('my-email@something.com', 'myPassword'); 9 | 10 | // Function helper example, see `../support/app.po.ts` file 11 | getGreeting().contains('Welcome react-mfe'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /apps/react-mfe-e2e/src/support/app.po.ts: -------------------------------------------------------------------------------- 1 | export const getGreeting = () => cy.get('h1'); 2 | -------------------------------------------------------------------------------- /apps/react-mfe-e2e/src/support/commands.ts: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | 11 | // eslint-disable-next-line @typescript-eslint/no-namespace 12 | declare namespace Cypress { 13 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 14 | interface Chainable { 15 | login(email: string, password: string): void; 16 | } 17 | } 18 | // 19 | // -- This is a parent command -- 20 | Cypress.Commands.add('login', (email, password) => { 21 | console.log('Custom command example: Login', email, password); 22 | }); 23 | // 24 | // -- This is a child command -- 25 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 26 | // 27 | // 28 | // -- This is a dual command -- 29 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 30 | // 31 | // 32 | // -- This will overwrite an existing command -- 33 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 34 | -------------------------------------------------------------------------------- /apps/react-mfe-e2e/src/support/index.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands'; 18 | -------------------------------------------------------------------------------- /apps/react-mfe-e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "sourceMap": false, 5 | "outDir": "../../dist/out-tsc", 6 | "allowJs": true, 7 | "types": ["cypress", "node"] 8 | }, 9 | "include": ["src/**/*.ts", "src/**/*.js"] 10 | } 11 | -------------------------------------------------------------------------------- /apps/react-mfe/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@nrwl/react/babel", 5 | { 6 | "runtime": "automatic" 7 | } 8 | ] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /apps/react-mfe/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by: 2 | # 1. autoprefixer to adjust CSS to support the below specified browsers 3 | # 2. babel preset-env to adjust included polyfills 4 | # 5 | # For additional information regarding the format and rule options, please see: 6 | # https://github.com/browserslist/browserslist#queries 7 | # 8 | # If you need to support different browsers in production, you may tweak the list below. 9 | 10 | last 1 Chrome version 11 | last 1 Firefox version 12 | last 2 Edge major versions 13 | last 2 Safari major version 14 | last 2 iOS major versions 15 | Firefox ESR 16 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /apps/react-mfe/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /apps/react-mfe/jest.config.ts: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | displayName: 'react-mfe', 3 | preset: '../../jest.preset.js', 4 | transform: { 5 | '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest', 6 | '^.+\\.[tj]sx?$': 'babel-jest', 7 | }, 8 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 9 | coverageDirectory: '../../coverage/apps/react-mfe', 10 | }; 11 | -------------------------------------------------------------------------------- /apps/react-mfe/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": "apps/react-mfe", 3 | "sourceRoot": "apps/react-mfe/src", 4 | "projectType": "application", 5 | "targets": { 6 | "build": { 7 | "executor": "@nrwl/web:webpack", 8 | "outputs": ["{options.outputPath}"], 9 | "defaultConfiguration": "production", 10 | "options": { 11 | "compiler": "babel", 12 | "outputPath": "dist/apps/react-mfe", 13 | "index": "apps/react-mfe/src/index.html", 14 | "baseHref": "/", 15 | "main": "apps/react-mfe/src/main.tsx", 16 | "polyfills": "apps/react-mfe/src/polyfills.ts", 17 | "tsConfig": "apps/react-mfe/tsconfig.app.json", 18 | "assets": [ 19 | "apps/react-mfe/src/favicon.ico", 20 | "apps/react-mfe/src/assets" 21 | ], 22 | "styles": ["apps/react-mfe/src/styles.scss"], 23 | "scripts": [], 24 | "webpackConfig": "@nrwl/react/plugins/webpack" 25 | }, 26 | "configurations": { 27 | "development": { 28 | "extractLicenses": false, 29 | "optimization": false, 30 | "sourceMap": true, 31 | "vendorChunk": true 32 | }, 33 | "production": { 34 | "fileReplacements": [ 35 | { 36 | "replace": "apps/react-mfe/src/environments/environment.ts", 37 | "with": "apps/react-mfe/src/environments/environment.prod.ts" 38 | } 39 | ], 40 | "optimization": true, 41 | "outputHashing": "all", 42 | "sourceMap": false, 43 | "namedChunks": false, 44 | "extractLicenses": true, 45 | "vendorChunk": false 46 | } 47 | } 48 | }, 49 | "serve": { 50 | "executor": "@nrwl/web:dev-server", 51 | "defaultConfiguration": "development", 52 | "options": { 53 | "buildTarget": "react-mfe:build", 54 | "hmr": true, 55 | "port": 4000 56 | }, 57 | "configurations": { 58 | "development": { 59 | "buildTarget": "react-mfe:build:development" 60 | }, 61 | "production": { 62 | "buildTarget": "react-mfe:build:production", 63 | "hmr": false 64 | } 65 | } 66 | }, 67 | "lint": { 68 | "executor": "@nrwl/linter:eslint", 69 | "outputs": ["{options.outputFile}"], 70 | "options": { 71 | "lintFilePatterns": ["apps/react-mfe/**/*.{ts,tsx,js,jsx}"] 72 | } 73 | }, 74 | "test": { 75 | "executor": "@nrwl/jest:jest", 76 | "outputs": ["coverage/apps/react-mfe"], 77 | "options": { 78 | "jestConfig": "apps/react-mfe/jest.config.ts", 79 | "passWithNoTests": true 80 | } 81 | } 82 | }, 83 | "tags": [] 84 | } 85 | -------------------------------------------------------------------------------- /apps/react-mfe/src/app/app.module.scss: -------------------------------------------------------------------------------- 1 | /* Your styles goes here. */ 2 | -------------------------------------------------------------------------------- /apps/react-mfe/src/app/app.spec.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react'; 2 | 3 | import { BrowserRouter } from 'react-router-dom'; 4 | 5 | import App from './app'; 6 | 7 | describe('App', () => { 8 | it('should render successfully', () => { 9 | const { baseElement } = render( 10 | 11 | 12 | 13 | ); 14 | 15 | expect(baseElement).toBeTruthy(); 16 | }); 17 | 18 | it('should have a greeting as the title', () => { 19 | const { getByText } = render( 20 | 21 | 22 | 23 | ); 24 | 25 | expect(getByText(/Welcome react-mfe/gi)).toBeTruthy(); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /apps/react-mfe/src/app/app.tsx: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 2 | import { Link, Route, Routes } from 'react-router-dom'; 3 | 4 | 5 | export function App() { 6 | /* const navigate = useNavigate(); 7 | const location = useLocation(); 8 | 9 | //useEffect(() => { 10 | function nav(data: any, unused: string, url?: string | URL | null | undefined) { 11 | console.log(url, location); 12 | if (url !== location.pathname) { 13 | originalPushStateFn(data, unused, url); 14 | } 15 | } 16 | patchPushState(nav as any, { overwrite: true }); 17 | patchReplaceState(replaceEventReplaceStateFn, { overwrite: true }); 18 | //}); */ 19 | 20 | return ( 21 | <> 22 | React Logo 23 |

React App (Micro App)

24 | 25 | {/* START: routes */} 26 | {/* These routes and navigation have been generated for you */} 27 | {/* Feel free to move and update them to fit your needs */} 28 | {/*
29 |
30 |
*/} 31 |
32 | 43 |
44 | 45 | home 3 works! 49 | } 50 | /> 51 | use-case 3 works! 55 | } 56 | /> 57 | 58 | {/* END: routes */} 59 | 60 | ); 61 | } 62 | 63 | export default App; 64 | -------------------------------------------------------------------------------- /apps/react-mfe/src/app/nx-welcome.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * 3 | This is a starter component and can be deleted. 4 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * 5 | Delete this file and get started with your project! 6 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * 7 | */ 8 | export function NxWelcome({ title }: { title: string }) { 9 | return ( 10 | <> 11 |