├── .editorconfig ├── .eslintrc.json ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .vscode └── extensions.json ├── apps ├── .gitkeep ├── remote1-e2e │ ├── .eslintrc.json │ ├── cypress.config.ts │ ├── project.json │ ├── src │ │ ├── e2e │ │ │ └── app.cy.ts │ │ ├── fixtures │ │ │ └── example.json │ │ └── support │ │ │ ├── app.po.ts │ │ │ ├── commands.ts │ │ │ └── e2e.ts │ └── tsconfig.json ├── remote1 │ ├── .browserslistrc │ ├── .eslintrc.json │ ├── jest.config.ts │ ├── project.json │ ├── src │ │ ├── app │ │ │ ├── app.component.html │ │ │ ├── app.component.scss │ │ │ ├── app.component.ts │ │ │ └── app.routes.ts │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── bootstrap.ts │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main.ts │ │ ├── polyfills.ts │ │ ├── styles.scss │ │ └── test-setup.ts │ ├── tsconfig.app.json │ ├── tsconfig.editor.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ ├── webpack.config.js │ └── webpack.prod.config.js ├── remote2-e2e │ ├── .eslintrc.json │ ├── cypress.config.ts │ ├── project.json │ ├── src │ │ ├── e2e │ │ │ └── app.cy.ts │ │ ├── fixtures │ │ │ └── example.json │ │ └── support │ │ │ ├── app.po.ts │ │ │ ├── commands.ts │ │ │ └── e2e.ts │ └── tsconfig.json ├── remote2 │ ├── .browserslistrc │ ├── .eslintrc.json │ ├── jest.config.ts │ ├── project.json │ ├── src │ │ ├── app │ │ │ ├── app.component.html │ │ │ ├── app.component.scss │ │ │ ├── app.component.ts │ │ │ └── app.routes.ts │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── bootstrap.ts │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main.ts │ │ ├── polyfills.ts │ │ ├── styles.scss │ │ └── test-setup.ts │ ├── tsconfig.app.json │ ├── tsconfig.editor.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ ├── webpack.config.js │ └── webpack.prod.config.js ├── shell-e2e │ ├── .eslintrc.json │ ├── cypress.config.ts │ ├── project.json │ ├── src │ │ ├── e2e │ │ │ └── app.cy.ts │ │ ├── fixtures │ │ │ └── example.json │ │ └── support │ │ │ ├── app.po.ts │ │ │ ├── commands.ts │ │ │ └── e2e.ts │ └── tsconfig.json └── shell │ ├── .browserslistrc │ ├── .eslintrc.json │ ├── jest.config.ts │ ├── project.json │ ├── src │ ├── app │ │ ├── app.component.html │ │ ├── app.component.scss │ │ ├── app.component.ts │ │ ├── components │ │ │ └── navbar │ │ │ │ ├── navbar.component.html │ │ │ │ ├── navbar.component.scss │ │ │ │ └── navbar.component.ts │ │ └── utils │ │ │ ├── custom-manifest.ts │ │ │ └── route-factory.ts │ ├── assets │ │ ├── .gitkeep │ │ └── mf.manifest.json │ ├── bootstrap.ts │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.scss │ └── test-setup.ts │ ├── tsconfig.app.json │ ├── tsconfig.editor.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ ├── webpack.config.js │ └── webpack.prod.config.js ├── decorate-angular-cli.js ├── jest.config.ts ├── jest.preset.js ├── libs ├── .gitkeep ├── remote1-lib │ ├── .eslintrc.json │ ├── README.md │ ├── jest.config.ts │ ├── project.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── components │ │ │ │ └── some │ │ │ │ │ ├── some.component.html │ │ │ │ │ ├── some.component.scss │ │ │ │ │ └── some.component.ts │ │ │ └── remote1.routes.ts │ │ └── test-setup.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── remote2-lib │ ├── .eslintrc.json │ ├── README.md │ ├── jest.config.ts │ ├── project.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── components │ │ │ │ ├── four │ │ │ │ │ ├── four.component.html │ │ │ │ │ ├── four.component.scss │ │ │ │ │ └── four.component.ts │ │ │ │ ├── one │ │ │ │ │ ├── one.component.html │ │ │ │ │ ├── one.component.scss │ │ │ │ │ └── one.component.ts │ │ │ │ ├── three │ │ │ │ │ ├── three.component.html │ │ │ │ │ ├── three.component.scss │ │ │ │ │ └── three.component.ts │ │ │ │ ├── two │ │ │ │ │ ├── two.component.html │ │ │ │ │ ├── two.component.scss │ │ │ │ │ └── two.component.ts │ │ │ │ └── wrapper │ │ │ │ │ ├── wrapper.component.html │ │ │ │ │ ├── wrapper.component.scss │ │ │ │ │ └── wrapper.component.ts │ │ │ └── remote2.routes.ts │ │ └── test-setup.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json └── shared │ ├── .eslintrc.json │ ├── README.md │ ├── jest.config.ts │ ├── project.json │ ├── src │ ├── index.ts │ ├── lib │ │ └── services │ │ │ └── echo.service.ts │ └── test-setup.ts │ ├── tsconfig.json │ ├── tsconfig.lib.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 | "files": ["*.spec.ts", "*.spec.tsx", "*.spec.js", "*.spec.jsx"], 36 | "env": { 37 | "jest": true 38 | }, 39 | "rules": {} 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /apps/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaasStefan/dynamic-module-federation/7686b0de54f9bb5f8e8546f48cc121b72422bfc0/apps/.gitkeep -------------------------------------------------------------------------------- /apps/remote1-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/remote1-e2e/cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'cypress'; 2 | import { nxE2EPreset } from '@nrwl/cypress/plugins/cypress-preset'; 3 | 4 | export default defineConfig({ 5 | e2e: nxE2EPreset(__dirname), 6 | }); 7 | -------------------------------------------------------------------------------- /apps/remote1-e2e/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remote1-e2e", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "apps/remote1-e2e/src", 5 | "projectType": "application", 6 | "targets": { 7 | "e2e": { 8 | "executor": "@nrwl/cypress:cypress", 9 | "options": { 10 | "cypressConfig": "apps/remote1-e2e/cypress.config.ts", 11 | "devServerTarget": "remote1:serve:development", 12 | "testingType": "e2e" 13 | }, 14 | "configurations": { 15 | "production": { 16 | "devServerTarget": "remote1:serve:production" 17 | } 18 | } 19 | }, 20 | "lint": { 21 | "executor": "@nrwl/linter:eslint", 22 | "outputs": [ 23 | "{options.outputFile}" 24 | ], 25 | "options": { 26 | "lintFilePatterns": [ 27 | "apps/remote1-e2e/**/*.{js,ts}" 28 | ] 29 | } 30 | } 31 | }, 32 | "tags": [], 33 | "implicitDependencies": [ 34 | "remote1" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /apps/remote1-e2e/src/e2e/app.cy.ts: -------------------------------------------------------------------------------- 1 | import { getGreeting } from '../support/app.po'; 2 | 3 | describe('remote1', () => { 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 remote1'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /apps/remote1-e2e/src/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io" 4 | } 5 | -------------------------------------------------------------------------------- /apps/remote1-e2e/src/support/app.po.ts: -------------------------------------------------------------------------------- 1 | export const getGreeting = () => cy.get('h1'); 2 | -------------------------------------------------------------------------------- /apps/remote1-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/remote1-e2e/src/support/e2e.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/remote1-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 | "forceConsistentCasingInFileNames": true, 9 | "strict": true, 10 | "noImplicitOverride": true, 11 | "noPropertyAccessFromIndexSignature": true, 12 | "noImplicitReturns": true, 13 | "noFallthroughCasesInSwitch": true 14 | }, 15 | "include": ["src/**/*.ts", "src/**/*.js", "cypress.config.ts"], 16 | "angularCompilerOptions": { 17 | "enableI18nLegacyMessageIdFormat": false, 18 | "strictInjectionParameters": true, 19 | "strictInputAccessModifiers": true, 20 | "strictTemplates": true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /apps/remote1/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | -------------------------------------------------------------------------------- /apps/remote1/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "extends": [ 8 | "plugin:@nrwl/nx/angular", 9 | "plugin:@angular-eslint/template/process-inline-templates" 10 | ], 11 | "rules": { 12 | "@angular-eslint/directive-selector": [ 13 | "error", 14 | { 15 | "type": "attribute", 16 | "prefix": "dynamicModuleFederation", 17 | "style": "camelCase" 18 | } 19 | ], 20 | "@angular-eslint/component-selector": [ 21 | "error", 22 | { 23 | "type": "element", 24 | "prefix": "dynamic-module-federation", 25 | "style": "kebab-case" 26 | } 27 | ] 28 | } 29 | }, 30 | { 31 | "files": ["*.html"], 32 | "extends": ["plugin:@nrwl/nx/angular-template"], 33 | "rules": {} 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /apps/remote1/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'remote1', 4 | preset: '../../jest.preset.js', 5 | setupFilesAfterEnv: ['/src/test-setup.ts'], 6 | globals: { 7 | 'ts-jest': { 8 | tsconfig: '/tsconfig.spec.json', 9 | stringifyContentPathRegex: '\\.(html|svg)$', 10 | }, 11 | }, 12 | coverageDirectory: '../../coverage/apps/remote1', 13 | transform: { 14 | '^.+\\.(ts|mjs|js|html)$': 'jest-preset-angular', 15 | }, 16 | transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], 17 | snapshotSerializers: [ 18 | 'jest-preset-angular/build/serializers/no-ng-attributes', 19 | 'jest-preset-angular/build/serializers/ng-snapshot', 20 | 'jest-preset-angular/build/serializers/html-comment', 21 | ], 22 | }; 23 | -------------------------------------------------------------------------------- /apps/remote1/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remote1", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "projectType": "application", 5 | "sourceRoot": "apps/remote1/src", 6 | "prefix": "dynamic-module-federation", 7 | "targets": { 8 | "build": { 9 | "executor": "@nrwl/angular:webpack-browser", 10 | "outputs": [ 11 | "{options.outputPath}" 12 | ], 13 | "options": { 14 | "outputPath": "dist/apps/remote1", 15 | "index": "apps/remote1/src/index.html", 16 | "main": "apps/remote1/src/main.ts", 17 | "polyfills": "apps/remote1/src/polyfills.ts", 18 | "tsConfig": "apps/remote1/tsconfig.app.json", 19 | "inlineStyleLanguage": "scss", 20 | "assets": [ 21 | "apps/remote1/src/favicon.ico", 22 | "apps/remote1/src/assets" 23 | ], 24 | "styles": [ 25 | "apps/remote1/src/styles.scss" 26 | ], 27 | "scripts": [], 28 | "customWebpackConfig": { 29 | "path": "apps/remote1/webpack.config.js" 30 | }, 31 | "commonChunk": false 32 | }, 33 | "configurations": { 34 | "production": { 35 | "budgets": [ 36 | { 37 | "type": "initial", 38 | "maximumWarning": "500kb", 39 | "maximumError": "1mb" 40 | }, 41 | { 42 | "type": "anyComponentStyle", 43 | "maximumWarning": "2kb", 44 | "maximumError": "4kb" 45 | } 46 | ], 47 | "fileReplacements": [ 48 | { 49 | "replace": "apps/remote1/src/environments/environment.ts", 50 | "with": "apps/remote1/src/environments/environment.prod.ts" 51 | } 52 | ], 53 | "outputHashing": "all", 54 | "customWebpackConfig": { 55 | "path": "apps/remote1/webpack.prod.config.js" 56 | } 57 | }, 58 | "development": { 59 | "buildOptimizer": false, 60 | "optimization": false, 61 | "vendorChunk": true, 62 | "extractLicenses": false, 63 | "sourceMap": true, 64 | "namedChunks": true 65 | } 66 | }, 67 | "defaultConfiguration": "production" 68 | }, 69 | "serve": { 70 | "executor": "@nrwl/angular:webpack-dev-server", 71 | "configurations": { 72 | "production": { 73 | "browserTarget": "remote1:build:production" 74 | }, 75 | "development": { 76 | "browserTarget": "remote1:build:development" 77 | } 78 | }, 79 | "defaultConfiguration": "development", 80 | "options": { 81 | "port": 4201, 82 | "publicHost": "http://localhost:4201" 83 | } 84 | }, 85 | "extract-i18n": { 86 | "executor": "ngx-build-plus:extract-i18n", 87 | "options": { 88 | "browserTarget": "remote1:build", 89 | "extraWebpackConfig": "apps/remote1/webpack.config.js" 90 | } 91 | }, 92 | "lint": { 93 | "executor": "@nrwl/linter:eslint", 94 | "options": { 95 | "lintFilePatterns": [ 96 | "apps/remote1/**/*.ts", 97 | "apps/remote1/**/*.html" 98 | ] 99 | } 100 | }, 101 | "test": { 102 | "executor": "@nrwl/jest:jest", 103 | "outputs": [ 104 | "{workspaceRoot}/coverage/{projectRoot}" 105 | ], 106 | "options": { 107 | "jestConfig": "apps/remote1/jest.config.ts", 108 | "passWithNoTests": true 109 | } 110 | } 111 | }, 112 | "tags": [] 113 | } 114 | -------------------------------------------------------------------------------- /apps/remote1/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/remote1/src/app/app.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaasStefan/dynamic-module-federation/7686b0de54f9bb5f8e8546f48cc121b72422bfc0/apps/remote1/src/app/app.component.scss -------------------------------------------------------------------------------- /apps/remote1/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { Component } from '@angular/core'; 3 | import { RouterOutlet } from '@angular/router'; 4 | 5 | @Component({ 6 | standalone: true, 7 | imports: [CommonModule, RouterOutlet], 8 | selector: 'dynamic-module-federation-root', 9 | templateUrl: './app.component.html', 10 | styleUrls: ['./app.component.scss'], 11 | }) 12 | export class AppComponent { 13 | title = 'remote1'; 14 | } 15 | -------------------------------------------------------------------------------- /apps/remote1/src/app/app.routes.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | 3 | export const routes: Routes = [ 4 | { 5 | path: '', 6 | loadChildren: () => 7 | import('@dynamic-module-federation/remote1-lib').then((m) => m.routes), 8 | }, 9 | ]; 10 | -------------------------------------------------------------------------------- /apps/remote1/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaasStefan/dynamic-module-federation/7686b0de54f9bb5f8e8546f48cc121b72422bfc0/apps/remote1/src/assets/.gitkeep -------------------------------------------------------------------------------- /apps/remote1/src/bootstrap.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { bootstrapApplication } from '@angular/platform-browser'; 3 | import { provideRouter } from '@angular/router'; 4 | import { routes } from '@dynamic-module-federation/remote1-lib'; 5 | import { AppComponent } from './app/app.component'; 6 | 7 | import { environment } from './environments/environment'; 8 | 9 | if (environment.production) { 10 | enableProdMode(); 11 | } 12 | 13 | bootstrapApplication(AppComponent, { 14 | providers: [ 15 | provideRouter(routes) 16 | ], 17 | }).catch((err) => console.error(err)); 18 | -------------------------------------------------------------------------------- /apps/remote1/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | }; 4 | -------------------------------------------------------------------------------- /apps/remote1/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false, 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /apps/remote1/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaasStefan/dynamic-module-federation/7686b0de54f9bb5f8e8546f48cc121b72422bfc0/apps/remote1/src/favicon.ico -------------------------------------------------------------------------------- /apps/remote1/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Remote1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/remote1/src/main.ts: -------------------------------------------------------------------------------- 1 | import('./bootstrap') 2 | .catch(err => console.error(err)); 3 | -------------------------------------------------------------------------------- /apps/remote1/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes recent versions of Safari, Chrome (including 12 | * Opera), Edge on the desktop, and iOS and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** 22 | * By default, zone.js will patch all possible macroTask and DomEvents 23 | * user can disable parts of macroTask/DomEvents patch by setting following flags 24 | * because those flags need to be set before `zone.js` being loaded, and webpack 25 | * will put import in the top of bundle, so user need to create a separate file 26 | * in this directory (for example: zone-flags.ts), and put the following flags 27 | * into that file, and then add the following code before importing zone.js. 28 | * import './zone-flags'; 29 | * 30 | * The flags allowed in zone-flags.ts are listed here. 31 | * 32 | * The following flags will work for all browsers. 33 | * 34 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 35 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 36 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 37 | * 38 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 39 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 40 | * 41 | * (window as any).__Zone_enable_cross_context_check = true; 42 | * 43 | */ 44 | 45 | /*************************************************************************************************** 46 | * Zone JS is required by default for Angular itself. 47 | */ 48 | import 'zone.js'; // Included with Angular CLI. 49 | 50 | /*************************************************************************************************** 51 | * APPLICATION IMPORTS 52 | */ 53 | -------------------------------------------------------------------------------- /apps/remote1/src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /apps/remote1/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | -------------------------------------------------------------------------------- /apps/remote1/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": [], 6 | "target": "es2020" 7 | }, 8 | "files": [ 9 | "src/main.ts", 10 | "src/polyfills.ts" 11 | ], 12 | "include": [ 13 | "src/**/*.d.ts" 14 | ], 15 | "exclude": [ 16 | "jest.config.ts", 17 | "**/*.test.ts", 18 | "**/*.spec.ts" 19 | ] 20 | } -------------------------------------------------------------------------------- /apps/remote1/tsconfig.editor.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["**/*.ts"], 4 | "compilerOptions": { 5 | "types": ["jest", "node"] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /apps/remote1/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.app.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | }, 12 | { 13 | "path": "./tsconfig.editor.json" 14 | } 15 | ], 16 | "compilerOptions": { 17 | "target": "es2020", 18 | "forceConsistentCasingInFileNames": true, 19 | "strict": true, 20 | "noImplicitOverride": true, 21 | "noPropertyAccessFromIndexSignature": true, 22 | "noImplicitReturns": true, 23 | "noFallthroughCasesInSwitch": true 24 | }, 25 | "angularCompilerOptions": { 26 | "enableI18nLegacyMessageIdFormat": false, 27 | "strictInjectionParameters": true, 28 | "strictInputAccessModifiers": true, 29 | "strictTemplates": true 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /apps/remote1/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /apps/remote1/webpack.config.js: -------------------------------------------------------------------------------- 1 | const { shareAll, withModuleFederationPlugin } = require('@angular-architects/module-federation/webpack'); 2 | 3 | module.exports = withModuleFederationPlugin({ 4 | 5 | name: 'remote1', 6 | 7 | exposes: { 8 | './Routes': './libs/remote1-lib/src/lib/remote1.routes.ts', 9 | }, 10 | 11 | shared: { 12 | ...shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }), 13 | }, 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /apps/remote1/webpack.prod.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./webpack.config'); 2 | -------------------------------------------------------------------------------- /apps/remote2-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/remote2-e2e/cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'cypress'; 2 | import { nxE2EPreset } from '@nrwl/cypress/plugins/cypress-preset'; 3 | 4 | export default defineConfig({ 5 | e2e: nxE2EPreset(__dirname), 6 | }); 7 | -------------------------------------------------------------------------------- /apps/remote2-e2e/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remote2-e2e", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "apps/remote2-e2e/src", 5 | "projectType": "application", 6 | "targets": { 7 | "e2e": { 8 | "executor": "@nrwl/cypress:cypress", 9 | "options": { 10 | "cypressConfig": "apps/remote2-e2e/cypress.config.ts", 11 | "devServerTarget": "remote2:serve:development", 12 | "testingType": "e2e" 13 | }, 14 | "configurations": { 15 | "production": { 16 | "devServerTarget": "remote2:serve:production" 17 | } 18 | } 19 | }, 20 | "lint": { 21 | "executor": "@nrwl/linter:eslint", 22 | "outputs": [ 23 | "{options.outputFile}" 24 | ], 25 | "options": { 26 | "lintFilePatterns": [ 27 | "apps/remote2-e2e/**/*.{js,ts}" 28 | ] 29 | } 30 | } 31 | }, 32 | "tags": [], 33 | "implicitDependencies": [ 34 | "remote2" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /apps/remote2-e2e/src/e2e/app.cy.ts: -------------------------------------------------------------------------------- 1 | import { getGreeting } from '../support/app.po'; 2 | 3 | describe('remote2', () => { 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 remote2'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /apps/remote2-e2e/src/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io" 4 | } 5 | -------------------------------------------------------------------------------- /apps/remote2-e2e/src/support/app.po.ts: -------------------------------------------------------------------------------- 1 | export const getGreeting = () => cy.get('h1'); 2 | -------------------------------------------------------------------------------- /apps/remote2-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/remote2-e2e/src/support/e2e.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/remote2-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 | "forceConsistentCasingInFileNames": true, 9 | "strict": true, 10 | "noImplicitOverride": true, 11 | "noPropertyAccessFromIndexSignature": true, 12 | "noImplicitReturns": true, 13 | "noFallthroughCasesInSwitch": true 14 | }, 15 | "include": ["src/**/*.ts", "src/**/*.js", "cypress.config.ts"], 16 | "angularCompilerOptions": { 17 | "enableI18nLegacyMessageIdFormat": false, 18 | "strictInjectionParameters": true, 19 | "strictInputAccessModifiers": true, 20 | "strictTemplates": true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /apps/remote2/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | -------------------------------------------------------------------------------- /apps/remote2/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "extends": [ 8 | "plugin:@nrwl/nx/angular", 9 | "plugin:@angular-eslint/template/process-inline-templates" 10 | ], 11 | "rules": { 12 | "@angular-eslint/directive-selector": [ 13 | "error", 14 | { 15 | "type": "attribute", 16 | "prefix": "dynamicModuleFederation", 17 | "style": "camelCase" 18 | } 19 | ], 20 | "@angular-eslint/component-selector": [ 21 | "error", 22 | { 23 | "type": "element", 24 | "prefix": "dynamic-module-federation", 25 | "style": "kebab-case" 26 | } 27 | ] 28 | } 29 | }, 30 | { 31 | "files": ["*.html"], 32 | "extends": ["plugin:@nrwl/nx/angular-template"], 33 | "rules": {} 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /apps/remote2/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'remote2', 4 | preset: '../../jest.preset.js', 5 | setupFilesAfterEnv: ['/src/test-setup.ts'], 6 | globals: { 7 | 'ts-jest': { 8 | tsconfig: '/tsconfig.spec.json', 9 | stringifyContentPathRegex: '\\.(html|svg)$', 10 | }, 11 | }, 12 | coverageDirectory: '../../coverage/apps/remote2', 13 | transform: { 14 | '^.+\\.(ts|mjs|js|html)$': 'jest-preset-angular', 15 | }, 16 | transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], 17 | snapshotSerializers: [ 18 | 'jest-preset-angular/build/serializers/no-ng-attributes', 19 | 'jest-preset-angular/build/serializers/ng-snapshot', 20 | 'jest-preset-angular/build/serializers/html-comment', 21 | ], 22 | }; 23 | -------------------------------------------------------------------------------- /apps/remote2/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remote2", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "projectType": "application", 5 | "sourceRoot": "apps/remote2/src", 6 | "prefix": "dynamic-module-federation", 7 | "targets": { 8 | "build": { 9 | "executor": "@nrwl/angular:webpack-browser", 10 | "outputs": [ 11 | "{options.outputPath}" 12 | ], 13 | "options": { 14 | "outputPath": "dist/apps/remote2", 15 | "index": "apps/remote2/src/index.html", 16 | "main": "apps/remote2/src/main.ts", 17 | "polyfills": "apps/remote2/src/polyfills.ts", 18 | "tsConfig": "apps/remote2/tsconfig.app.json", 19 | "inlineStyleLanguage": "scss", 20 | "assets": [ 21 | "apps/remote2/src/favicon.ico", 22 | "apps/remote2/src/assets" 23 | ], 24 | "styles": [ 25 | "apps/remote2/src/styles.scss" 26 | ], 27 | "scripts": [], 28 | "customWebpackConfig": { 29 | "path": "apps/remote2/webpack.config.js" 30 | }, 31 | "commonChunk": false 32 | }, 33 | "configurations": { 34 | "production": { 35 | "budgets": [ 36 | { 37 | "type": "initial", 38 | "maximumWarning": "500kb", 39 | "maximumError": "1mb" 40 | }, 41 | { 42 | "type": "anyComponentStyle", 43 | "maximumWarning": "2kb", 44 | "maximumError": "4kb" 45 | } 46 | ], 47 | "fileReplacements": [ 48 | { 49 | "replace": "apps/remote2/src/environments/environment.ts", 50 | "with": "apps/remote2/src/environments/environment.prod.ts" 51 | } 52 | ], 53 | "outputHashing": "all", 54 | "customWebpackConfig": { 55 | "path": "apps/remote2/webpack.prod.config.js" 56 | } 57 | }, 58 | "development": { 59 | "buildOptimizer": false, 60 | "optimization": false, 61 | "vendorChunk": true, 62 | "extractLicenses": false, 63 | "sourceMap": true, 64 | "namedChunks": true 65 | } 66 | }, 67 | "defaultConfiguration": "production" 68 | }, 69 | "serve": { 70 | "executor": "@nrwl/angular:webpack-dev-server", 71 | "configurations": { 72 | "production": { 73 | "browserTarget": "remote2:build:production" 74 | }, 75 | "development": { 76 | "browserTarget": "remote2:build:development" 77 | } 78 | }, 79 | "defaultConfiguration": "development", 80 | "options": { 81 | "port": 4202, 82 | "publicHost": "http://localhost:4202" 83 | } 84 | }, 85 | "extract-i18n": { 86 | "executor": "ngx-build-plus:extract-i18n", 87 | "options": { 88 | "browserTarget": "remote2:build", 89 | "extraWebpackConfig": "apps/remote2/webpack.config.js" 90 | } 91 | }, 92 | "lint": { 93 | "executor": "@nrwl/linter:eslint", 94 | "options": { 95 | "lintFilePatterns": [ 96 | "apps/remote2/**/*.ts", 97 | "apps/remote2/**/*.html" 98 | ] 99 | } 100 | }, 101 | "test": { 102 | "executor": "@nrwl/jest:jest", 103 | "outputs": [ 104 | "{workspaceRoot}/coverage/{projectRoot}" 105 | ], 106 | "options": { 107 | "jestConfig": "apps/remote2/jest.config.ts", 108 | "passWithNoTests": true 109 | } 110 | } 111 | }, 112 | "tags": [] 113 | } 114 | -------------------------------------------------------------------------------- /apps/remote2/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/remote2/src/app/app.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaasStefan/dynamic-module-federation/7686b0de54f9bb5f8e8546f48cc121b72422bfc0/apps/remote2/src/app/app.component.scss -------------------------------------------------------------------------------- /apps/remote2/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { Component } from '@angular/core'; 3 | import { RouterOutlet } from '@angular/router'; 4 | 5 | @Component({ 6 | standalone: true, 7 | imports: [ 8 | CommonModule, 9 | RouterOutlet 10 | ], 11 | selector: 'dynamic-module-federation-root', 12 | templateUrl: './app.component.html', 13 | styleUrls: ['./app.component.scss'], 14 | }) 15 | export class AppComponent { 16 | title = 'remote2'; 17 | } 18 | -------------------------------------------------------------------------------- /apps/remote2/src/app/app.routes.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | 3 | export const routes: Routes = [ 4 | { 5 | path: '', 6 | loadChildren: () => 7 | import('@dynamic-module-federation/remote2-lib').then((m) => m.routes), 8 | }, 9 | ]; 10 | -------------------------------------------------------------------------------- /apps/remote2/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaasStefan/dynamic-module-federation/7686b0de54f9bb5f8e8546f48cc121b72422bfc0/apps/remote2/src/assets/.gitkeep -------------------------------------------------------------------------------- /apps/remote2/src/bootstrap.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { bootstrapApplication } from '@angular/platform-browser'; 3 | import { provideRouter } from '@angular/router'; 4 | import { AppComponent } from './app/app.component'; 5 | import { routes } from './app/app.routes'; 6 | 7 | import { environment } from './environments/environment'; 8 | 9 | if (environment.production) { 10 | enableProdMode(); 11 | } 12 | 13 | bootstrapApplication(AppComponent, { 14 | providers: [ 15 | provideRouter(routes) 16 | ], 17 | }).catch((err) => console.error(err)); 18 | -------------------------------------------------------------------------------- /apps/remote2/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | }; 4 | -------------------------------------------------------------------------------- /apps/remote2/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false, 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /apps/remote2/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaasStefan/dynamic-module-federation/7686b0de54f9bb5f8e8546f48cc121b72422bfc0/apps/remote2/src/favicon.ico -------------------------------------------------------------------------------- /apps/remote2/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Remote2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/remote2/src/main.ts: -------------------------------------------------------------------------------- 1 | import('./bootstrap') 2 | .catch(err => console.error(err)); 3 | -------------------------------------------------------------------------------- /apps/remote2/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes recent versions of Safari, Chrome (including 12 | * Opera), Edge on the desktop, and iOS and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** 22 | * By default, zone.js will patch all possible macroTask and DomEvents 23 | * user can disable parts of macroTask/DomEvents patch by setting following flags 24 | * because those flags need to be set before `zone.js` being loaded, and webpack 25 | * will put import in the top of bundle, so user need to create a separate file 26 | * in this directory (for example: zone-flags.ts), and put the following flags 27 | * into that file, and then add the following code before importing zone.js. 28 | * import './zone-flags'; 29 | * 30 | * The flags allowed in zone-flags.ts are listed here. 31 | * 32 | * The following flags will work for all browsers. 33 | * 34 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 35 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 36 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 37 | * 38 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 39 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 40 | * 41 | * (window as any).__Zone_enable_cross_context_check = true; 42 | * 43 | */ 44 | 45 | /*************************************************************************************************** 46 | * Zone JS is required by default for Angular itself. 47 | */ 48 | import 'zone.js'; // Included with Angular CLI. 49 | 50 | /*************************************************************************************************** 51 | * APPLICATION IMPORTS 52 | */ 53 | -------------------------------------------------------------------------------- /apps/remote2/src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /apps/remote2/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | -------------------------------------------------------------------------------- /apps/remote2/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": [], 6 | "target": "es2020" 7 | }, 8 | "files": [ 9 | "src/main.ts", 10 | "src/polyfills.ts" 11 | ], 12 | "include": [ 13 | "src/**/*.d.ts" 14 | ], 15 | "exclude": [ 16 | "jest.config.ts", 17 | "**/*.test.ts", 18 | "**/*.spec.ts" 19 | ] 20 | } -------------------------------------------------------------------------------- /apps/remote2/tsconfig.editor.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["**/*.ts"], 4 | "compilerOptions": { 5 | "types": ["jest", "node"] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /apps/remote2/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.app.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | }, 12 | { 13 | "path": "./tsconfig.editor.json" 14 | } 15 | ], 16 | "compilerOptions": { 17 | "target": "es2020", 18 | "forceConsistentCasingInFileNames": true, 19 | "strict": true, 20 | "noImplicitOverride": true, 21 | "noPropertyAccessFromIndexSignature": true, 22 | "noImplicitReturns": true, 23 | "noFallthroughCasesInSwitch": true 24 | }, 25 | "angularCompilerOptions": { 26 | "enableI18nLegacyMessageIdFormat": false, 27 | "strictInjectionParameters": true, 28 | "strictInputAccessModifiers": true, 29 | "strictTemplates": true 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /apps/remote2/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /apps/remote2/webpack.config.js: -------------------------------------------------------------------------------- 1 | const { shareAll, withModuleFederationPlugin } = require('@angular-architects/module-federation/webpack'); 2 | 3 | module.exports = withModuleFederationPlugin({ 4 | 5 | name: 'remote2', 6 | 7 | exposes: { 8 | './Routes': './libs/remote2-lib/src/lib/remote2.routes.ts', 9 | }, 10 | 11 | shared: { 12 | ...shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }), 13 | }, 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /apps/remote2/webpack.prod.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./webpack.config'); 2 | -------------------------------------------------------------------------------- /apps/shell-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 | "files": ["src/plugins/index.js"], 11 | "rules": { 12 | "@typescript-eslint/no-var-requires": "off", 13 | "no-undef": "off" 14 | } 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /apps/shell-e2e/cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'cypress'; 2 | import { nxE2EPreset } from '@nrwl/cypress/plugins/cypress-preset'; 3 | 4 | export default defineConfig({ 5 | e2e: nxE2EPreset(__dirname), 6 | }); 7 | -------------------------------------------------------------------------------- /apps/shell-e2e/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shell-e2e", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "apps/shell-e2e/src", 5 | "projectType": "application", 6 | "targets": { 7 | "e2e": { 8 | "executor": "@nrwl/cypress:cypress", 9 | "options": { 10 | "cypressConfig": "apps/shell-e2e/cypress.config.ts", 11 | "devServerTarget": "shell:serve:development", 12 | "testingType": "e2e" 13 | }, 14 | "configurations": { 15 | "production": { 16 | "devServerTarget": "shell:serve:production" 17 | } 18 | } 19 | }, 20 | "lint": { 21 | "executor": "@nrwl/linter:eslint", 22 | "outputs": [ 23 | "{options.outputFile}" 24 | ], 25 | "options": { 26 | "lintFilePatterns": [ 27 | "apps/shell-e2e/**/*.{js,ts}" 28 | ] 29 | } 30 | } 31 | }, 32 | "tags": [], 33 | "implicitDependencies": [ 34 | "shell" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /apps/shell-e2e/src/e2e/app.cy.ts: -------------------------------------------------------------------------------- 1 | import { getGreeting } from '../support/app.po'; 2 | 3 | describe('shell', () => { 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 shell'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /apps/shell-e2e/src/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io" 4 | } 5 | -------------------------------------------------------------------------------- /apps/shell-e2e/src/support/app.po.ts: -------------------------------------------------------------------------------- 1 | export const getGreeting = () => cy.get('h1'); 2 | -------------------------------------------------------------------------------- /apps/shell-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/shell-e2e/src/support/e2e.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/shell-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 | "forceConsistentCasingInFileNames": true, 9 | "strict": true, 10 | "noImplicitOverride": true, 11 | "noPropertyAccessFromIndexSignature": true, 12 | "noImplicitReturns": true, 13 | "noFallthroughCasesInSwitch": true 14 | }, 15 | "include": ["src/**/*.ts", "src/**/*.js", "cypress.config.ts"], 16 | "angularCompilerOptions": { 17 | "enableI18nLegacyMessageIdFormat": false, 18 | "strictInjectionParameters": true, 19 | "strictInputAccessModifiers": true, 20 | "strictTemplates": true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /apps/shell/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | -------------------------------------------------------------------------------- /apps/shell/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "extends": [ 8 | "plugin:@nrwl/nx/angular", 9 | "plugin:@angular-eslint/template/process-inline-templates" 10 | ], 11 | "rules": { 12 | "@angular-eslint/directive-selector": [ 13 | "error", 14 | { 15 | "type": "attribute", 16 | "prefix": "dynamicModuleFederation", 17 | "style": "camelCase" 18 | } 19 | ], 20 | "@angular-eslint/component-selector": [ 21 | "error", 22 | { 23 | "type": "element", 24 | "prefix": "dynamic-module-federation", 25 | "style": "kebab-case" 26 | } 27 | ] 28 | } 29 | }, 30 | { 31 | "files": ["*.html"], 32 | "extends": ["plugin:@nrwl/nx/angular-template"], 33 | "rules": {} 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /apps/shell/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'shell', 4 | preset: '../../jest.preset.js', 5 | setupFilesAfterEnv: ['/src/test-setup.ts'], 6 | globals: { 7 | 'ts-jest': { 8 | tsconfig: '/tsconfig.spec.json', 9 | stringifyContentPathRegex: '\\.(html|svg)$', 10 | }, 11 | }, 12 | coverageDirectory: '../../coverage/apps/shell', 13 | transform: { 14 | '^.+\\.(ts|mjs|js|html)$': 'jest-preset-angular', 15 | }, 16 | transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], 17 | snapshotSerializers: [ 18 | 'jest-preset-angular/build/serializers/no-ng-attributes', 19 | 'jest-preset-angular/build/serializers/ng-snapshot', 20 | 'jest-preset-angular/build/serializers/html-comment', 21 | ], 22 | }; 23 | -------------------------------------------------------------------------------- /apps/shell/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shell", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "projectType": "application", 5 | "sourceRoot": "apps/shell/src", 6 | "prefix": "dynamic-module-federation", 7 | "targets": { 8 | "build": { 9 | "executor": "@nrwl/angular:webpack-browser", 10 | "outputs": [ 11 | "{options.outputPath}" 12 | ], 13 | "options": { 14 | "outputPath": "dist/apps/shell", 15 | "index": "apps/shell/src/index.html", 16 | "main": "apps/shell/src/main.ts", 17 | "polyfills": "apps/shell/src/polyfills.ts", 18 | "tsConfig": "apps/shell/tsconfig.app.json", 19 | "inlineStyleLanguage": "scss", 20 | "assets": [ 21 | "apps/shell/src/favicon.ico", 22 | "apps/shell/src/assets" 23 | ], 24 | "styles": [ 25 | "apps/shell/src/styles.scss" 26 | ], 27 | "scripts": [], 28 | "customWebpackConfig": { 29 | "path": "apps/shell/webpack.config.js" 30 | }, 31 | "commonChunk": false 32 | }, 33 | "configurations": { 34 | "production": { 35 | "budgets": [ 36 | { 37 | "type": "initial", 38 | "maximumWarning": "500kb", 39 | "maximumError": "1mb" 40 | }, 41 | { 42 | "type": "anyComponentStyle", 43 | "maximumWarning": "2kb", 44 | "maximumError": "4kb" 45 | } 46 | ], 47 | "fileReplacements": [ 48 | { 49 | "replace": "apps/shell/src/environments/environment.ts", 50 | "with": "apps/shell/src/environments/environment.prod.ts" 51 | } 52 | ], 53 | "outputHashing": "all", 54 | "customWebpackConfig": { 55 | "path": "apps/shell/webpack.prod.config.js" 56 | } 57 | }, 58 | "development": { 59 | "buildOptimizer": false, 60 | "optimization": false, 61 | "vendorChunk": true, 62 | "extractLicenses": false, 63 | "sourceMap": true, 64 | "namedChunks": true 65 | } 66 | }, 67 | "defaultConfiguration": "production" 68 | }, 69 | "serve": { 70 | "executor": "@nrwl/angular:webpack-dev-server", 71 | "configurations": { 72 | "production": { 73 | "browserTarget": "shell:build:production" 74 | }, 75 | "development": { 76 | "browserTarget": "shell:build:development" 77 | } 78 | }, 79 | "defaultConfiguration": "development", 80 | "options": { 81 | "port": 4200, 82 | "publicHost": "http://localhost:4200" 83 | } 84 | }, 85 | "extract-i18n": { 86 | "executor": "ngx-build-plus:extract-i18n", 87 | "options": { 88 | "browserTarget": "shell:build", 89 | "extraWebpackConfig": "apps/shell/webpack.config.js" 90 | } 91 | }, 92 | "lint": { 93 | "executor": "@nrwl/linter:eslint", 94 | "options": { 95 | "lintFilePatterns": [ 96 | "apps/shell/**/*.ts", 97 | "apps/shell/**/*.html" 98 | ] 99 | } 100 | }, 101 | "test": { 102 | "executor": "@nrwl/jest:jest", 103 | "outputs": [ 104 | "{workspaceRoot}/coverage/{projectRoot}" 105 | ], 106 | "options": { 107 | "jestConfig": "apps/shell/jest.config.ts", 108 | "passWithNoTests": true 109 | } 110 | } 111 | }, 112 | "tags": [] 113 | } 114 | -------------------------------------------------------------------------------- /apps/shell/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 | 5 | 6 |
7 | 8 |
9 |
-------------------------------------------------------------------------------- /apps/shell/src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | 2 | .content { 3 | display: flex; 4 | flex-direction: column; 5 | height: 94%; 6 | width: 96%; 7 | position: absolute; 8 | padding: 2%; 9 | 10 | .nav { 11 | flex-grow: none; 12 | } 13 | 14 | .remote { 15 | flex-grow: 1; 16 | padding: 20px; 17 | border: 5px dotted red; 18 | } 19 | } -------------------------------------------------------------------------------- /apps/shell/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { Component } from '@angular/core'; 3 | import { RouterLinkWithHref, RouterOutlet } from '@angular/router'; 4 | import { NavbarComponent } from './components/navbar/navbar.component'; 5 | 6 | @Component({ 7 | standalone: true, 8 | imports: [CommonModule, RouterOutlet, RouterLinkWithHref, NavbarComponent], 9 | selector: 'dynamic-module-federation-root', 10 | templateUrl: './app.component.html', 11 | styleUrls: ['./app.component.scss'], 12 | }) 13 | export class AppComponent { 14 | } 15 | -------------------------------------------------------------------------------- /apps/shell/src/app/components/navbar/navbar.component.html: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /apps/shell/src/app/components/navbar/navbar.component.scss: -------------------------------------------------------------------------------- 1 | @mixin box($color, $light-color) { 2 | border-radius: 5px; 3 | border: 2px solid $color; 4 | padding: 5px; 5 | background-color: $light-color; 6 | } 7 | 8 | .navbar { 9 | @include box(black, lightgray); 10 | display: flex; 11 | flex-direction: row; 12 | justify-content: space-around; 13 | margin-bottom: 10px; 14 | 15 | a { 16 | @include box(purple, lightpink); 17 | } 18 | } -------------------------------------------------------------------------------- /apps/shell/src/app/components/navbar/navbar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { RouterLinkWithHref } from '@angular/router'; 4 | import { getManifest } from '@angular-architects/module-federation'; 5 | import { CustomManifest } from '../../utils/custom-manifest'; 6 | 7 | @Component({ 8 | selector: 'dynamic-module-federation-navbar', 9 | standalone: true, 10 | imports: [CommonModule, RouterLinkWithHref], 11 | templateUrl: './navbar.component.html', 12 | styleUrls: ['./navbar.component.scss'], 13 | }) 14 | export class NavbarComponent { 15 | readonly manifest = getManifest(); 16 | } 17 | -------------------------------------------------------------------------------- /apps/shell/src/app/utils/custom-manifest.ts: -------------------------------------------------------------------------------- 1 | import { Manifest, RemoteConfig } from "@angular-architects/module-federation"; 2 | 3 | export type CustomRemoteConfig = RemoteConfig & { 4 | exposedModule: string; 5 | route: string; 6 | routeConfigName: string; 7 | }; 8 | 9 | export type CustomManifest = Manifest; -------------------------------------------------------------------------------- /apps/shell/src/app/utils/route-factory.ts: -------------------------------------------------------------------------------- 1 | import { getManifest, loadRemoteModule } from '@angular-architects/module-federation'; 2 | import { Routes } from '@angular/router'; 3 | import { CustomManifest } from './custom-manifest'; 4 | 5 | export function createRoutes(): Routes { 6 | return Object.entries(getManifest()).map(([key, value]) => ({ 7 | path: value.route, 8 | loadChildren: () => 9 | loadRemoteModule({ 10 | type: 'manifest', 11 | remoteName: key, 12 | exposedModule: value.exposedModule, 13 | }).then((m) => m[value.routeConfigName]), 14 | })); 15 | } 16 | -------------------------------------------------------------------------------- /apps/shell/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaasStefan/dynamic-module-federation/7686b0de54f9bb5f8e8546f48cc121b72422bfc0/apps/shell/src/assets/.gitkeep -------------------------------------------------------------------------------- /apps/shell/src/assets/mf.manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "remote1": { 3 | "remoteEntry": "http://localhost:4201/remoteEntry.js", 4 | "exposedModule": "./Routes", 5 | "route": "one", 6 | "routeConfigName": "routes" 7 | }, 8 | "remote2": { 9 | "remoteEntry": "http://localhost:4202/remoteEntry.js", 10 | "exposedModule": "./Routes", 11 | "route": "two", 12 | "routeConfigName": "routes" 13 | } 14 | } -------------------------------------------------------------------------------- /apps/shell/src/bootstrap.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode, importProvidersFrom } from '@angular/core'; 2 | import { bootstrapApplication } from '@angular/platform-browser'; 3 | import { provideRouter, ROUTES } from '@angular/router'; 4 | import { AppComponent } from './app/app.component'; 5 | import { HttpClientModule } from '@angular/common/http'; 6 | import { environment } from './environments/environment'; 7 | import { createRoutes } from './app/utils/route-factory'; 8 | 9 | if (environment.production) { 10 | enableProdMode(); 11 | } 12 | 13 | bootstrapApplication(AppComponent, { 14 | providers: [ 15 | importProvidersFrom(HttpClientModule), 16 | provideRouter([]), 17 | { 18 | provide: ROUTES, 19 | useFactory: () => createRoutes(), 20 | multi: true, 21 | }, 22 | ], 23 | }).catch((err) => console.error(err)); 24 | -------------------------------------------------------------------------------- /apps/shell/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | }; 4 | -------------------------------------------------------------------------------- /apps/shell/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false, 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /apps/shell/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaasStefan/dynamic-module-federation/7686b0de54f9bb5f8e8546f48cc121b72422bfc0/apps/shell/src/favicon.ico -------------------------------------------------------------------------------- /apps/shell/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Shell 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/shell/src/main.ts: -------------------------------------------------------------------------------- 1 | import { loadManifest } from '@angular-architects/module-federation'; 2 | 3 | loadManifest('/assets/mf.manifest.json') 4 | .catch((err) => console.error(err)) 5 | .then(() => import('./bootstrap')) 6 | .catch((err) => console.error(err)); 7 | -------------------------------------------------------------------------------- /apps/shell/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes recent versions of Safari, Chrome (including 12 | * Opera), Edge on the desktop, and iOS and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** 22 | * By default, zone.js will patch all possible macroTask and DomEvents 23 | * user can disable parts of macroTask/DomEvents patch by setting following flags 24 | * because those flags need to be set before `zone.js` being loaded, and webpack 25 | * will put import in the top of bundle, so user need to create a separate file 26 | * in this directory (for example: zone-flags.ts), and put the following flags 27 | * into that file, and then add the following code before importing zone.js. 28 | * import './zone-flags'; 29 | * 30 | * The flags allowed in zone-flags.ts are listed here. 31 | * 32 | * The following flags will work for all browsers. 33 | * 34 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 35 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 36 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 37 | * 38 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 39 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 40 | * 41 | * (window as any).__Zone_enable_cross_context_check = true; 42 | * 43 | */ 44 | 45 | /*************************************************************************************************** 46 | * Zone JS is required by default for Angular itself. 47 | */ 48 | import 'zone.js'; // Included with Angular CLI. 49 | 50 | /*************************************************************************************************** 51 | * APPLICATION IMPORTS 52 | */ 53 | -------------------------------------------------------------------------------- /apps/shell/src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | 4 | html, body { 5 | font-family: 'Comic Sans MS'; 6 | margin: 0px; 7 | padding: 0px; 8 | } -------------------------------------------------------------------------------- /apps/shell/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | -------------------------------------------------------------------------------- /apps/shell/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": [], 6 | "target": "es2020" 7 | }, 8 | "files": [ 9 | "src/main.ts", 10 | "src/polyfills.ts" 11 | ], 12 | "include": [ 13 | "src/**/*.d.ts" 14 | ], 15 | "exclude": [ 16 | "jest.config.ts", 17 | "**/*.test.ts", 18 | "**/*.spec.ts" 19 | ] 20 | } -------------------------------------------------------------------------------- /apps/shell/tsconfig.editor.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["**/*.ts"], 4 | "compilerOptions": { 5 | "types": ["jest", "node"] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /apps/shell/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.app.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | }, 12 | { 13 | "path": "./tsconfig.editor.json" 14 | } 15 | ], 16 | "compilerOptions": { 17 | "target": "es2020", 18 | "forceConsistentCasingInFileNames": true, 19 | "strict": true, 20 | "noImplicitOverride": true, 21 | "noPropertyAccessFromIndexSignature": true, 22 | "noImplicitReturns": true, 23 | "noFallthroughCasesInSwitch": true 24 | }, 25 | "angularCompilerOptions": { 26 | "enableI18nLegacyMessageIdFormat": false, 27 | "strictInjectionParameters": true, 28 | "strictInputAccessModifiers": true, 29 | "strictTemplates": true 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /apps/shell/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /apps/shell/webpack.config.js: -------------------------------------------------------------------------------- 1 | const { shareAll, withModuleFederationPlugin } = require('@angular-architects/module-federation/webpack'); 2 | 3 | module.exports = withModuleFederationPlugin({ 4 | 5 | shared: { 6 | ...shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }), 7 | }, 8 | 9 | }); 10 | -------------------------------------------------------------------------------- /apps/shell/webpack.prod.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./webpack.config'); 2 | -------------------------------------------------------------------------------- /decorate-angular-cli.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file decorates the Angular CLI with the Nx CLI to enable features such as computation caching 3 | * and faster execution of tasks. 4 | * 5 | * It does this by: 6 | * 7 | * - Patching the Angular CLI to warn you in case you accidentally use the undecorated ng command. 8 | * - Symlinking the ng to nx command, so all commands run through the Nx CLI 9 | * - Updating the package.json postinstall script to give you control over this script 10 | * 11 | * The Nx CLI decorates the Angular CLI, so the Nx CLI is fully compatible with it. 12 | * Every command you run should work the same when using the Nx CLI, except faster. 13 | * 14 | * Because of symlinking you can still type `ng build/test/lint` in the terminal. The ng command, in this case, 15 | * will point to nx, which will perform optimizations before invoking ng. So the Angular CLI is always invoked. 16 | * The Nx CLI simply does some optimizations before invoking the Angular CLI. 17 | * 18 | * To opt out of this patch: 19 | * - Replace occurrences of nx with ng in your package.json 20 | * - Remove the script from your postinstall script in your package.json 21 | * - Delete and reinstall your node_modules 22 | */ 23 | 24 | const fs = require('fs'); 25 | const os = require('os'); 26 | const cp = require('child_process'); 27 | const isWindows = os.platform() === 'win32'; 28 | let output; 29 | try { 30 | output = require('@nrwl/workspace').output; 31 | } catch (e) { 32 | console.warn('Angular CLI could not be decorated to enable computation caching. Please ensure @nrwl/workspace is installed.'); 33 | process.exit(0); 34 | } 35 | 36 | /** 37 | * Symlink of ng to nx, so you can keep using `ng build/test/lint` and still 38 | * invoke the Nx CLI and get the benefits of computation caching. 39 | */ 40 | function symlinkNgCLItoNxCLI() { 41 | try { 42 | const ngPath = './node_modules/.bin/ng'; 43 | const nxPath = './node_modules/.bin/nx'; 44 | if (isWindows) { 45 | /** 46 | * This is the most reliable way to create symlink-like behavior on Windows. 47 | * Such that it works in all shells and works with npx. 48 | */ 49 | ['', '.cmd', '.ps1'].forEach(ext => { 50 | if (fs.existsSync(nxPath + ext)) fs.writeFileSync(ngPath + ext, fs.readFileSync(nxPath + ext)); 51 | }); 52 | } else { 53 | // If unix-based, symlink 54 | cp.execSync(`ln -sf ./nx ${ngPath}`); 55 | } 56 | } 57 | catch(e) { 58 | output.error({ title: 'Unable to create a symlink from the Angular CLI to the Nx CLI:' + e.message }); 59 | throw e; 60 | } 61 | } 62 | 63 | try { 64 | symlinkNgCLItoNxCLI(); 65 | require('nx/src/adapter/decorate-cli').decorateCli(); 66 | output.log({ title: 'Angular CLI has been decorated to enable computation caching.' }); 67 | } catch(e) { 68 | output.error({ title: 'Decoration of the Angular CLI did not complete successfully' }); 69 | } 70 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import { getJestProjects } from '@nrwl/jest'; 2 | 3 | export default { 4 | projects: getJestProjects(), 5 | }; 6 | -------------------------------------------------------------------------------- /jest.preset.js: -------------------------------------------------------------------------------- 1 | const nxPreset = require('@nrwl/jest/preset').default; 2 | 3 | module.exports = { ...nxPreset }; 4 | -------------------------------------------------------------------------------- /libs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaasStefan/dynamic-module-federation/7686b0de54f9bb5f8e8546f48cc121b72422bfc0/libs/.gitkeep -------------------------------------------------------------------------------- /libs/remote1-lib/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "extends": [ 8 | "plugin:@nrwl/nx/angular", 9 | "plugin:@angular-eslint/template/process-inline-templates" 10 | ], 11 | "rules": { 12 | "@angular-eslint/directive-selector": [ 13 | "error", 14 | { 15 | "type": "attribute", 16 | "prefix": "dynamicModuleFederation", 17 | "style": "camelCase" 18 | } 19 | ], 20 | "@angular-eslint/component-selector": [ 21 | "error", 22 | { 23 | "type": "element", 24 | "prefix": "dynamic-module-federation", 25 | "style": "kebab-case" 26 | } 27 | ] 28 | } 29 | }, 30 | { 31 | "files": ["*.html"], 32 | "extends": ["plugin:@nrwl/nx/angular-template"], 33 | "rules": {} 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /libs/remote1-lib/README.md: -------------------------------------------------------------------------------- 1 | # remote1-lib 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test remote1-lib` to execute the unit tests. 8 | -------------------------------------------------------------------------------- /libs/remote1-lib/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'remote1-lib', 4 | preset: '../../jest.preset.js', 5 | setupFilesAfterEnv: ['/src/test-setup.ts'], 6 | globals: { 7 | 'ts-jest': { 8 | tsconfig: '/tsconfig.spec.json', 9 | stringifyContentPathRegex: '\\.(html|svg)$', 10 | }, 11 | }, 12 | coverageDirectory: '../../coverage/libs/remote1-lib', 13 | transform: { 14 | '^.+\\.(ts|mjs|js|html)$': 'jest-preset-angular', 15 | }, 16 | transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], 17 | snapshotSerializers: [ 18 | 'jest-preset-angular/build/serializers/no-ng-attributes', 19 | 'jest-preset-angular/build/serializers/ng-snapshot', 20 | 'jest-preset-angular/build/serializers/html-comment', 21 | ], 22 | }; 23 | -------------------------------------------------------------------------------- /libs/remote1-lib/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remote1-lib", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "projectType": "library", 5 | "sourceRoot": "libs/remote1-lib/src", 6 | "prefix": "dynamic-module-federation", 7 | "targets": { 8 | "test": { 9 | "executor": "@nrwl/jest:jest", 10 | "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], 11 | "options": { 12 | "jestConfig": "libs/remote1-lib/jest.config.ts", 13 | "passWithNoTests": true 14 | } 15 | }, 16 | "lint": { 17 | "executor": "@nrwl/linter:eslint", 18 | "options": { 19 | "lintFilePatterns": [ 20 | "libs/remote1-lib/**/*.ts", 21 | "libs/remote1-lib/**/*.html" 22 | ] 23 | } 24 | } 25 | }, 26 | "tags": [] 27 | } 28 | -------------------------------------------------------------------------------- /libs/remote1-lib/src/index.ts: -------------------------------------------------------------------------------- 1 | export {routes} from './lib/remote1.routes'; -------------------------------------------------------------------------------- /libs/remote1-lib/src/lib/components/some/some.component.html: -------------------------------------------------------------------------------- 1 |

some works!

2 | -------------------------------------------------------------------------------- /libs/remote1-lib/src/lib/components/some/some.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaasStefan/dynamic-module-federation/7686b0de54f9bb5f8e8546f48cc121b72422bfc0/libs/remote1-lib/src/lib/components/some/some.component.scss -------------------------------------------------------------------------------- /libs/remote1-lib/src/lib/components/some/some.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { EchoService } from '@dynamic-module-federation/shared'; 4 | 5 | @Component({ 6 | selector: 'dynamic-module-federation-some', 7 | standalone: true, 8 | imports: [CommonModule], 9 | templateUrl: './some.component.html', 10 | styleUrls: ['./some.component.scss'], 11 | }) 12 | export class SomeComponent implements OnInit { 13 | constructor( 14 | private echo: EchoService 15 | ) { 16 | } 17 | 18 | ngOnInit(): void { 19 | this.echo.print('some'); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /libs/remote1-lib/src/lib/remote1.routes.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | import { SomeComponent } from './components/some/some.component'; 3 | 4 | export const routes: Routes = [ 5 | { 6 | path: '', 7 | component: SomeComponent, 8 | }, 9 | ]; 10 | -------------------------------------------------------------------------------- /libs/remote1-lib/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | -------------------------------------------------------------------------------- /libs/remote1-lib/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "compilerOptions": { 14 | "target": "es2020", 15 | "forceConsistentCasingInFileNames": true, 16 | "strict": true, 17 | "noImplicitOverride": true, 18 | "noPropertyAccessFromIndexSignature": true, 19 | "noImplicitReturns": true, 20 | "noFallthroughCasesInSwitch": true 21 | }, 22 | "angularCompilerOptions": { 23 | "enableI18nLegacyMessageIdFormat": false, 24 | "strictInjectionParameters": true, 25 | "strictInputAccessModifiers": true, 26 | "strictTemplates": true 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /libs/remote1-lib/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "declarationMap": true, 7 | "inlineSources": true, 8 | "types": [] 9 | }, 10 | "exclude": [ 11 | "src/test-setup.ts", 12 | "**/*.spec.ts", 13 | "jest.config.ts", 14 | "**/*.test.ts" 15 | ], 16 | "include": ["**/*.ts"] 17 | } 18 | -------------------------------------------------------------------------------- /libs/remote1-lib/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /libs/remote2-lib/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "extends": [ 8 | "plugin:@nrwl/nx/angular", 9 | "plugin:@angular-eslint/template/process-inline-templates" 10 | ], 11 | "rules": { 12 | "@angular-eslint/directive-selector": [ 13 | "error", 14 | { 15 | "type": "attribute", 16 | "prefix": "dynamicModuleFederation", 17 | "style": "camelCase" 18 | } 19 | ], 20 | "@angular-eslint/component-selector": [ 21 | "error", 22 | { 23 | "type": "element", 24 | "prefix": "dynamic-module-federation", 25 | "style": "kebab-case" 26 | } 27 | ] 28 | } 29 | }, 30 | { 31 | "files": ["*.html"], 32 | "extends": ["plugin:@nrwl/nx/angular-template"], 33 | "rules": {} 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /libs/remote2-lib/README.md: -------------------------------------------------------------------------------- 1 | # remote2-lib 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test remote2-lib` to execute the unit tests. 8 | -------------------------------------------------------------------------------- /libs/remote2-lib/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'remote2-lib', 4 | preset: '../../jest.preset.js', 5 | setupFilesAfterEnv: ['/src/test-setup.ts'], 6 | globals: { 7 | 'ts-jest': { 8 | tsconfig: '/tsconfig.spec.json', 9 | stringifyContentPathRegex: '\\.(html|svg)$', 10 | }, 11 | }, 12 | coverageDirectory: '../../coverage/libs/remote2-lib', 13 | transform: { 14 | '^.+\\.(ts|mjs|js|html)$': 'jest-preset-angular', 15 | }, 16 | transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], 17 | snapshotSerializers: [ 18 | 'jest-preset-angular/build/serializers/no-ng-attributes', 19 | 'jest-preset-angular/build/serializers/ng-snapshot', 20 | 'jest-preset-angular/build/serializers/html-comment', 21 | ], 22 | }; 23 | -------------------------------------------------------------------------------- /libs/remote2-lib/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remote2-lib", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "projectType": "library", 5 | "sourceRoot": "libs/remote2-lib/src", 6 | "prefix": "dynamic-module-federation", 7 | "targets": { 8 | "test": { 9 | "executor": "@nrwl/jest:jest", 10 | "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], 11 | "options": { 12 | "jestConfig": "libs/remote2-lib/jest.config.ts", 13 | "passWithNoTests": true 14 | } 15 | }, 16 | "lint": { 17 | "executor": "@nrwl/linter:eslint", 18 | "options": { 19 | "lintFilePatterns": [ 20 | "libs/remote2-lib/**/*.ts", 21 | "libs/remote2-lib/**/*.html" 22 | ] 23 | } 24 | } 25 | }, 26 | "tags": [] 27 | } 28 | -------------------------------------------------------------------------------- /libs/remote2-lib/src/index.ts: -------------------------------------------------------------------------------- 1 | 2 | export {routes} from './lib/remote2.routes'; -------------------------------------------------------------------------------- /libs/remote2-lib/src/lib/components/four/four.component.html: -------------------------------------------------------------------------------- 1 |

four works!

2 | -------------------------------------------------------------------------------- /libs/remote2-lib/src/lib/components/four/four.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaasStefan/dynamic-module-federation/7686b0de54f9bb5f8e8546f48cc121b72422bfc0/libs/remote2-lib/src/lib/components/four/four.component.scss -------------------------------------------------------------------------------- /libs/remote2-lib/src/lib/components/four/four.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { EchoService } from '@dynamic-module-federation/shared'; 4 | 5 | @Component({ 6 | selector: 'dynamic-module-federation-four', 7 | standalone: true, 8 | imports: [CommonModule], 9 | templateUrl: './four.component.html', 10 | styleUrls: ['./four.component.scss'], 11 | }) 12 | export class FourComponent implements OnInit { 13 | constructor( 14 | private echo: EchoService 15 | ) {} 16 | 17 | ngOnInit(): void { 18 | this.echo.print('4'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /libs/remote2-lib/src/lib/components/one/one.component.html: -------------------------------------------------------------------------------- 1 |

one works!

2 | -------------------------------------------------------------------------------- /libs/remote2-lib/src/lib/components/one/one.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaasStefan/dynamic-module-federation/7686b0de54f9bb5f8e8546f48cc121b72422bfc0/libs/remote2-lib/src/lib/components/one/one.component.scss -------------------------------------------------------------------------------- /libs/remote2-lib/src/lib/components/one/one.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { EchoService } from '@dynamic-module-federation/shared'; 4 | 5 | @Component({ 6 | selector: 'dynamic-module-federation-one', 7 | standalone: true, 8 | imports: [CommonModule], 9 | templateUrl: './one.component.html', 10 | styleUrls: ['./one.component.scss'], 11 | }) 12 | export class OneComponent implements OnInit { 13 | constructor( 14 | private echo: EchoService 15 | ) {} 16 | 17 | ngOnInit(): void { 18 | this.echo.print('1'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /libs/remote2-lib/src/lib/components/three/three.component.html: -------------------------------------------------------------------------------- 1 |

three works!

2 | -------------------------------------------------------------------------------- /libs/remote2-lib/src/lib/components/three/three.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaasStefan/dynamic-module-federation/7686b0de54f9bb5f8e8546f48cc121b72422bfc0/libs/remote2-lib/src/lib/components/three/three.component.scss -------------------------------------------------------------------------------- /libs/remote2-lib/src/lib/components/three/three.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { EchoService } from '@dynamic-module-federation/shared'; 4 | 5 | @Component({ 6 | selector: 'dynamic-module-federation-three', 7 | standalone: true, 8 | imports: [CommonModule], 9 | templateUrl: './three.component.html', 10 | styleUrls: ['./three.component.scss'], 11 | }) 12 | export class ThreeComponent implements OnInit { 13 | constructor( 14 | private echo: EchoService 15 | ) {} 16 | 17 | ngOnInit(): void { 18 | this.echo.print('3'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /libs/remote2-lib/src/lib/components/two/two.component.html: -------------------------------------------------------------------------------- 1 |

two works!

2 | -------------------------------------------------------------------------------- /libs/remote2-lib/src/lib/components/two/two.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaasStefan/dynamic-module-federation/7686b0de54f9bb5f8e8546f48cc121b72422bfc0/libs/remote2-lib/src/lib/components/two/two.component.scss -------------------------------------------------------------------------------- /libs/remote2-lib/src/lib/components/two/two.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { EchoService } from '@dynamic-module-federation/shared'; 4 | 5 | @Component({ 6 | selector: 'dynamic-module-federation-two', 7 | standalone: true, 8 | imports: [CommonModule], 9 | templateUrl: './two.component.html', 10 | styleUrls: ['./two.component.scss'], 11 | }) 12 | export class TwoComponent implements OnInit { 13 | constructor( 14 | private echo: EchoService 15 | ) {} 16 | 17 | ngOnInit(): void { 18 | this.echo.print('2'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /libs/remote2-lib/src/lib/components/wrapper/wrapper.component.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /libs/remote2-lib/src/lib/components/wrapper/wrapper.component.scss: -------------------------------------------------------------------------------- 1 | @mixin box($color, $light-color) { 2 | border-radius: 5px; 3 | border: 2px solid $color; 4 | padding: 5px; 5 | background-color: $light-color; 6 | } 7 | 8 | .navbar { 9 | @include box(blue, lightblue); 10 | display: flex; 11 | flex-direction: row; 12 | justify-content: space-around; 13 | 14 | a { 15 | @include box(red, lightcoral); 16 | } 17 | } -------------------------------------------------------------------------------- /libs/remote2-lib/src/lib/components/wrapper/wrapper.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { RouterLinkWithHref, RouterOutlet } from '@angular/router'; 4 | 5 | @Component({ 6 | selector: 'dynamic-module-federation-wrapper', 7 | standalone: true, 8 | imports: [CommonModule, RouterOutlet, RouterLinkWithHref], 9 | templateUrl: './wrapper.component.html', 10 | styleUrls: ['./wrapper.component.scss'], 11 | }) 12 | export class WrapperComponent { 13 | } 14 | -------------------------------------------------------------------------------- /libs/remote2-lib/src/lib/remote2.routes.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | import { FourComponent } from './components/four/four.component'; 3 | import { OneComponent } from './components/one/one.component'; 4 | import { ThreeComponent } from './components/three/three.component'; 5 | import { TwoComponent } from './components/two/two.component'; 6 | import { WrapperComponent } from './components/wrapper/wrapper.component'; 7 | 8 | export const routes: Routes = [ 9 | { 10 | path: '', 11 | component: WrapperComponent, 12 | providers: [], 13 | children: [ 14 | { 15 | path: '', 16 | redirectTo: '1', 17 | pathMatch: 'full' 18 | }, 19 | { 20 | path: '1', 21 | component: OneComponent, 22 | }, 23 | { 24 | path: '2', 25 | component: TwoComponent, 26 | }, 27 | { 28 | path: '3', 29 | component: ThreeComponent, 30 | }, 31 | { 32 | path: '4', 33 | component: FourComponent, 34 | }, 35 | ], 36 | }, 37 | ]; 38 | -------------------------------------------------------------------------------- /libs/remote2-lib/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | -------------------------------------------------------------------------------- /libs/remote2-lib/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "compilerOptions": { 14 | "target": "es2020", 15 | "forceConsistentCasingInFileNames": true, 16 | "strict": true, 17 | "noImplicitOverride": true, 18 | "noPropertyAccessFromIndexSignature": true, 19 | "noImplicitReturns": true, 20 | "noFallthroughCasesInSwitch": true 21 | }, 22 | "angularCompilerOptions": { 23 | "enableI18nLegacyMessageIdFormat": false, 24 | "strictInjectionParameters": true, 25 | "strictInputAccessModifiers": true, 26 | "strictTemplates": true 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /libs/remote2-lib/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "declarationMap": true, 7 | "inlineSources": true, 8 | "types": [] 9 | }, 10 | "exclude": [ 11 | "src/test-setup.ts", 12 | "**/*.spec.ts", 13 | "jest.config.ts", 14 | "**/*.test.ts" 15 | ], 16 | "include": ["**/*.ts"] 17 | } 18 | -------------------------------------------------------------------------------- /libs/remote2-lib/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /libs/shared/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "extends": [ 8 | "plugin:@nrwl/nx/angular", 9 | "plugin:@angular-eslint/template/process-inline-templates" 10 | ], 11 | "rules": { 12 | "@angular-eslint/directive-selector": [ 13 | "error", 14 | { 15 | "type": "attribute", 16 | "prefix": "dynamicModuleFederation", 17 | "style": "camelCase" 18 | } 19 | ], 20 | "@angular-eslint/component-selector": [ 21 | "error", 22 | { 23 | "type": "element", 24 | "prefix": "dynamic-module-federation", 25 | "style": "kebab-case" 26 | } 27 | ] 28 | } 29 | }, 30 | { 31 | "files": ["*.html"], 32 | "extends": ["plugin:@nrwl/nx/angular-template"], 33 | "rules": {} 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /libs/shared/README.md: -------------------------------------------------------------------------------- 1 | # shared 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test shared` to execute the unit tests. 8 | -------------------------------------------------------------------------------- /libs/shared/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'shared', 4 | preset: '../../jest.preset.js', 5 | setupFilesAfterEnv: ['/src/test-setup.ts'], 6 | globals: { 7 | 'ts-jest': { 8 | tsconfig: '/tsconfig.spec.json', 9 | stringifyContentPathRegex: '\\.(html|svg)$', 10 | }, 11 | }, 12 | coverageDirectory: '../../coverage/libs/shared', 13 | transform: { 14 | '^.+\\.(ts|mjs|js|html)$': 'jest-preset-angular', 15 | }, 16 | transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], 17 | snapshotSerializers: [ 18 | 'jest-preset-angular/build/serializers/no-ng-attributes', 19 | 'jest-preset-angular/build/serializers/ng-snapshot', 20 | 'jest-preset-angular/build/serializers/html-comment', 21 | ], 22 | }; 23 | -------------------------------------------------------------------------------- /libs/shared/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shared", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "projectType": "library", 5 | "sourceRoot": "libs/shared/src", 6 | "prefix": "dynamic-module-federation", 7 | "targets": { 8 | "test": { 9 | "executor": "@nrwl/jest:jest", 10 | "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], 11 | "options": { 12 | "jestConfig": "libs/shared/jest.config.ts", 13 | "passWithNoTests": true 14 | } 15 | }, 16 | "lint": { 17 | "executor": "@nrwl/linter:eslint", 18 | "options": { 19 | "lintFilePatterns": ["libs/shared/**/*.ts", "libs/shared/**/*.html"] 20 | } 21 | } 22 | }, 23 | "tags": [] 24 | } 25 | -------------------------------------------------------------------------------- /libs/shared/src/index.ts: -------------------------------------------------------------------------------- 1 | export { EchoService } from './lib/services/echo.service'; 2 | -------------------------------------------------------------------------------- /libs/shared/src/lib/services/echo.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | @Injectable({ 4 | providedIn: 'root' 5 | }) 6 | export class EchoService { 7 | print(message: string): void { 8 | console.log(message); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /libs/shared/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | -------------------------------------------------------------------------------- /libs/shared/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ], 13 | "compilerOptions": { 14 | "target": "es2020", 15 | "forceConsistentCasingInFileNames": true, 16 | "strict": true, 17 | "noImplicitOverride": true, 18 | "noPropertyAccessFromIndexSignature": true, 19 | "noImplicitReturns": true, 20 | "noFallthroughCasesInSwitch": true 21 | }, 22 | "angularCompilerOptions": { 23 | "enableI18nLegacyMessageIdFormat": false, 24 | "strictInjectionParameters": true, 25 | "strictInputAccessModifiers": true, 26 | "strictTemplates": true 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /libs/shared/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "declarationMap": true, 7 | "inlineSources": true, 8 | "types": [] 9 | }, 10 | "exclude": [ 11 | "src/test-setup.ts", 12 | "**/*.spec.ts", 13 | "jest.config.ts", 14 | "**/*.test.ts" 15 | ], 16 | "include": ["**/*.ts"] 17 | } 18 | -------------------------------------------------------------------------------- /libs/shared/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "files": ["src/test-setup.ts"], 9 | "include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /nx.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/nx/schemas/nx-schema.json", 3 | "npmScope": "dynamic-module-federation", 4 | "affected": { 5 | "defaultBase": "master" 6 | }, 7 | "tasksRunnerOptions": { 8 | "default": { 9 | "runner": "nx/tasks-runners/default", 10 | "options": { 11 | "cacheableOperations": [ 12 | "build", 13 | "lint", 14 | "test", 15 | "e2e" 16 | ] 17 | } 18 | } 19 | }, 20 | "targetDefaults": { 21 | "build": { 22 | "dependsOn": [ 23 | "^build" 24 | ], 25 | "inputs": [ 26 | "production", 27 | "^production" 28 | ] 29 | }, 30 | "test": { 31 | "inputs": [ 32 | "default", 33 | "^production", 34 | "{workspaceRoot}/jest.preset.js" 35 | ] 36 | }, 37 | "e2e": { 38 | "inputs": [ 39 | "default", 40 | "^production" 41 | ] 42 | }, 43 | "lint": { 44 | "inputs": [ 45 | "default", 46 | "{workspaceRoot}/.eslintrc.json" 47 | ] 48 | } 49 | }, 50 | "namedInputs": { 51 | "default": [ 52 | "{projectRoot}/**/*", 53 | "sharedGlobals" 54 | ], 55 | "production": [ 56 | "default", 57 | "!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)", 58 | "!{projectRoot}/tsconfig.spec.json", 59 | "!{projectRoot}/jest.config.[jt]s", 60 | "!{projectRoot}/.eslintrc.json" 61 | ], 62 | "sharedGlobals": [] 63 | }, 64 | "cli": { 65 | "packageManager": "npm" 66 | }, 67 | "generators": { 68 | "@nrwl/angular:application": { 69 | "style": "scss", 70 | "linter": "eslint", 71 | "unitTestRunner": "jest", 72 | "e2eTestRunner": "cypress" 73 | }, 74 | "@nrwl/angular:library": { 75 | "linter": "eslint", 76 | "unitTestRunner": "jest" 77 | }, 78 | "@nrwl/angular:component": { 79 | "style": "scss" 80 | } 81 | }, 82 | "defaultProject": "shell" 83 | } 84 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dynamic-module-federation", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "ng": "nx", 7 | "postinstall": "node ./decorate-angular-cli.js", 8 | "start": "nx serve", 9 | "build": "nx build", 10 | "test": "nx test", 11 | "run:all": "node node_modules/@angular-architects/module-federation/src/server/mf-dev-server.js" 12 | }, 13 | "private": true, 14 | "dependencies": { 15 | "@angular/animations": "~14.2.0", 16 | "@angular/common": "~14.2.0", 17 | "@angular/compiler": "~14.2.0", 18 | "@angular/core": "~14.2.0", 19 | "@angular/forms": "~14.2.0", 20 | "@angular/platform-browser": "~14.2.0", 21 | "@angular/platform-browser-dynamic": "~14.2.0", 22 | "@angular/router": "~14.2.0", 23 | "@nrwl/angular": "15.0.0", 24 | "rxjs": "~7.5.0", 25 | "tslib": "^2.3.0", 26 | "zone.js": "~0.11.4" 27 | }, 28 | "devDependencies": { 29 | "@angular-architects/module-federation": "^14.3.14", 30 | "@angular-devkit/build-angular": "~14.2.0", 31 | "@angular-eslint/eslint-plugin": "~14.0.4", 32 | "@angular-eslint/eslint-plugin-template": "~14.0.4", 33 | "@angular-eslint/template-parser": "~14.0.4", 34 | "@angular/cli": "~14.2.0", 35 | "@angular/compiler-cli": "~14.2.0", 36 | "@angular/language-service": "~14.2.0", 37 | "@nrwl/cli": "15.0.0", 38 | "@nrwl/cypress": "15.0.0", 39 | "@nrwl/eslint-plugin-nx": "15.0.0", 40 | "@nrwl/jest": "15.0.0", 41 | "@nrwl/linter": "15.0.0", 42 | "@nrwl/workspace": "15.0.0", 43 | "@types/jest": "28.1.1", 44 | "@types/node": "16.11.7", 45 | "@typescript-eslint/eslint-plugin": "^5.36.1", 46 | "@typescript-eslint/parser": "^5.36.1", 47 | "cypress": "^10.7.0", 48 | "eslint": "~8.15.0", 49 | "eslint-config-prettier": "8.1.0", 50 | "eslint-plugin-cypress": "^2.10.3", 51 | "jest": "28.1.1", 52 | "jest-environment-jsdom": "28.1.1", 53 | "jest-preset-angular": "~12.2.2", 54 | "ngx-build-plus": "^14.0.0", 55 | "nx": "15.0.0", 56 | "prettier": "^2.6.2", 57 | "ts-jest": "28.0.5", 58 | "ts-node": "10.9.1", 59 | "typescript": "~4.8.2" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /tools/generators/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HaasStefan/dynamic-module-federation/7686b0de54f9bb5f8e8546f48cc121b72422bfc0/tools/generators/.gitkeep -------------------------------------------------------------------------------- /tools/tsconfig.tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "../dist/out-tsc/tools", 5 | "rootDir": ".", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": ["node"], 9 | "importHelpers": false 10 | }, 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "importHelpers": true, 11 | "target": "es2020", 12 | "module": "esnext", 13 | "lib": ["es2017", "dom"], 14 | "skipLibCheck": true, 15 | "skipDefaultLibCheck": true, 16 | "baseUrl": ".", 17 | "paths": { 18 | "@dynamic-module-federation/remote1-lib": [ 19 | "libs/remote1-lib/src/index.ts" 20 | ], 21 | "@dynamic-module-federation/remote2-lib": [ 22 | "libs/remote2-lib/src/index.ts" 23 | ], 24 | "@dynamic-module-federation/shared": ["libs/shared/src/index.ts"] 25 | } 26 | }, 27 | "exclude": ["node_modules", "tmp"] 28 | } 29 | --------------------------------------------------------------------------------