├── .editorconfig ├── .eslintignore ├── .eslintrc.base.json ├── .eslintrc.json ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.yml │ ├── feature-request.yml │ └── question.yml └── workflows │ └── ci.yml ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .verdaccio └── config.yml ├── .vscode ├── extensions.json └── settings.json ├── LICENSE ├── README.md ├── apps ├── .gitkeep ├── mfe1-e2e │ ├── .eslintrc.json │ ├── cypress.json │ ├── project.json │ ├── src │ │ ├── fixtures │ │ │ └── example.json │ │ ├── integration │ │ │ └── app.spec.ts │ │ ├── plugins │ │ │ └── index.js │ │ └── support │ │ │ ├── app.po.ts │ │ │ ├── commands.ts │ │ │ └── index.ts │ └── tsconfig.json ├── mfe1 │ ├── .eslintrc.json │ ├── federation.config.js │ ├── jest.config.ts │ ├── project.json │ ├── src │ │ ├── app │ │ │ ├── app.component.css │ │ │ ├── app.component.html │ │ │ ├── app.component.spec.ts │ │ │ ├── app.component.ts │ │ │ ├── app.module.ts │ │ │ ├── demo │ │ │ │ ├── demo.component.css │ │ │ │ ├── demo.component.html │ │ │ │ ├── demo.component.spec.ts │ │ │ │ └── demo.component.ts │ │ │ └── nx-welcome.component.ts │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── bootstrap.ts │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main.ts │ │ ├── polyfills.ts │ │ ├── styles.css │ │ └── test-setup.ts │ ├── tsconfig.app.json │ ├── tsconfig.editor.json │ ├── tsconfig.json │ └── tsconfig.spec.json ├── mfe2-e2e │ ├── .eslintrc.json │ ├── cypress.json │ ├── project.json │ ├── src │ │ ├── fixtures │ │ │ └── example.json │ │ ├── integration │ │ │ └── app.spec.ts │ │ ├── plugins │ │ │ └── index.js │ │ └── support │ │ │ ├── app.po.ts │ │ │ ├── commands.ts │ │ │ └── index.ts │ └── tsconfig.json ├── mfe2 │ ├── .eslintrc.json │ ├── federation.config.js │ ├── jest.config.ts │ ├── project.json │ ├── src │ │ ├── app │ │ │ ├── app.component.css │ │ │ ├── app.component.html │ │ │ ├── app.component.spec.ts │ │ │ ├── app.component.ts │ │ │ ├── app.module.ts │ │ │ └── nx-welcome.component.ts │ │ ├── assets │ │ │ ├── .gitkeep │ │ │ └── federation.manifest.json │ │ ├── bootstrap.ts │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main.ts │ │ ├── polyfills.ts │ │ ├── styles.css │ │ └── test-setup.ts │ ├── tsconfig.app.json │ ├── tsconfig.editor.json │ ├── tsconfig.json │ └── tsconfig.spec.json ├── native-federation-e2e │ ├── .eslintrc.json │ ├── jest.config.ts │ ├── project.json │ ├── tests │ │ └── native-federation.spec.ts │ ├── tsconfig.json │ └── tsconfig.spec.json ├── playground-e2e │ ├── .eslintrc.json │ ├── cypress.json │ ├── project.json │ ├── src │ │ ├── fixtures │ │ │ └── example.json │ │ ├── integration │ │ │ └── app.spec.ts │ │ ├── plugins │ │ │ └── index.js │ │ └── support │ │ │ ├── app.po.ts │ │ │ ├── commands.ts │ │ │ └── index.ts │ ├── tsconfig.e2e.json │ └── tsconfig.json └── playground │ ├── .eslintrc.json │ ├── federation.config.js │ ├── jest.config.ts │ ├── project.json │ ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ └── app.module.ts │ ├── assets │ │ └── .gitkeep │ ├── bootstrap.ts │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ └── test-setup.ts │ ├── tsconfig.app.json │ ├── tsconfig.editor.json │ ├── tsconfig.json │ └── tsconfig.spec.json ├── error.png ├── jest.config.ts ├── jest.preset.js ├── libs ├── mf-runtime │ ├── .eslintrc.json │ ├── LICENSE │ ├── README.md │ ├── enhanced │ │ ├── README.md │ │ ├── ng-package.json │ │ └── src │ │ │ ├── index.ts │ │ │ └── lib │ │ │ ├── init-federation.ts │ │ │ └── loadRemoteModule.ts │ ├── jest.config.ts │ ├── ng-package.json │ ├── package.json │ ├── project.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ └── loader │ │ │ │ ├── dynamic-federation.ts │ │ │ │ └── webpack-runtime-api.d.ts │ │ └── test-setup.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ ├── tsconfig.lib.prod.json │ └── tsconfig.spec.json ├── mf-tools │ ├── .eslintrc.json │ ├── .vscode │ │ ├── settings.json │ │ └── spellright.dict │ ├── LICENSE │ ├── README.md │ ├── img │ │ └── example.png │ ├── jest.config.ts │ ├── ng-package.json │ ├── package.json │ ├── project.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── mf-tools.module.ts │ │ │ ├── utils │ │ │ │ └── global-state.ts │ │ │ └── web-components │ │ │ │ ├── bootstrap-utils.ts │ │ │ │ ├── router-utils.ts │ │ │ │ └── web-component-wrapper.ts │ │ └── test-setup.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ ├── tsconfig.lib.prod.json │ ├── tsconfig.spec.json │ └── tutorial │ │ └── index.md ├── mf │ ├── .babelrc │ ├── .eslintrc.json │ ├── LICENSE │ ├── README.md │ ├── builders.json │ ├── collection.json │ ├── executors.json │ ├── generators.json │ ├── jest.config.ts │ ├── nguniversal.ts │ ├── package.json │ ├── post-build.js │ ├── project.json │ ├── rspack.ts │ ├── runtime.ts │ ├── src │ │ ├── builders │ │ │ └── build │ │ │ │ ├── builder.ts │ │ │ │ ├── schema.d.ts │ │ │ │ └── schema.json │ │ ├── executors │ │ │ └── build │ │ │ │ ├── executor.spec.ts │ │ │ │ ├── executor.ts │ │ │ │ ├── schema.d.ts │ │ │ │ └── schema.json │ │ ├── generators │ │ │ └── mf │ │ │ │ ├── files │ │ │ │ └── src │ │ │ │ │ └── index.ts__template__ │ │ │ │ ├── generator.spec.ts │ │ │ │ ├── generator.ts │ │ │ │ ├── schema.d.ts │ │ │ │ └── schema.json │ │ ├── index.ts │ │ ├── nguniversal.ts │ │ ├── rspack │ │ │ ├── index.ts │ │ │ ├── plugin-script-module.ts │ │ │ └── with-federation.ts │ │ ├── schematics │ │ │ ├── boot-async │ │ │ │ ├── schema.d.ts │ │ │ │ ├── schema.json │ │ │ │ └── schematic.ts │ │ │ ├── init-rspack │ │ │ │ ├── files │ │ │ │ │ ├── federation.config.ts__tmpl__ │ │ │ │ │ └── rsbuild.config.ts__tmpl__ │ │ │ │ ├── prod-config.ts │ │ │ │ ├── schema.d.ts │ │ │ │ ├── schema.json │ │ │ │ └── schematic.ts │ │ │ ├── init-webpack │ │ │ │ ├── files │ │ │ │ │ └── webpack.config.js__tmpl__ │ │ │ │ ├── prod-config.ts │ │ │ │ ├── schema.d.ts │ │ │ │ ├── schema.json │ │ │ │ └── schematic.ts │ │ │ ├── init │ │ │ │ ├── schema.d.ts │ │ │ │ ├── schema.json │ │ │ │ └── schematic.ts │ │ │ ├── migrate-to-13 │ │ │ │ ├── schema.d.ts │ │ │ │ ├── schema.json │ │ │ │ └── schematic.ts │ │ │ ├── migrate-to-14-3 │ │ │ │ ├── schema.d.ts │ │ │ │ ├── schema.json │ │ │ │ └── schematic.ts │ │ │ ├── nguniversal │ │ │ │ ├── schema.d.ts │ │ │ │ ├── schema.json │ │ │ │ └── schematic.ts │ │ │ ├── patch │ │ │ │ └── schematic.ts │ │ │ └── remove │ │ │ │ ├── schema.d.ts │ │ │ │ ├── schema.json │ │ │ │ └── schematic.ts │ │ ├── server │ │ │ ├── colors.ts │ │ │ ├── index.ts │ │ │ ├── mf-dev-build-server.ts.bak │ │ │ ├── mf-dev-server.ts │ │ │ ├── task-queue.ts │ │ │ ├── tsconfig.json.bak │ │ │ └── workspace.ts │ │ ├── universal │ │ │ └── create-fetch.ts │ │ ├── utils │ │ │ ├── create-config.ts │ │ │ ├── decl.d.ts │ │ │ ├── modify-entry-plugin.ts │ │ │ ├── share-utils.ts │ │ │ ├── shared-mappings.ts │ │ │ ├── skip-list.ts │ │ │ ├── webpack.types.ts │ │ │ └── with-mf-plugin.ts │ │ └── webpack.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ ├── tsconfig.spec.json │ ├── tutorial │ │ ├── .vscode │ │ │ └── settings.json │ │ ├── braindump-ssr.md │ │ ├── mfe1.png │ │ ├── result.png │ │ ├── shell.png │ │ └── tutorial.md │ └── webpack.ts ├── native-federation-core │ ├── .eslintrc.json │ ├── LICENSE │ ├── README.md │ ├── build.ts │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── build.ts │ │ ├── config.ts │ │ ├── index.ts │ │ └── lib │ │ │ ├── config │ │ │ ├── configuration-context.ts │ │ │ ├── federation-config.ts │ │ │ ├── share-utils.ts │ │ │ └── with-native-federation.ts │ │ │ ├── core │ │ │ ├── build-adapter.d.ts │ │ │ ├── build-adapter.ts │ │ │ ├── build-for-federation.ts │ │ │ ├── bundle-exposed-and-mappings.ts │ │ │ ├── bundle-shared.ts │ │ │ ├── default-external-list.ts │ │ │ ├── default-server-deps-list.ts │ │ │ ├── default-skip-list.ts │ │ │ ├── federation-builder.ts │ │ │ ├── federation-options.ts │ │ │ ├── get-externals.ts │ │ │ ├── load-federation-config.ts │ │ │ ├── write-federation-info.ts │ │ │ └── write-import-map.ts │ │ │ └── utils │ │ │ ├── build-result-map.ts │ │ │ ├── build-utils.ts │ │ │ ├── copy-src-map-if-exists.ts │ │ │ ├── hash-file.ts │ │ │ ├── logger.d.ts │ │ │ ├── logger.js │ │ │ ├── logger.js.map │ │ │ ├── logger.ts │ │ │ ├── mapped-paths.d.ts │ │ │ ├── mapped-paths.js │ │ │ ├── mapped-paths.js.map │ │ │ ├── mapped-paths.ts │ │ │ ├── normalize.ts │ │ │ ├── package-info.ts │ │ │ └── resolve-glob.ts │ ├── stack.png │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── native-federation-esbuild │ ├── .eslintrc.json │ ├── LICENSE │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── index.ts │ │ └── lib │ │ │ ├── adapter.ts │ │ │ ├── collect-exports.ts │ │ │ └── react-replacements.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── native-federation-node │ ├── .eslintrc.json │ ├── LICENSE │ ├── README.md │ ├── build │ │ └── create-data-url.js │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ │ ├── index.ts │ │ └── lib │ │ │ ├── node │ │ │ └── init-node-federation.ts │ │ │ └── utils │ │ │ ├── import-map-loader.js │ │ │ └── loader-as-data-url.js │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── native-federation-runtime │ ├── .eslintrc.json │ ├── LICENSE │ ├── README.md │ ├── jest.config.ts │ ├── ng-package.json │ ├── package-lock.json │ ├── package.json │ ├── project.json │ ├── src │ │ ├── index.ts │ │ ├── lib │ │ │ ├── get-shared.ts │ │ │ ├── init-federation.ts │ │ │ ├── load-remote-module.ts │ │ │ ├── model │ │ │ │ ├── externals.ts │ │ │ │ ├── federation-info.ts │ │ │ │ ├── global-cache.ts │ │ │ │ ├── import-map.ts │ │ │ │ └── remotes.ts │ │ │ ├── test-setup.ts │ │ │ └── utils │ │ │ │ ├── add-import-map.ts │ │ │ │ └── path-utils.ts │ │ └── test-setup.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ ├── tsconfig.lib.prod.json │ └── tsconfig.spec.json ├── native-federation │ ├── .eslintrc.json │ ├── LICENSE │ ├── README.md │ ├── builders.json │ ├── collection.json │ ├── config.ts │ ├── demo-repo.png │ ├── docs │ │ ├── migrate.md │ │ ├── share-faq.md │ │ └── update18.md │ ├── example.png │ ├── executors.json │ ├── generators.json │ ├── jest.config.ts │ ├── migrate-appbuilder.md │ ├── migration-collection.json │ ├── package.json │ ├── post-build.js │ ├── project.json │ ├── src │ │ ├── builders │ │ │ ├── build │ │ │ │ ├── builder.ts │ │ │ │ ├── schema.d.ts │ │ │ │ └── schema.json │ │ │ └── serve │ │ │ │ ├── builder.ts.bak │ │ │ │ └── schema.json.bak │ │ ├── config.ts │ │ ├── executors │ │ │ └── build │ │ │ │ ├── executor.spec.ts │ │ │ │ ├── executor.ts │ │ │ │ ├── schema.d.ts │ │ │ │ └── schema.json │ │ ├── generators │ │ │ └── native-federation │ │ │ │ ├── files │ │ │ │ └── src │ │ │ │ │ └── index.ts__template__ │ │ │ │ ├── generator.spec.ts │ │ │ │ ├── generator.ts │ │ │ │ ├── schema.d.ts │ │ │ │ └── schema.json │ │ ├── index.ts │ │ ├── patch-angular-build.ts │ │ ├── plugin │ │ │ ├── dev-externals-mixin.ts │ │ │ ├── externals-skip-list.ts │ │ │ └── index.ts │ │ ├── schematics │ │ │ ├── appbuilder │ │ │ │ ├── schema.d.ts │ │ │ │ ├── schema.json │ │ │ │ └── schematic.ts │ │ │ ├── init │ │ │ │ ├── files │ │ │ │ │ └── federation.config.js__tmpl__ │ │ │ │ ├── schema.d.ts │ │ │ │ ├── schema.json │ │ │ │ └── schematic.ts │ │ │ ├── remove │ │ │ │ ├── schema.d.ts │ │ │ │ ├── schema.json │ │ │ │ └── schematic.ts │ │ │ └── update18 │ │ │ │ ├── schema.json │ │ │ │ └── schematic.ts │ │ └── utils │ │ │ ├── angular-esbuild-adapter.ts │ │ │ ├── angular-locales.ts │ │ │ ├── create-compiler-options.ts │ │ │ ├── event-sorce.ts │ │ │ ├── i18n.ts │ │ │ ├── mem-resuts.ts │ │ │ ├── patch-angular-build.ts │ │ │ ├── rebuild-events.ts │ │ │ ├── rollup.ts.bak │ │ │ ├── rollup.ts.bak.bak │ │ │ ├── shared-mappings-plugin.ts │ │ │ └── updateIndexHtml.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json └── playground-lib │ ├── .eslintrc.json │ ├── README.md │ ├── jest.config.ts │ ├── project.json │ ├── src │ ├── index.ts │ ├── lib │ │ ├── auth.component.ts │ │ ├── auth.service.ts │ │ └── playground-lib.module.ts │ └── test-setup.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── migration-guide-13.md ├── migration-guide-14.md ├── migration-guide.md ├── nx.json ├── package-lock.json ├── package.json ├── project.json ├── serve.js ├── tools └── scripts │ ├── publish-utils.mjs │ ├── publish.mjs │ ├── start-local-registry.ts │ └── stop-local-registry.ts ├── tsconfig.base.json ├── update-local-mf.bat └── update-local-nf.sh /.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 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.eslintrc.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "ignorePatterns": ["**/*"], 4 | "plugins": ["@nx"], 5 | "overrides": [ 6 | { 7 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 8 | "rules": { 9 | "@typescript-eslint/no-explicit-any": "warn", 10 | "@nx/enforce-module-boundaries": [ 11 | "error", 12 | { 13 | "enforceBuildableLibDependency": true, 14 | "allow": [], 15 | "depConstraints": [ 16 | { 17 | "sourceTag": "*", 18 | "onlyDependOnLibsWithTags": ["*"] 19 | } 20 | ] 21 | } 22 | ] 23 | } 24 | }, 25 | { 26 | "files": ["*.ts", "*.tsx"], 27 | "extends": ["plugin:@nx/typescript"], 28 | "rules": { "@typescript-eslint/no-explicit-any": "warn" } 29 | }, 30 | { 31 | "files": ["*.js", "*.jsx"], 32 | "extends": ["plugin:@nx/javascript"], 33 | "rules": {} 34 | }, 35 | { 36 | "files": ["*.spec.ts", "*.spec.tsx", "*.spec.js", "*.spec.jsx"], 37 | "env": { 38 | "jest": true 39 | }, 40 | "rules": {} 41 | }, 42 | { 43 | "files": "*.json", 44 | "parser": "jsonc-eslint-parser", 45 | "rules": {} 46 | } 47 | ] 48 | } 49 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignorePatterns": ["**/*"], 3 | "overrides": [ 4 | { 5 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 6 | "rules": { 7 | "@nx/enforce-module-boundaries": [ 8 | "error", 9 | { 10 | "enforceBuildableLibDependency": true, 11 | "allow": [], 12 | "depConstraints": [ 13 | { 14 | "sourceTag": "*", 15 | "onlyDependOnLibsWithTags": ["*"] 16 | } 17 | ] 18 | } 19 | ] 20 | } 21 | }, 22 | { 23 | "files": ["*.ts", "*.tsx"], 24 | "rules": {} 25 | }, 26 | { 27 | "files": ["*.js", "*.jsx"], 28 | "rules": {} 29 | }, 30 | { 31 | "files": ["*.spec.ts", "*.spec.tsx", "*.spec.js", "*.spec.jsx"], 32 | "env": { 33 | "jest": true 34 | }, 35 | "rules": {} 36 | }, 37 | { 38 | "files": "*.json", 39 | "parser": "jsonc-eslint-parser", 40 | "rules": {} 41 | }, 42 | { 43 | "files": ["*.ts"], 44 | "rules": { 45 | "@angular-eslint/prefer-standalone": "off" 46 | } 47 | } 48 | ], 49 | "extends": ["./.eslintrc.base.json"] 50 | } 51 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Submit a Request For Consideration 3 | 4 | body: 5 | - type: dropdown 6 | id: affected-packages 7 | attributes: 8 | label: For which library do you have a feature request? 9 | options: 10 | - native-federation 11 | - module-federation 12 | - other 13 | multiple: true 14 | validations: 15 | required: true 16 | 17 | - type: textarea 18 | id: information 19 | attributes: 20 | label: Information 21 | description: What feature would you like to see added? 22 | validations: 23 | required: true 24 | 25 | - type: textarea 26 | id: alternatives 27 | attributes: 28 | label: Describe any alternatives/workarounds you're currently using 29 | 30 | - type: checkboxes 31 | id: assistance 32 | attributes: 33 | label: I would be willing to submit a PR to fix this issue 34 | description: Assistance is provided if you need help submitting a pull request 35 | options: 36 | - label: 'Yes' 37 | - label: 'No' 38 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.yml: -------------------------------------------------------------------------------- 1 | name: Question / Help 2 | description: Ask a question or request help 3 | 4 | body: 5 | - type: dropdown 6 | id: affected-packages 7 | attributes: 8 | label: For which library do you need help? 9 | options: 10 | - native-federation 11 | - module-federation 12 | - other 13 | multiple: true 14 | validations: 15 | required: true 16 | 17 | - type: textarea 18 | id: information 19 | attributes: 20 | label: Question 21 | description: What do you need help with? 22 | validations: 23 | required: true 24 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | permissions: 10 | actions: read 11 | contents: read 12 | 13 | jobs: 14 | main: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 20 | 21 | # Connect your workspace on nx.app and uncomment this to enable task distribution. 22 | # The "--stop-agents-after" is optional, but allows idle agents to shut down once the "build" targets have been requested 23 | # - run: npx nx-cloud start-ci-run --distribute-on="5 linux-medium-js" --stop-agents-after="build" 24 | 25 | # Cache node_modules 26 | - uses: actions/setup-node@v3 27 | with: 28 | node-version: 20 29 | cache: 'npm' 30 | - run: npm ci 31 | - uses: nrwl/nx-set-shas@v4 32 | 33 | - run: npx nx format:check 34 | #TODO: remove exclude when apps are fixed 35 | - run: npx nx affected -t lint test build --exclude mfe1 mfe2 playground 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | dist 5 | tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | yarn-error.log 34 | testem.log 35 | /typings 36 | 37 | # System Files 38 | .DS_Store 39 | Thumbs.db 40 | 41 | # Nx 42 | .nx/cache 43 | .nx 44 | migrations.json 45 | 46 | # Angular 47 | .angular 48 | 49 | .nx 50 | .cursor/rules/nx-rules.mdc 51 | .github/instructions/nx.instructions.md 52 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Add files here to ignore them from prettier formatting 2 | 3 | /dist 4 | /coverage 5 | /.nx/cache 6 | .angular 7 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /.verdaccio/config.yml: -------------------------------------------------------------------------------- 1 | # path to a directory with all packages 2 | storage: ../tmp/local-registry/storage 3 | 4 | # a list of other known repositories we can talk to 5 | uplinks: 6 | npmjs: 7 | url: https://registry.npmjs.org/ 8 | maxage: 60m 9 | 10 | packages: 11 | '**': 12 | # give all users (including non-authenticated users) full access 13 | # because it is a local registry 14 | access: $all 15 | publish: $all 16 | unpublish: $all 17 | 18 | # if package is not available locally, proxy requests to npm registry 19 | proxy: npmjs 20 | 21 | # log settings 22 | logs: 23 | type: stdout 24 | format: pretty 25 | level: warn 26 | 27 | publish: 28 | allow_offline: true # set offline to true to allow publish offline 29 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "angular.ng-template", 4 | "nrwl.angular-console", 5 | "esbenp.prettier-vscode", 6 | "firsttris.vscode-jest-runner" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "spellright.language": ["en"], 3 | "spellright.documentTypes": ["markdown", "latex", "plaintext"], 4 | "workbench.colorCustomizations": { 5 | "activityBar.activeBackground": "#ab307e", 6 | "activityBar.activeBorder": "#25320e", 7 | "activityBar.background": "#ab307e", 8 | "activityBar.foreground": "#e7e7e7", 9 | "activityBar.inactiveForeground": "#e7e7e799", 10 | "activityBarBadge.background": "#25320e", 11 | "activityBarBadge.foreground": "#e7e7e7", 12 | "statusBar.background": "#832561", 13 | "statusBar.foreground": "#e7e7e7", 14 | "statusBarItem.hoverBackground": "#ab307e", 15 | "titleBar.activeBackground": "#832561", 16 | "titleBar.activeForeground": "#e7e7e7", 17 | "titleBar.inactiveBackground": "#83256199", 18 | "titleBar.inactiveForeground": "#e7e7e799", 19 | "sash.hoverBorder": "#ab307e", 20 | "statusBarItem.remoteBackground": "#832561", 21 | "statusBarItem.remoteForeground": "#e7e7e7", 22 | "commandCenter.border": "#e7e7e799" 23 | }, 24 | "peacock.color": "#832561", 25 | "eslint.validate": ["json"], 26 | "files.exclude": { 27 | "**/.git": true, 28 | "**/.svn": true, 29 | "**/.hg": true, 30 | "**/CVS": true, 31 | "**/.DS_Store": true, 32 | "**/Thumbs.db": true 33 | }, 34 | "hide-files.files": [] 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Softarc Consulting GmbH 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /apps/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-architects/module-federation-plugin/31c8117df81fe7e8be388839a92cf369bd47eed9/apps/.gitkeep -------------------------------------------------------------------------------- /apps/mfe1-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/mfe1-e2e/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileServerFolder": ".", 3 | "fixturesFolder": "./src/fixtures", 4 | "integrationFolder": "./src/integration", 5 | "modifyObstructiveCode": false, 6 | "supportFile": "./src/support/index.ts", 7 | "pluginsFile": "./src/plugins/index", 8 | "video": true, 9 | "videosFolder": "../../dist/cypress/apps/mfe1-e2e/videos", 10 | "screenshotsFolder": "../../dist/cypress/apps/mfe1-e2e/screenshots", 11 | "chromeWebSecurity": false 12 | } 13 | -------------------------------------------------------------------------------- /apps/mfe1-e2e/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mfe1-e2e", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "apps/mfe1-e2e/src", 5 | "projectType": "application", 6 | "targets": { 7 | "e2e": { 8 | "executor": "@nx/cypress:cypress", 9 | "options": { 10 | "cypressConfig": "apps/mfe1-e2e/cypress.json", 11 | "devServerTarget": "mfe1:serve:development", 12 | "testingType": "e2e" 13 | }, 14 | "configurations": { 15 | "production": { 16 | "devServerTarget": "mfe1:serve:production" 17 | } 18 | } 19 | }, 20 | "lint": { 21 | "executor": "@nx/eslint:lint", 22 | "outputs": ["{options.outputFile}"], 23 | "options": { 24 | "lintFilePatterns": ["apps/mfe1-e2e/**/*.{js,ts}"] 25 | } 26 | } 27 | }, 28 | "tags": [], 29 | "implicitDependencies": ["mfe1"] 30 | } 31 | -------------------------------------------------------------------------------- /apps/mfe1-e2e/src/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io" 4 | } 5 | -------------------------------------------------------------------------------- /apps/mfe1-e2e/src/integration/app.spec.ts: -------------------------------------------------------------------------------- 1 | import { getGreeting } from '../support/app.po'; 2 | 3 | describe('mfe1', () => { 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 mfe1'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /apps/mfe1-e2e/src/plugins/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example plugins/index.js can be used to load plugins 3 | // 4 | // You can change the location of this file or turn off loading 5 | // the plugins file with the 'pluginsFile' configuration option. 6 | // 7 | // You can read more here: 8 | // https://on.cypress.io/plugins-guide 9 | // *********************************************************** 10 | 11 | // This function is called when a project is opened or re-opened (e.g. due to 12 | // the project's config changing) 13 | 14 | const { preprocessTypescript } = require('@nx/cypress/plugins/preprocessor'); 15 | 16 | module.exports = (on, config) => { 17 | // `on` is used to hook into various events Cypress emits 18 | // `config` is the resolved Cypress config 19 | 20 | // Preprocess Typescript file using Nx helper 21 | on('file:preprocessor', preprocessTypescript(config)); 22 | }; 23 | -------------------------------------------------------------------------------- /apps/mfe1-e2e/src/support/app.po.ts: -------------------------------------------------------------------------------- 1 | export const getGreeting = () => cy.get('h1'); 2 | -------------------------------------------------------------------------------- /apps/mfe1-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/mfe1-e2e/src/support/index.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.ts 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.ts using ES2015 syntax: 17 | import './commands'; 18 | -------------------------------------------------------------------------------- /apps/mfe1-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"], 16 | "angularCompilerOptions": { 17 | "enableI18nLegacyMessageIdFormat": false, 18 | "strictInjectionParameters": true, 19 | "strictInputAccessModifiers": true, 20 | "strictTemplates": true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /apps/mfe1/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "extends": [ 8 | "plugin:@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": "angularArchitects", 17 | "style": "camelCase" 18 | } 19 | ], 20 | "@angular-eslint/component-selector": [ 21 | "error", 22 | { 23 | "type": "element", 24 | "prefix": "angular-architects", 25 | "style": "kebab-case" 26 | } 27 | ], 28 | "@angular-eslint/prefer-standalone": "off" 29 | } 30 | }, 31 | { 32 | "files": ["*.html"], 33 | "extends": ["plugin:@nx/angular-template"], 34 | "rules": {} 35 | } 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /apps/mfe1/federation.config.js: -------------------------------------------------------------------------------- 1 | const { 2 | withNativeFederation, 3 | shareAll, 4 | } = require('@angular-architects/native-federation/config'); 5 | 6 | module.exports = withNativeFederation({ 7 | name: 'mfe1', 8 | 9 | exposes: { 10 | './cmp': 'apps/mfe1/src/app/demo/demo.component.ts', 11 | }, 12 | 13 | shared: { 14 | ...shareAll({ 15 | singleton: true, 16 | strictVersion: true, 17 | requiredVersion: 'auto', 18 | }), 19 | }, 20 | 21 | sharedMappings: ['@angular-architects/playground-lib'], 22 | }); 23 | -------------------------------------------------------------------------------- /apps/mfe1/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'mfe1', 4 | preset: '../../jest.preset.js', 5 | setupFilesAfterEnv: ['/src/test-setup.ts'], 6 | globals: {}, 7 | coverageDirectory: '../../coverage/apps/mfe1', 8 | transform: { 9 | '^.+\\.(ts|mjs|js|html)$': [ 10 | 'jest-preset-angular', 11 | { 12 | tsconfig: '/tsconfig.spec.json', 13 | stringifyContentPathRegex: '\\.(html|svg)$', 14 | }, 15 | ], 16 | }, 17 | transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], 18 | snapshotSerializers: [ 19 | 'jest-preset-angular/build/serializers/no-ng-attributes', 20 | 'jest-preset-angular/build/serializers/ng-snapshot', 21 | 'jest-preset-angular/build/serializers/html-comment', 22 | ], 23 | }; 24 | -------------------------------------------------------------------------------- /apps/mfe1/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-architects/module-federation-plugin/31c8117df81fe7e8be388839a92cf369bd47eed9/apps/mfe1/src/app/app.component.css -------------------------------------------------------------------------------- /apps/mfe1/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /apps/mfe1/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | import { NxWelcomeComponent } from './nx-welcome.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async () => { 7 | await TestBed.configureTestingModule({ 8 | declarations: [AppComponent, NxWelcomeComponent], 9 | }).compileComponents(); 10 | }); 11 | 12 | it('should create the app', () => { 13 | const fixture = TestBed.createComponent(AppComponent); 14 | const app = fixture.componentInstance; 15 | expect(app).toBeTruthy(); 16 | }); 17 | 18 | it(`should have as title 'mfe1'`, () => { 19 | const fixture = TestBed.createComponent(AppComponent); 20 | const app = fixture.componentInstance; 21 | expect(app.title).toEqual('mfe1'); 22 | }); 23 | 24 | it('should render title', () => { 25 | const fixture = TestBed.createComponent(AppComponent); 26 | fixture.detectChanges(); 27 | const compiled = fixture.nativeElement as HTMLElement; 28 | expect(compiled.querySelector('h1')?.textContent).toContain('Welcome mfe1'); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /apps/mfe1/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'angular-architects-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'], 7 | }) 8 | export class AppComponent { 9 | title = 'mfe1'; 10 | } 11 | -------------------------------------------------------------------------------- /apps/mfe1/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | 4 | import { AppComponent } from './app.component'; 5 | import { DemoComponent } from './demo/demo.component'; 6 | import { NxWelcomeComponent } from './nx-welcome.component'; 7 | 8 | @NgModule({ 9 | declarations: [AppComponent, NxWelcomeComponent], 10 | imports: [BrowserModule, DemoComponent], 11 | providers: [], 12 | bootstrap: [AppComponent], 13 | }) 14 | export class AppModule {} 15 | -------------------------------------------------------------------------------- /apps/mfe1/src/app/demo/demo.component.css: -------------------------------------------------------------------------------- 1 | p { 2 | color: green; 3 | } 4 | -------------------------------------------------------------------------------- /apps/mfe1/src/app/demo/demo.component.html: -------------------------------------------------------------------------------- 1 |

demo works!

2 | 3 |
{{ title }}
4 | 5 |
6 | 7 | 8 | -------------------------------------------------------------------------------- /apps/mfe1/src/app/demo/demo.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DemoComponent } from './demo.component'; 4 | 5 | describe('DemoComponent', () => { 6 | let component: DemoComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({}).compileComponents(); 11 | 12 | fixture = TestBed.createComponent(DemoComponent); 13 | component = fixture.componentInstance; 14 | fixture.detectChanges(); 15 | }); 16 | 17 | it('should create', () => { 18 | expect(component).toBeTruthy(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /apps/mfe1/src/app/demo/demo.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AuthService, 3 | PlaygroundLibModule, 4 | } from '@angular-architects/playground-lib'; 5 | import { CommonModule } from '@angular/common'; 6 | import { Component } from '@angular/core'; 7 | 8 | @Component({ 9 | standalone: true, 10 | selector: 'angular-architects-demo', 11 | templateUrl: './demo.component.html', 12 | styleUrls: ['./demo.component.css'], 13 | imports: [CommonModule, PlaygroundLibModule], 14 | }) 15 | export class DemoComponent { 16 | title = 'Hallo'; 17 | 18 | constructor(authService: AuthService) { 19 | console.log('userName', authService.userName); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /apps/mfe1/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-architects/module-federation-plugin/31c8117df81fe7e8be388839a92cf369bd47eed9/apps/mfe1/src/assets/.gitkeep -------------------------------------------------------------------------------- /apps/mfe1/src/bootstrap.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic() 12 | .bootstrapModule(AppModule) 13 | .catch((err) => console.error(err)); 14 | -------------------------------------------------------------------------------- /apps/mfe1/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | }; 4 | -------------------------------------------------------------------------------- /apps/mfe1/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/mfe1/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-architects/module-federation-plugin/31c8117df81fe7e8be388839a92cf369bd47eed9/apps/mfe1/src/favicon.ico -------------------------------------------------------------------------------- /apps/mfe1/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mfe1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/mfe1/src/main.ts: -------------------------------------------------------------------------------- 1 | import { initFederation } from '@angular-architects/native-federation'; 2 | 3 | initFederation() 4 | .then(() => import('./bootstrap')) 5 | .catch((err) => console.error(err)); 6 | -------------------------------------------------------------------------------- /apps/mfe1/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /apps/mfe1/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | -------------------------------------------------------------------------------- /apps/mfe1/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": [] 6 | }, 7 | "files": ["src/main.ts", "src/polyfills.ts"], 8 | "include": ["src/**/*.d.ts"], 9 | "exclude": ["**/*.test.ts", "**/*.spec.ts", "jest.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /apps/mfe1/tsconfig.editor.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["**/*.ts"], 4 | "compilerOptions": { 5 | "types": ["jest", "node"] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /apps/mfe1/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/mfe1/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/mfe2-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/mfe2-e2e/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileServerFolder": ".", 3 | "fixturesFolder": "./src/fixtures", 4 | "integrationFolder": "./src/integration", 5 | "modifyObstructiveCode": false, 6 | "supportFile": "./src/support/index.ts", 7 | "pluginsFile": "./src/plugins/index", 8 | "video": true, 9 | "videosFolder": "../../dist/cypress/apps/mfe2-e2e/videos", 10 | "screenshotsFolder": "../../dist/cypress/apps/mfe2-e2e/screenshots", 11 | "chromeWebSecurity": false 12 | } 13 | -------------------------------------------------------------------------------- /apps/mfe2-e2e/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mfe2-e2e", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "apps/mfe2-e2e/src", 5 | "projectType": "application", 6 | "targets": { 7 | "e2e": { 8 | "executor": "@nx/cypress:cypress", 9 | "options": { 10 | "cypressConfig": "apps/mfe2-e2e/cypress.json", 11 | "devServerTarget": "mfe2:serve:development", 12 | "testingType": "e2e" 13 | }, 14 | "configurations": { 15 | "production": { 16 | "devServerTarget": "mfe2:serve:production" 17 | } 18 | } 19 | }, 20 | "lint": { 21 | "executor": "@nx/eslint:lint", 22 | "outputs": ["{options.outputFile}"], 23 | "options": { 24 | "lintFilePatterns": ["apps/mfe2-e2e/**/*.{js,ts}"] 25 | } 26 | } 27 | }, 28 | "tags": [], 29 | "implicitDependencies": ["mfe2"] 30 | } 31 | -------------------------------------------------------------------------------- /apps/mfe2-e2e/src/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io" 4 | } 5 | -------------------------------------------------------------------------------- /apps/mfe2-e2e/src/integration/app.spec.ts: -------------------------------------------------------------------------------- 1 | import { getGreeting } from '../support/app.po'; 2 | 3 | describe('mfe2', () => { 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 mfe2'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /apps/mfe2-e2e/src/plugins/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example plugins/index.js can be used to load plugins 3 | // 4 | // You can change the location of this file or turn off loading 5 | // the plugins file with the 'pluginsFile' configuration option. 6 | // 7 | // You can read more here: 8 | // https://on.cypress.io/plugins-guide 9 | // *********************************************************** 10 | 11 | // This function is called when a project is opened or re-opened (e.g. due to 12 | // the project's config changing) 13 | 14 | const { preprocessTypescript } = require('@nx/cypress/plugins/preprocessor'); 15 | 16 | module.exports = (on, config) => { 17 | // `on` is used to hook into various events Cypress emits 18 | // `config` is the resolved Cypress config 19 | 20 | // Preprocess Typescript file using Nx helper 21 | on('file:preprocessor', preprocessTypescript(config)); 22 | }; 23 | -------------------------------------------------------------------------------- /apps/mfe2-e2e/src/support/app.po.ts: -------------------------------------------------------------------------------- 1 | export const getGreeting = () => cy.get('h1'); 2 | -------------------------------------------------------------------------------- /apps/mfe2-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/mfe2-e2e/src/support/index.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.ts 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.ts using ES2015 syntax: 17 | import './commands'; 18 | -------------------------------------------------------------------------------- /apps/mfe2-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"], 16 | "angularCompilerOptions": { 17 | "enableI18nLegacyMessageIdFormat": false, 18 | "strictInjectionParameters": true, 19 | "strictInputAccessModifiers": true, 20 | "strictTemplates": true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /apps/mfe2/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "extends": [ 8 | "plugin:@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": "angularArchitects", 17 | "style": "camelCase" 18 | } 19 | ], 20 | "@angular-eslint/component-selector": [ 21 | "error", 22 | { 23 | "type": "element", 24 | "prefix": "angular-architects", 25 | "style": "kebab-case" 26 | } 27 | ], 28 | "@angular-eslint/prefer-standalone": "off" 29 | } 30 | }, 31 | { 32 | "files": ["*.html"], 33 | "extends": ["plugin:@nx/angular-template"], 34 | "rules": {} 35 | } 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /apps/mfe2/federation.config.js: -------------------------------------------------------------------------------- 1 | const { 2 | withNativeFederation, 3 | shareAll, 4 | } = require('@angular-architects/native-federation/config'); 5 | 6 | module.exports = withNativeFederation({ 7 | shared: { 8 | ...shareAll({ 9 | singleton: true, 10 | strictVersion: true, 11 | requiredVersion: 'auto', 12 | }), 13 | }, 14 | }); 15 | -------------------------------------------------------------------------------- /apps/mfe2/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'mfe2', 4 | preset: '../../jest.preset.js', 5 | setupFilesAfterEnv: ['/src/test-setup.ts'], 6 | globals: {}, 7 | coverageDirectory: '../../coverage/apps/mfe2', 8 | transform: { 9 | '^.+\\.(ts|mjs|js|html)$': [ 10 | 'jest-preset-angular', 11 | { 12 | tsconfig: '/tsconfig.spec.json', 13 | stringifyContentPathRegex: '\\.(html|svg)$', 14 | }, 15 | ], 16 | }, 17 | transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], 18 | snapshotSerializers: [ 19 | 'jest-preset-angular/build/serializers/no-ng-attributes', 20 | 'jest-preset-angular/build/serializers/ng-snapshot', 21 | 'jest-preset-angular/build/serializers/html-comment', 22 | ], 23 | }; 24 | -------------------------------------------------------------------------------- /apps/mfe2/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-architects/module-federation-plugin/31c8117df81fe7e8be388839a92cf369bd47eed9/apps/mfe2/src/app/app.component.css -------------------------------------------------------------------------------- /apps/mfe2/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /apps/mfe2/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | import { NxWelcomeComponent } from './nx-welcome.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async () => { 7 | await TestBed.configureTestingModule({ 8 | declarations: [AppComponent, NxWelcomeComponent], 9 | }).compileComponents(); 10 | }); 11 | 12 | it('should create the app', () => { 13 | const fixture = TestBed.createComponent(AppComponent); 14 | const app = fixture.componentInstance; 15 | expect(app).toBeTruthy(); 16 | }); 17 | 18 | it(`should have as title 'mfe2'`, () => { 19 | const fixture = TestBed.createComponent(AppComponent); 20 | const app = fixture.componentInstance; 21 | expect(app.title).toEqual('mfe2'); 22 | }); 23 | 24 | it('should render title', () => { 25 | const fixture = TestBed.createComponent(AppComponent); 26 | fixture.detectChanges(); 27 | const compiled = fixture.nativeElement as HTMLElement; 28 | expect(compiled.querySelector('h1')?.textContent).toContain('Welcome mfe2'); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /apps/mfe2/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'angular-architects-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'], 7 | }) 8 | export class AppComponent { 9 | title = 'mfe2'; 10 | } 11 | -------------------------------------------------------------------------------- /apps/mfe2/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | 4 | import { AppComponent } from './app.component'; 5 | import { NxWelcomeComponent } from './nx-welcome.component'; 6 | 7 | @NgModule({ 8 | declarations: [AppComponent, NxWelcomeComponent], 9 | imports: [BrowserModule], 10 | providers: [], 11 | bootstrap: [AppComponent], 12 | }) 13 | export class AppModule {} 14 | -------------------------------------------------------------------------------- /apps/mfe2/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-architects/module-federation-plugin/31c8117df81fe7e8be388839a92cf369bd47eed9/apps/mfe2/src/assets/.gitkeep -------------------------------------------------------------------------------- /apps/mfe2/src/assets/federation.manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "mfe1": "http://localhost:4200/remoteEntry.json", 3 | "playground": "http://localhost:4200/remoteEntry.json" 4 | } 5 | -------------------------------------------------------------------------------- /apps/mfe2/src/bootstrap.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic() 12 | .bootstrapModule(AppModule) 13 | .catch((err) => console.error(err)); 14 | -------------------------------------------------------------------------------- /apps/mfe2/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | }; 4 | -------------------------------------------------------------------------------- /apps/mfe2/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/mfe2/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-architects/module-federation-plugin/31c8117df81fe7e8be388839a92cf369bd47eed9/apps/mfe2/src/favicon.ico -------------------------------------------------------------------------------- /apps/mfe2/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mfe2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/mfe2/src/main.ts: -------------------------------------------------------------------------------- 1 | import { initFederation } from '@angular-architects/native-federation'; 2 | 3 | initFederation('/assets/federation.manifest.json') 4 | .catch((err) => console.error(err)) 5 | .then(() => import('./bootstrap')) 6 | .catch((err) => console.error(err)); 7 | -------------------------------------------------------------------------------- /apps/mfe2/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /apps/mfe2/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | -------------------------------------------------------------------------------- /apps/mfe2/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": [] 6 | }, 7 | "files": ["src/main.ts", "src/polyfills.ts"], 8 | "include": ["src/**/*.d.ts"], 9 | "exclude": ["**/*.test.ts", "**/*.spec.ts", "jest.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /apps/mfe2/tsconfig.editor.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["**/*.ts"], 4 | "compilerOptions": { 5 | "types": ["jest", "node"] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /apps/mfe2/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/mfe2/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/native-federation-e2e/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.base.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /apps/native-federation-e2e/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'native-federation-e2e', 4 | preset: '../../jest.preset.js', 5 | transform: { 6 | '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], 7 | }, 8 | moduleFileExtensions: ['ts', 'js', 'html'], 9 | coverageDirectory: '../../coverage/apps/native-federation-e2e', 10 | }; 11 | -------------------------------------------------------------------------------- /apps/native-federation-e2e/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "native-federation-e2e", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "projectType": "application", 5 | "sourceRoot": "apps/native-federation-e2e/src", 6 | "targets": { 7 | "e2e": { 8 | "executor": "@nx/jest:jest", 9 | "options": { 10 | "jestConfig": "apps/native-federation-e2e/jest.config.ts", 11 | "runInBand": true, 12 | "passWithNoTests": false 13 | }, 14 | "dependsOn": ["native-federation:build"] 15 | }, 16 | "test": { 17 | "command": "echo Noop" 18 | } 19 | }, 20 | "tags": [], 21 | "implicitDependencies": ["native-federation"] 22 | } 23 | -------------------------------------------------------------------------------- /apps/native-federation-e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.spec.json" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /apps/native-federation-e2e/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "src/**/*.test.ts", 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /apps/playground-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/playground-e2e/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileServerFolder": ".", 3 | "fixturesFolder": "./src/fixtures", 4 | "integrationFolder": "./src/integration", 5 | "modifyObstructiveCode": false, 6 | "pluginsFile": "./src/plugins/index", 7 | "supportFile": "./src/support/index.ts", 8 | "video": true, 9 | "videosFolder": "../../dist/cypress/apps/playground-e2e/videos", 10 | "screenshotsFolder": "../../dist/cypress/apps/playground-e2e/screenshots", 11 | "chromeWebSecurity": false 12 | } 13 | -------------------------------------------------------------------------------- /apps/playground-e2e/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "playground-e2e", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "apps/playground-e2e/src", 5 | "projectType": "application", 6 | "targets": { 7 | "e2e": { 8 | "executor": "@nx/cypress:cypress", 9 | "options": { 10 | "cypressConfig": "apps/playground-e2e/cypress.json", 11 | "tsConfig": "apps/playground-e2e/tsconfig.e2e.json", 12 | "devServerTarget": "playground:serve:development" 13 | }, 14 | "configurations": { 15 | "production": { 16 | "devServerTarget": "playground:serve:production" 17 | } 18 | } 19 | }, 20 | "lint": { 21 | "executor": "@nx/eslint:lint", 22 | "options": { 23 | "lintFilePatterns": ["apps/playground-e2e/**/*.{js,ts}"] 24 | }, 25 | "outputs": ["{options.outputFile}"] 26 | } 27 | }, 28 | "tags": [], 29 | "implicitDependencies": ["playground"] 30 | } 31 | -------------------------------------------------------------------------------- /apps/playground-e2e/src/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io" 4 | } 5 | -------------------------------------------------------------------------------- /apps/playground-e2e/src/integration/app.spec.ts: -------------------------------------------------------------------------------- 1 | import { getGreeting } from '../support/app.po'; 2 | 3 | describe('playground', () => { 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('Hello Native Federation!'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /apps/playground-e2e/src/plugins/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example plugins/index.js can be used to load plugins 3 | // 4 | // You can change the location of this file or turn off loading 5 | // the plugins file with the 'pluginsFile' configuration option. 6 | // 7 | // You can read more here: 8 | // https://on.cypress.io/plugins-guide 9 | // *********************************************************** 10 | 11 | // This function is called when a project is opened or re-opened (e.g. due to 12 | // the project's config changing) 13 | 14 | const { preprocessTypescript } = require('@nx/cypress/plugins/preprocessor'); 15 | 16 | module.exports = (on, config) => { 17 | // `on` is used to hook into various events Cypress emits 18 | // `config` is the resolved Cypress config 19 | 20 | // Preprocess Typescript file using Nx helper 21 | on('file:preprocessor', preprocessTypescript(config)); 22 | }; 23 | -------------------------------------------------------------------------------- /apps/playground-e2e/src/support/app.po.ts: -------------------------------------------------------------------------------- 1 | export const getGreeting = () => cy.get('h1'); 2 | -------------------------------------------------------------------------------- /apps/playground-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/playground-e2e/src/support/index.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands'; 18 | -------------------------------------------------------------------------------- /apps/playground-e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "sourceMap": false, 5 | "outDir": "../../dist/out-tsc", 6 | "allowJs": true, 7 | "types": ["cypress", "node"] 8 | }, 9 | "include": ["src/**/*.ts", "src/**/*.js"] 10 | } 11 | -------------------------------------------------------------------------------- /apps/playground-e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.e2e.json" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /apps/playground/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "extends": [ 8 | "plugin:@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": "angularArchitects", 17 | "style": "camelCase" 18 | } 19 | ], 20 | "@angular-eslint/component-selector": [ 21 | "error", 22 | { 23 | "type": "element", 24 | "prefix": "angular-architects", 25 | "style": "kebab-case" 26 | } 27 | ], 28 | "@angular-eslint/prefer-standalone": "off" 29 | } 30 | }, 31 | { 32 | "files": ["*.html"], 33 | "extends": ["plugin:@nx/angular-template"], 34 | "rules": {} 35 | } 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /apps/playground/federation.config.js: -------------------------------------------------------------------------------- 1 | const { 2 | withNativeFederation, 3 | shareAll, 4 | } = require('@angular-architects/native-federation/config'); 5 | 6 | module.exports = withNativeFederation({ 7 | shared: { 8 | ...shareAll({ 9 | singleton: true, 10 | strictVersion: true, 11 | requiredVersion: 'auto', 12 | }), 13 | }, 14 | 15 | sharedMappings: ['@angular-architects/playground-lib'], 16 | }); 17 | -------------------------------------------------------------------------------- /apps/playground/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'playground', 4 | preset: '../../jest.preset.js', 5 | setupFilesAfterEnv: ['/src/test-setup.ts'], 6 | globals: {}, 7 | coverageDirectory: '../../coverage/apps/playground', 8 | snapshotSerializers: [ 9 | 'jest-preset-angular/build/serializers/no-ng-attributes', 10 | 'jest-preset-angular/build/serializers/ng-snapshot', 11 | 'jest-preset-angular/build/serializers/html-comment', 12 | ], 13 | transform: { 14 | '^.+.(ts|mjs|js|html)$': [ 15 | 'jest-preset-angular', 16 | { 17 | tsconfig: '/tsconfig.spec.json', 18 | stringifyContentPathRegex: '\\.(html|svg)$', 19 | }, 20 | ], 21 | }, 22 | transformIgnorePatterns: ['node_modules/(?!.*.mjs$)'], 23 | }; 24 | -------------------------------------------------------------------------------- /apps/playground/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |

Hello Native Federation!

2 | 3 |
4 | 5 |
6 | 7 |
8 |
9 |
10 | -------------------------------------------------------------------------------- /apps/playground/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | 4 | describe('AppComponent', () => { 5 | beforeEach(async () => { 6 | await TestBed.configureTestingModule({ 7 | declarations: [AppComponent], 8 | }).compileComponents(); 9 | }); 10 | 11 | it('should create the app', () => { 12 | const fixture = TestBed.createComponent(AppComponent); 13 | const app = fixture.componentInstance; 14 | expect(app).toBeTruthy(); 15 | }); 16 | 17 | it(`should have as title 'playground'`, () => { 18 | const fixture = TestBed.createComponent(AppComponent); 19 | const app = fixture.componentInstance; 20 | expect(app.title).toEqual('playground'); 21 | }); 22 | 23 | it('should render title', () => { 24 | const fixture = TestBed.createComponent(AppComponent); 25 | fixture.detectChanges(); 26 | const compiled = fixture.nativeElement; 27 | expect(compiled.querySelector('h1').textContent).toContain( 28 | 'Hello Native Federation!' 29 | ); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /apps/playground/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { loadRemoteModule } from '@angular-architects/native-federation'; 2 | import { AuthService } from '@angular-architects/playground-lib'; 3 | import { Component, Type } from '@angular/core'; 4 | 5 | @Component({ 6 | selector: 'angular-architects-root', 7 | templateUrl: './app.component.html', 8 | styleUrls: ['./app.component.css'], 9 | }) 10 | export class AppComponent { 11 | title = 'playground'; 12 | Cmp: Type; 13 | 14 | constructor(authService: AuthService) { 15 | authService.userName = 'Jane Doe'; 16 | } 17 | 18 | async load() { 19 | // const m = await importShim('http://localhost:3001/cmp.js'); 20 | 21 | const m = await loadRemoteModule({ 22 | remoteEntry: 'http://localhost:3001/remoteEntry.json', 23 | // remoteName: 'mfe1', 24 | exposedModule: './cmp', 25 | }); 26 | 27 | this.Cmp = m.DemoComponent; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /apps/playground/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | 4 | import { AppComponent } from './app.component'; 5 | 6 | @NgModule({ 7 | declarations: [AppComponent], 8 | imports: [BrowserModule], 9 | providers: [], 10 | bootstrap: [AppComponent], 11 | }) 12 | export class AppModule {} 13 | -------------------------------------------------------------------------------- /apps/playground/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-architects/module-federation-plugin/31c8117df81fe7e8be388839a92cf369bd47eed9/apps/playground/src/assets/.gitkeep -------------------------------------------------------------------------------- /apps/playground/src/bootstrap.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic() 12 | .bootstrapModule(AppModule) 13 | .catch((err) => console.error(err)); 14 | -------------------------------------------------------------------------------- /apps/playground/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | }; 4 | -------------------------------------------------------------------------------- /apps/playground/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/playground/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-architects/module-federation-plugin/31c8117df81fe7e8be388839a92cf369bd47eed9/apps/playground/src/favicon.ico -------------------------------------------------------------------------------- /apps/playground/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Playground 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/playground/src/main.ts: -------------------------------------------------------------------------------- 1 | import { initFederation } from '@angular-architects/native-federation'; 2 | 3 | initFederation({ 4 | //'mfe1': 'http://localhost:3001/remoteEntry.json' 5 | }) 6 | .then(() => import('./bootstrap')) 7 | .catch((e) => console.error('err', e)); 8 | -------------------------------------------------------------------------------- /apps/playground/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /apps/playground/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | 3 | import { getTestBed } from '@angular/core/testing'; 4 | import { 5 | BrowserDynamicTestingModule, 6 | platformBrowserDynamicTesting, 7 | } from '@angular/platform-browser-dynamic/testing'; 8 | 9 | getTestBed().resetTestEnvironment(); 10 | getTestBed().initTestEnvironment( 11 | BrowserDynamicTestingModule, 12 | platformBrowserDynamicTesting(), 13 | { teardown: { destroyAfterEach: false } } 14 | ); 15 | -------------------------------------------------------------------------------- /apps/playground/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": [] 6 | }, 7 | "files": ["src/main.ts", "src/polyfills.ts"], 8 | "include": ["src/**/*.d.ts"], 9 | "exclude": ["jest.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /apps/playground/tsconfig.editor.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["**/*.ts"], 4 | "compilerOptions": { 5 | "types": ["jest", "node"] 6 | }, 7 | "exclude": ["jest.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /apps/playground/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 | } 19 | } 20 | -------------------------------------------------------------------------------- /apps/playground/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": ["**/*.spec.ts", "**/*.test.ts", "**/*.d.ts", "jest.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-architects/module-federation-plugin/31c8117df81fe7e8be388839a92cf369bd47eed9/error.png -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import { getJestProjectsAsync } from '@nx/jest'; 2 | 3 | export default async () => ({ 4 | projects: await getJestProjectsAsync(), 5 | }); 6 | -------------------------------------------------------------------------------- /jest.preset.js: -------------------------------------------------------------------------------- 1 | const nxPreset = require('@nx/jest/preset').default; 2 | 3 | module.exports = { 4 | ...nxPreset, 5 | /* TODO: Update to latest Jest snapshotFormat 6 | * By default Nx has kept the older style of Jest Snapshot formats 7 | * to prevent breaking of any existing tests with snapshots. 8 | * It's recommend you update to the latest format. 9 | * You can do this by removing snapshotFormat property 10 | * and running tests with --update-snapshot flag. 11 | * Example: "nx affected --targets=e2e --update-snapshot" 12 | * More info: https://jestjs.io/docs/upgrading-to-jest29#snapshot-format 13 | */ 14 | snapshotFormat: { escapeString: true, printBasicPrototype: true }, 15 | // because of https://github.com/jestjs/jest/issues/4422 16 | globals: { 17 | Uint8Array: Uint8Array, 18 | }, 19 | passWithNoTests: true, 20 | }; 21 | -------------------------------------------------------------------------------- /libs/mf-runtime/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json", "../../.eslintrc.base.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "extends": [ 8 | "plugin:@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": "angularArchitects", 17 | "style": "camelCase" 18 | } 19 | ], 20 | "@angular-eslint/component-selector": [ 21 | "error", 22 | { 23 | "type": "element", 24 | "prefix": "angular-architects", 25 | "style": "kebab-case" 26 | } 27 | ], 28 | "@angular-eslint/prefer-standalone": "off" 29 | } 30 | }, 31 | { 32 | "files": ["*.html"], 33 | "extends": ["plugin:@nx/angular-template"], 34 | "rules": {} 35 | }, 36 | { 37 | "files": ["*.json"], 38 | "parser": "jsonc-eslint-parser", 39 | "rules": { 40 | "@nx/dependency-checks": "warn" 41 | } 42 | } 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /libs/mf-runtime/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Softarc Consulting GmbH 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /libs/mf-runtime/README.md: -------------------------------------------------------------------------------- 1 | # @angular-architects/module-federation-runtime 2 | 3 | Runtime lib for @angular-architects/module-federation. 4 | -------------------------------------------------------------------------------- /libs/mf-runtime/enhanced/README.md: -------------------------------------------------------------------------------- 1 | # @angular-architects/module-federation-runtime/enhanced 2 | 3 | Secondary entry point of `@angular-architects/module-federation-runtime`. It can be used by importing from `@angular-architects/module-federation-runtime/enhanced`. 4 | -------------------------------------------------------------------------------- /libs/mf-runtime/enhanced/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "lib": { 3 | "entryFile": "src/index.ts" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /libs/mf-runtime/enhanced/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/init-federation'; 2 | export * from './lib/loadRemoteModule'; 3 | -------------------------------------------------------------------------------- /libs/mf-runtime/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'mf-runtime', 4 | preset: '../../jest.preset.js', 5 | setupFilesAfterEnv: ['/src/test-setup.ts'], 6 | coverageDirectory: '../../coverage/libs/mf-runtime', 7 | transform: { 8 | '^.+\\.(ts|mjs|js|html)$': [ 9 | 'jest-preset-angular', 10 | { 11 | tsconfig: '/tsconfig.spec.json', 12 | stringifyContentPathRegex: '\\.(html|svg)$', 13 | }, 14 | ], 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/mf-runtime/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../dist/libs/mf-runtime", 4 | "lib": { 5 | "entryFile": "src/index.ts" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /libs/mf-runtime/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@angular-architects/module-federation-runtime", 3 | "license": "MIT", 4 | "version": "19.0.3", 5 | "peerDependencies": { 6 | "@angular/common": ">=18.0.0", 7 | "@angular/core": ">=18.0.0", 8 | "@module-federation/enhanced": "^0.9.0", 9 | "@module-federation/runtime-core": "^0.6.21" 10 | }, 11 | "dependencies": { 12 | "tslib": "^2.0.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /libs/mf-runtime/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mf-runtime", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "projectType": "library", 5 | "sourceRoot": "libs/mf-runtime/src", 6 | "prefix": "angular-architects", 7 | "targets": { 8 | "build": { 9 | "executor": "@nx/angular:package", 10 | "outputs": ["{workspaceRoot}/dist/{projectRoot}"], 11 | "options": { 12 | "project": "libs/mf-runtime/ng-package.json" 13 | }, 14 | "configurations": { 15 | "production": { 16 | "tsConfig": "libs/mf-runtime/tsconfig.lib.prod.json" 17 | }, 18 | "development": { 19 | "tsConfig": "libs/mf-runtime/tsconfig.lib.json" 20 | } 21 | }, 22 | "defaultConfiguration": "production" 23 | }, 24 | "publish": { 25 | "dependsOn": ["build"], 26 | "executor": "nx:run-commands", 27 | "options": { 28 | "command": "node tools/scripts/publish.mjs mf-runtime npm {args.ver} {args.tag}" 29 | } 30 | }, 31 | "publish-local": { 32 | "dependsOn": ["build"], 33 | "executor": "nx:run-commands", 34 | "options": { 35 | "command": "node tools/scripts/publish.mjs mf-runtime verdaccio {args.ver}" 36 | } 37 | } 38 | }, 39 | "tags": ["org:angular-architects", "scope:mf"] 40 | } 41 | -------------------------------------------------------------------------------- /libs/mf-runtime/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/loader/dynamic-federation'; 2 | -------------------------------------------------------------------------------- /libs/mf-runtime/src/lib/loader/webpack-runtime-api.d.ts: -------------------------------------------------------------------------------- 1 | type Scope = unknown; 2 | type Factory = () => any; 3 | 4 | type Container = { 5 | init(shareScope: Scope): void; 6 | get(module: string): Factory; 7 | }; 8 | 9 | declare const __webpack_init_sharing__: (shareScope: string) => Promise; 10 | declare const __webpack_share_scopes__: { default: Scope }; 11 | -------------------------------------------------------------------------------- /libs/mf-runtime/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | // @ts-expect-error https://thymikee.github.io/jest-preset-angular/docs/getting-started/test-environment 2 | globalThis.ngJest = { 3 | testEnvironmentOptions: { 4 | errorOnUnknownElements: true, 5 | errorOnUnknownProperties: true, 6 | }, 7 | }; 8 | import 'jest-preset-angular/setup-jest'; 9 | -------------------------------------------------------------------------------- /libs/mf-runtime/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "target": "es2022", 5 | "useDefineForClassFields": false, 6 | "forceConsistentCasingInFileNames": true, 7 | // "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true 12 | }, 13 | "files": [], 14 | "include": [], 15 | "references": [ 16 | { 17 | "path": "./tsconfig.lib.json" 18 | }, 19 | { 20 | "path": "./tsconfig.spec.json" 21 | } 22 | ], 23 | "angularCompilerOptions": { 24 | "enableI18nLegacyMessageIdFormat": false, 25 | "strictInjectionParameters": true, 26 | "strictInputAccessModifiers": true, 27 | "strictTemplates": true 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /libs/mf-runtime/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 | "**/*.spec.ts", 12 | "test-setup.ts", 13 | "jest.config.ts", 14 | "**/*.test.ts" 15 | ], 16 | "include": ["**/*.ts"] 17 | } 18 | -------------------------------------------------------------------------------- /libs/mf-runtime/tsconfig.lib.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.lib.json", 3 | "compilerOptions": { 4 | "declarationMap": false 5 | }, 6 | "angularCompilerOptions": { 7 | "compilationMode": "partial" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /libs/mf-runtime/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "target": "es2016", 7 | "types": ["jest", "node"] 8 | }, 9 | "files": ["src/test-setup.ts"], 10 | "include": [ 11 | "jest.config.ts", 12 | "src/**/*.test.ts", 13 | "src/**/*.spec.ts", 14 | "src/**/*.d.ts" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /libs/mf-tools/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json", "../../.eslintrc.base.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "extends": [ 8 | "plugin:@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": "angularArchitects", 17 | "style": "camelCase" 18 | } 19 | ], 20 | "@angular-eslint/component-selector": [ 21 | "error", 22 | { 23 | "type": "element", 24 | "prefix": "angular-architects", 25 | "style": "kebab-case" 26 | } 27 | ], 28 | "@angular-eslint/prefer-standalone": "off" 29 | } 30 | }, 31 | { 32 | "files": ["*.html"], 33 | "extends": ["plugin:@nx/angular-template"], 34 | "rules": {} 35 | }, 36 | { 37 | "files": ["*.json"], 38 | "parser": "jsonc-eslint-parser", 39 | "rules": { 40 | "@nx/dependency-checks": "warn" 41 | } 42 | } 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /libs/mf-tools/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "spellright.language": ["en"], 3 | "spellright.documentTypes": ["markdown", "latex", "plaintext"] 4 | } 5 | -------------------------------------------------------------------------------- /libs/mf-tools/.vscode/spellright.dict: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-architects/module-federation-plugin/31c8117df81fe7e8be388839a92cf369bd47eed9/libs/mf-tools/.vscode/spellright.dict -------------------------------------------------------------------------------- /libs/mf-tools/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Softarc Consulting GmbH 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /libs/mf-tools/img/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-architects/module-federation-plugin/31c8117df81fe7e8be388839a92cf369bd47eed9/libs/mf-tools/img/example.png -------------------------------------------------------------------------------- /libs/mf-tools/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'mf-tools', 4 | preset: '../../jest.preset.js', 5 | setupFilesAfterEnv: ['/src/test-setup.ts'], 6 | coverageDirectory: '../../coverage/libs/mf-tools', 7 | transform: { 8 | '^.+\\.(ts|mjs|js|html)$': [ 9 | 'jest-preset-angular', 10 | { 11 | tsconfig: '/tsconfig.spec.json', 12 | stringifyContentPathRegex: '\\.(html|svg)$', 13 | }, 14 | ], 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/mf-tools/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../dist/libs/mf-tools", 4 | "lib": { 5 | "entryFile": "src/index.ts" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /libs/mf-tools/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@angular-architects/module-federation-tools", 3 | "version": "19.0.3", 4 | "license": "MIT", 5 | "peerDependencies": {}, 6 | "dependencies": { 7 | "tslib": "^2.0.0" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /libs/mf-tools/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mf-tools", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "projectType": "library", 5 | "sourceRoot": "libs/mf-tools/src", 6 | "prefix": "angular-architects", 7 | "targets": { 8 | "build": { 9 | "executor": "@nx/angular:package", 10 | "outputs": ["{workspaceRoot}/dist/{projectRoot}"], 11 | "options": { 12 | "project": "libs/mf-tools/ng-package.json" 13 | }, 14 | "configurations": { 15 | "production": { 16 | "tsConfig": "libs/mf-tools/tsconfig.lib.prod.json" 17 | }, 18 | "development": { 19 | "tsConfig": "libs/mf-tools/tsconfig.lib.json" 20 | } 21 | }, 22 | "defaultConfiguration": "production" 23 | }, 24 | "publish": { 25 | "dependsOn": ["build"], 26 | "executor": "nx:run-commands", 27 | "options": { 28 | "command": "node tools/scripts/publish.mjs mf-tools npm {args.ver} {args.tag}" 29 | } 30 | }, 31 | "publish-local": { 32 | "dependsOn": ["build"], 33 | "executor": "nx:run-commands", 34 | "options": { 35 | "command": "node tools/scripts/publish.mjs mf-tools verdaccio {args.ver}" 36 | } 37 | } 38 | }, 39 | "tags": ["org:angular-architects", "scope:mf"] 40 | } 41 | -------------------------------------------------------------------------------- /libs/mf-tools/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/mf-tools.module'; 2 | export * from './lib/web-components/web-component-wrapper'; 3 | export * from './lib/web-components/bootstrap-utils'; 4 | export * from './lib/web-components/router-utils'; 5 | -------------------------------------------------------------------------------- /libs/mf-tools/src/lib/mf-tools.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { WebComponentWrapper } from './web-components/web-component-wrapper'; 4 | 5 | @NgModule({ 6 | imports: [CommonModule], 7 | declarations: [WebComponentWrapper], 8 | exports: [WebComponentWrapper], 9 | }) 10 | export class ModuleFederationToolsModule {} 11 | -------------------------------------------------------------------------------- /libs/mf-tools/src/lib/utils/global-state.ts: -------------------------------------------------------------------------------- 1 | export const packageNamespace = '@angular-architects/module-federation-tools'; 2 | 3 | function getGlobalState(): T { 4 | const globalState = window as unknown as { [packageNamespace]: T }; 5 | globalState[packageNamespace] = 6 | globalState[packageNamespace] || ({} as unknown as T); 7 | return globalState[packageNamespace]; 8 | } 9 | 10 | export function getGlobalStateSlice(): T; 11 | export function getGlobalStateSlice(selector: (globalState: T) => R): R; 12 | export function getGlobalStateSlice( 13 | selector?: (globalState: T) => R 14 | ): R | T { 15 | const globalState = getGlobalState(); 16 | return selector ? selector(globalState) : globalState; 17 | } 18 | 19 | export function setGlobalStateSlice(slice: T): T { 20 | return Object.assign(getGlobalState(), slice); 21 | } 22 | -------------------------------------------------------------------------------- /libs/mf-tools/src/lib/web-components/router-utils.ts: -------------------------------------------------------------------------------- 1 | import { Router, UrlMatcher, UrlSegment } from '@angular/router'; 2 | 3 | export function startsWith(prefix: string): UrlMatcher { 4 | return (url: UrlSegment[]) => { 5 | const fullUrl = url.map((u) => u.path).join('/'); 6 | if (fullUrl.startsWith(prefix)) { 7 | return { consumed: url }; 8 | } 9 | return null; 10 | }; 11 | } 12 | 13 | export function endsWith(prefix: string): UrlMatcher { 14 | return (url: UrlSegment[]) => { 15 | const fullUrl = url.map((u) => u.path).join('/'); 16 | if (fullUrl.endsWith(prefix)) { 17 | return { consumed: url }; 18 | } 19 | return null; 20 | }; 21 | } 22 | 23 | export function connectRouter(router: Router, useHash = false): void { 24 | let url: string; 25 | if (!useHash) { 26 | url = `${location.pathname.substring(1)}${location.search}`; 27 | router.navigateByUrl(url); 28 | window.addEventListener('popstate', () => { 29 | router.navigateByUrl(url); 30 | }); 31 | } else { 32 | url = `${location.hash.substring(1)}${location.search}`; 33 | router.navigateByUrl(url); 34 | window.addEventListener('hashchange', () => { 35 | router.navigateByUrl(url); 36 | }); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /libs/mf-tools/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | // @ts-expect-error https://thymikee.github.io/jest-preset-angular/docs/getting-started/test-environment 2 | globalThis.ngJest = { 3 | testEnvironmentOptions: { 4 | errorOnUnknownElements: true, 5 | errorOnUnknownProperties: true, 6 | }, 7 | }; 8 | import 'jest-preset-angular/setup-jest'; 9 | -------------------------------------------------------------------------------- /libs/mf-tools/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "target": "es2022", 5 | "useDefineForClassFields": false, 6 | "forceConsistentCasingInFileNames": true, 7 | // "strict": true, 8 | "noImplicitOverride": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noImplicitReturns": true, 11 | "noFallthroughCasesInSwitch": true 12 | }, 13 | "files": [], 14 | "include": [], 15 | "references": [ 16 | { 17 | "path": "./tsconfig.lib.json" 18 | }, 19 | { 20 | "path": "./tsconfig.spec.json" 21 | } 22 | ], 23 | "angularCompilerOptions": { 24 | "enableI18nLegacyMessageIdFormat": false, 25 | "strictInjectionParameters": true, 26 | "strictInputAccessModifiers": true, 27 | "strictTemplates": true 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /libs/mf-tools/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/**/*.spec.ts", 12 | "src/test-setup.ts", 13 | "jest.config.ts", 14 | "src/**/*.test.ts" 15 | ], 16 | "include": ["src/**/*.ts"] 17 | } 18 | -------------------------------------------------------------------------------- /libs/mf-tools/tsconfig.lib.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.lib.json", 3 | "compilerOptions": { 4 | "declarationMap": false 5 | }, 6 | "angularCompilerOptions": { 7 | "compilationMode": "partial" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /libs/mf-tools/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "target": "es2016", 7 | "types": ["jest", "node"] 8 | }, 9 | "files": ["src/test-setup.ts"], 10 | "include": [ 11 | "jest.config.ts", 12 | "src/**/*.test.ts", 13 | "src/**/*.spec.ts", 14 | "src/**/*.d.ts" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /libs/mf/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@nx/js/babel", 5 | { 6 | "useBuiltIns": "usage" 7 | } 8 | ] 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /libs/mf/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.base.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | }, 17 | { 18 | "files": ["*.json"], 19 | "parser": "jsonc-eslint-parser", 20 | "rules": { 21 | "@nx/dependency-checks": "warn" 22 | } 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /libs/mf/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Softarc Consulting GmbH 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /libs/mf/builders.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/@angular-devkit/architect/src/builders-schema.json", 3 | "builders": { 4 | "build": { 5 | "implementation": "./src/builders/build/builder", 6 | "schema": "./src/builders/build/schema.json", 7 | "description": "build builder" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /libs/mf/executors.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "executors": { 4 | "build": { 5 | "implementation": "./src/executors/build/executor", 6 | "schema": "./src/executors/build/schema.json", 7 | "description": "build executor" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /libs/mf/generators.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "name": "mf", 4 | "version": "0.0.1", 5 | "generators": { 6 | "mf": { 7 | "factory": "./src/generators/mf/generator", 8 | "schema": "./src/generators/mf/schema.json", 9 | "description": "mf generator" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /libs/mf/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'mf', 4 | preset: '../../jest.preset.js', 5 | testEnvironment: 'node', 6 | transform: { 7 | '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], 8 | }, 9 | moduleFileExtensions: ['ts', 'js', 'html'], 10 | coverageDirectory: '../../coverage/libs/mf', 11 | }; 12 | -------------------------------------------------------------------------------- /libs/mf/nguniversal.ts: -------------------------------------------------------------------------------- 1 | export * from './src/universal/create-fetch'; 2 | -------------------------------------------------------------------------------- /libs/mf/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@angular-architects/module-federation", 3 | "version": "19.0.3", 4 | "license": "MIT", 5 | "repository": { 6 | "type": "GitHub", 7 | "url": "https://github.com/angular-architects/module-federation-plugin" 8 | }, 9 | "author": { 10 | "name": "Manfred Steyer", 11 | "email": "manfred.steyer@gmx.net", 12 | "url": "https://www.angulararchitects.io" 13 | }, 14 | "module": "src/index.js", 15 | "ES2015": "./src/index.js", 16 | "sideEffects": false, 17 | "schematics": "./collection.json", 18 | "builders": "./builders.json", 19 | "dependencies": { 20 | "@angular-architects/module-federation-runtime": "19.0.3", 21 | "word-wrap": "^1.2.3", 22 | "callsite": "^1.0.0", 23 | "node-fetch": "^2.6.7", 24 | "semver": "^7.3.5" 25 | }, 26 | "peerDependencies": {}, 27 | "ng-update": { 28 | "migrations": "./migrations.json", 29 | "package-group": [ 30 | "@angular-architects/module-federation-tools", 31 | "ngx-build-plus" 32 | ] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /libs/mf/post-build.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | // const index = fs.readFileSync(path.join(__dirname, 'src/index.ts'), { 5 | // encoding: 'utf-8', 6 | // }); 7 | // fs.writeFileSync( 8 | // path.join(__dirname, '../../dist/libs/mf/src/index.js'), 9 | // index 10 | // ); 11 | 12 | // const nguniversal = fs.readFileSync( 13 | // path.join(__dirname, 'src/nguniversal.ts'), 14 | // { 15 | // encoding: 'utf-8', 16 | // } 17 | // ); 18 | // fs.writeFileSync( 19 | // path.join(__dirname, '../../dist/libs/mf/src/nguniversal.js'), 20 | // nguniversal 21 | // ); 22 | 23 | const webpack2 = fs.readFileSync(path.join(__dirname, 'webpack.ts'), { 24 | encoding: 'utf-8', 25 | }); 26 | fs.writeFileSync( 27 | path.join(__dirname, '../../dist/libs/mf/webpack.js'), 28 | 'module.exports = require("./src/webpack.js");' 29 | ); 30 | -------------------------------------------------------------------------------- /libs/mf/rspack.ts: -------------------------------------------------------------------------------- 1 | export * from './src/rspack'; 2 | export { 3 | DEFAULT_SECONARIES_SKIP_LIST, 4 | DEFAULT_SKIP_LIST, 5 | SharedMappings, 6 | findRootTsConfigJson, 7 | share, 8 | shareAll, 9 | } from './webpack'; 10 | -------------------------------------------------------------------------------- /libs/mf/runtime.ts: -------------------------------------------------------------------------------- 1 | export * from '@angular-architects/module-federation-runtime/enhanced'; 2 | -------------------------------------------------------------------------------- /libs/mf/src/builders/build/builder.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BuilderContext, 3 | BuilderOutput, 4 | createBuilder, 5 | } from '@angular-devkit/architect'; 6 | import { Observable, of } from 'rxjs'; 7 | import { tap } from 'rxjs/operators'; 8 | import { BuildBuilderSchema } from './schema'; 9 | 10 | export function runBuilder( 11 | options: BuildBuilderSchema, 12 | context: BuilderContext 13 | ): Observable { 14 | return of({ success: true }).pipe( 15 | tap(() => { 16 | context.logger.info('Builder ran for build'); 17 | }) 18 | ); 19 | } 20 | 21 | export default createBuilder(runBuilder as any); 22 | -------------------------------------------------------------------------------- /libs/mf/src/builders/build/schema.d.ts: -------------------------------------------------------------------------------- 1 | import { JsonObject } from '@angular-devkit/core'; 2 | 3 | export interface BuildBuilderSchema extends JsonObject {} // eslint-disable-line 4 | -------------------------------------------------------------------------------- /libs/mf/src/builders/build/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "outputCapture": "direct-nodejs", 4 | "$schema": "http://json-schema.org/schema", 5 | "title": "Build builder", 6 | "description": "", 7 | "type": "object", 8 | "properties": {}, 9 | "required": [] 10 | } 11 | -------------------------------------------------------------------------------- /libs/mf/src/executors/build/executor.spec.ts: -------------------------------------------------------------------------------- 1 | import { BuildExecutorSchema } from './schema'; 2 | import executor from './executor'; 3 | 4 | const options: BuildExecutorSchema = {}; 5 | 6 | describe('Build Executor', () => { 7 | it('can run', async () => { 8 | const output = await executor(options); 9 | expect(output.success).toBe(true); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /libs/mf/src/executors/build/executor.ts: -------------------------------------------------------------------------------- 1 | import { BuildExecutorSchema } from './schema'; 2 | 3 | export default async function runExecutor(options: BuildExecutorSchema) { 4 | console.log('Executor ran for Build', options); 5 | return { 6 | success: true, 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /libs/mf/src/executors/build/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface BuildExecutorSchema {} // eslint-disable-line 2 | -------------------------------------------------------------------------------- /libs/mf/src/executors/build/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "cli": "nx", 4 | "title": "Build executor", 5 | "description": "", 6 | "type": "object", 7 | "properties": {}, 8 | "required": [] 9 | } 10 | -------------------------------------------------------------------------------- /libs/mf/src/generators/mf/files/src/index.ts__template__: -------------------------------------------------------------------------------- 1 | const variable = "<%= projectName %>"; -------------------------------------------------------------------------------- /libs/mf/src/generators/mf/generator.spec.ts: -------------------------------------------------------------------------------- 1 | import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; 2 | import { Tree, readProjectConfiguration } from '@nx/devkit'; 3 | 4 | import generator from './generator'; 5 | import { MfGeneratorSchema } from './schema'; 6 | 7 | describe('mf generator', () => { 8 | let appTree: Tree; 9 | const options: MfGeneratorSchema = { name: 'test' }; 10 | 11 | beforeEach(() => { 12 | appTree = createTreeWithEmptyWorkspace(); 13 | }); 14 | 15 | it('should run successfully', async () => { 16 | await generator(appTree, options); 17 | const config = readProjectConfiguration(appTree, 'test'); 18 | expect(config).toBeDefined(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /libs/mf/src/generators/mf/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface MfGeneratorSchema { 2 | name: string; 3 | tags?: string; 4 | directory?: string; 5 | } 6 | -------------------------------------------------------------------------------- /libs/mf/src/generators/mf/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "cli": "nx", 4 | "id": "Mf", 5 | "title": "", 6 | "type": "object", 7 | "properties": { 8 | "name": { 9 | "type": "string", 10 | "description": "", 11 | "$default": { 12 | "$source": "argv", 13 | "index": 0 14 | }, 15 | "x-prompt": "What name would you like to use?" 16 | }, 17 | "tags": { 18 | "type": "string", 19 | "description": "Add tags to the project (used for linting)", 20 | "alias": "t" 21 | }, 22 | "directory": { 23 | "type": "string", 24 | "description": "A directory where the project is placed", 25 | "alias": "d" 26 | } 27 | }, 28 | "required": ["name"] 29 | } 30 | -------------------------------------------------------------------------------- /libs/mf/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from '@angular-architects/module-federation-runtime'; 2 | -------------------------------------------------------------------------------- /libs/mf/src/nguniversal.ts: -------------------------------------------------------------------------------- 1 | export * from './universal/create-fetch'; 2 | -------------------------------------------------------------------------------- /libs/mf/src/rspack/index.ts: -------------------------------------------------------------------------------- 1 | export * from './plugin-script-module'; 2 | export * from './with-federation'; 3 | -------------------------------------------------------------------------------- /libs/mf/src/rspack/plugin-script-module.ts: -------------------------------------------------------------------------------- 1 | import { HtmlBasicTag, RsbuildPlugin } from '@rsbuild/core'; 2 | 3 | export const pluginScriptModule = (): RsbuildPlugin => ({ 4 | name: 'plugin-script-module', 5 | setup: (api) => { 6 | api.modifyHTMLTags(({ headTags, bodyTags }) => { 7 | updateTags(headTags); 8 | updateTags(bodyTags); 9 | 10 | return { headTags, bodyTags }; 11 | }); 12 | }, 13 | }); 14 | 15 | function updateTags(tags: HtmlBasicTag[]) { 16 | tags.forEach((tag) => { 17 | if (tag.tag === 'script') { 18 | tag.attrs = { 19 | ...tag.attrs, 20 | type: 'module', 21 | }; 22 | } 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/boot-async/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface BootAsyncSchema { 2 | project: string; 3 | async: boolean; 4 | } 5 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/boot-async/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "$id": "mf", 4 | "title": "", 5 | "type": "object", 6 | "properties": { 7 | "project": { 8 | "type": "string", 9 | "description": "The project to add module federation", 10 | "x-prompt": "Project name (press enter for default project)" 11 | }, 12 | "async": { 13 | "type": "boolean", 14 | "description": "Enable or disable async bootstrapping", 15 | "$default": { 16 | "$source": "argv", 17 | "index": 0 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/init-rspack/files/federation.config.ts__tmpl__: -------------------------------------------------------------------------------- 1 | import { withFederation, shareAll } from '@angular-architects/module-federation/rspack' 2 | 3 | export default withFederation({ 4 | options: { 5 | <% if (type === 'remote') { %> 6 | name: '<%=project%>', 7 | 8 | exposes: { 9 | './Component': './src/app/app.component.ts', 10 | }, 11 | <% } else if (type === 'host') { %> 12 | remotes: {<% for (key in remoteMap) { %> 13 | "<%=key%>": "<%=remoteMap[key]%>",<% } %> 14 | }, 15 | <% } %> 16 | shared: { 17 | ...shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }), 18 | }, 19 | 20 | }, 21 | skip: [ 22 | // Add the names of packages, entrypoints 23 | // and libs you don't want to share here 24 | // Strings are compared with === 25 | 26 | // Examples: 27 | // 'rxjs/ajax' 28 | // p => p.startsWith('rxjs/ajax') 29 | // /^rxjs\/ajax/ 30 | ] 31 | }); 32 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/init-rspack/files/rsbuild.config.ts__tmpl__: -------------------------------------------------------------------------------- 1 | import { createConfig } from '@ng-rsbuild/plugin-angular'; 2 | import applyFederation from './federation.config'; 3 | 4 | const rsbuildConfig = createConfig( 5 | { 6 | browser: './src/main.ts', 7 | }, 8 | { 9 | server: { 10 | port: <%=port%>, 11 | }, 12 | } 13 | ); 14 | 15 | export default applyFederation(rsbuildConfig); 16 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/init-rspack/prod-config.ts: -------------------------------------------------------------------------------- 1 | export const prodConfig = `module.exports = require('./webpack.config'); 2 | `; 3 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/init-rspack/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface MfSchematicSchema { 2 | project: string; 3 | port: string; 4 | nxBuilders: boolean | undefined; 5 | type: 'host' | 'dynamic-host' | 'remote' | 'legacy'; 6 | } 7 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/init-rspack/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "$id": "mf", 4 | "title": "", 5 | "type": "object", 6 | "properties": { 7 | "project": { 8 | "type": "string", 9 | "description": "The project to add module federation", 10 | "$default": { 11 | "$source": "argv", 12 | "index": 0 13 | }, 14 | "x-prompt": "Project name (press enter for default project)" 15 | }, 16 | "port": { 17 | "type": "number", 18 | "description": "The port to use for the federated module (remote, micro frontend, etc.)", 19 | "x-prompt": { 20 | "message": "Port to use", 21 | "type": "number" 22 | }, 23 | "$default": { 24 | "$source": "argv", 25 | "index": 1 26 | } 27 | }, 28 | "type": { 29 | "enum": ["host", "dynamic-host", "remote", "legacy"], 30 | "type": "string", 31 | "default": "legacy" 32 | }, 33 | "nxBuilders": { 34 | "type": "boolean", 35 | "description": "Use builders provided by Nx instead of ngx-build-plus? Defaults to true for Nx workspaces and false for CLI workspaces." 36 | } 37 | }, 38 | "required": ["port"] 39 | } 40 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/init-webpack/files/webpack.config.js__tmpl__: -------------------------------------------------------------------------------- 1 | const { shareAll, withModuleFederationPlugin } = require('@angular-architects/module-federation/webpack'); 2 | 3 | module.exports = withModuleFederationPlugin({ 4 | <% if (type === 'remote') { %> 5 | name: '<%=project%>', 6 | 7 | exposes: { 8 | './Component': './<%=projectSourceRoot%>/app/app.component.ts', 9 | }, 10 | <% } else if (type === 'host') { %> 11 | remotes: {<% for (key in remoteMap) { %> 12 | "<%=key%>": "<%=remoteMap[key]%>",<% } %> 13 | }, 14 | <% } %> 15 | shared: { 16 | ...shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }), 17 | }, 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/init-webpack/prod-config.ts: -------------------------------------------------------------------------------- 1 | export const prodConfig = `module.exports = require('./webpack.config'); 2 | `; 3 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/init-webpack/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface MfSchematicSchema { 2 | project: string; 3 | port: string; 4 | nxBuilders: boolean | undefined; 5 | skipConfirmation: boolean; 6 | type: 'host' | 'dynamic-host' | 'remote' | 'legacy'; 7 | } 8 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/init-webpack/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "$id": "mf", 4 | "title": "", 5 | "type": "object", 6 | "properties": { 7 | "project": { 8 | "type": "string", 9 | "description": "The project to add module federation", 10 | "$default": { 11 | "$source": "argv", 12 | "index": 0 13 | }, 14 | "x-prompt": "Project name (press enter for default project)" 15 | }, 16 | "port": { 17 | "type": "number", 18 | "description": "The port to use for the federated module (remote, micro frontend, etc.)", 19 | "x-prompt": { 20 | "message": "Port to use", 21 | "type": "number" 22 | }, 23 | "$default": { 24 | "$source": "argv", 25 | "index": 1 26 | } 27 | }, 28 | "type": { 29 | "enum": ["host", "dynamic-host", "remote", "legacy"], 30 | "type": "string", 31 | "default": "legacy" 32 | }, 33 | "nxBuilders": { 34 | "type": "boolean", 35 | "description": "Use builders provided by Nx instead of ngx-build-plus? Defaults to true for Nx workspaces and false for CLI workspaces." 36 | }, 37 | "skip-confirmation": { 38 | "type": "boolean", 39 | "default": false 40 | } 41 | }, 42 | "required": ["port"] 43 | } 44 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/init/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface InitSchema { 2 | project: string; 3 | port: string | number; 4 | nxBuilders: boolean | undefined; 5 | type: 'host' | 'dynamic-host' | 'remote' | 'legacy'; 6 | skipConfirmation: boolean; 7 | stack: 8 | | 'module-federation-webpack' 9 | | 'module-federation-rsbuild-experimental' 10 | | 'native-federation-esbuild'; 11 | } 12 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/migrate-to-13/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface BootAsyncSchema { 2 | project: string; 3 | async: boolean; 4 | } 5 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/migrate-to-13/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "$id": "mf", 4 | "title": "", 5 | "type": "object", 6 | "properties": {} 7 | } 8 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/migrate-to-13/schematic.ts: -------------------------------------------------------------------------------- 1 | import { Rule } from '@angular-devkit/schematics'; 2 | 3 | export function index(): Rule { 4 | return async function () { 5 | console.info(`!!! 6 | Angular 13 compiles bundles as EcmaScript modules. 7 | Hence, we need to adjust how we use Module Federation. 8 | We've got you covered. Please find all information here: 9 | https://github.com/angular-architects/module-federation-plugin/blob/main/migration-guide.md 10 | !!! 11 | `); 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/migrate-to-14-3/schema.d.ts: -------------------------------------------------------------------------------- 1 | type BootAsyncSchema = object; 2 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/migrate-to-14-3/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "$id": "mf", 4 | "title": "", 5 | "type": "object", 6 | "properties": {} 7 | } 8 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/migrate-to-14-3/schematic.ts: -------------------------------------------------------------------------------- 1 | import { Rule } from '@angular-devkit/schematics'; 2 | import { 3 | addPackageJsonDependency, 4 | NodeDependencyType, 5 | } from '@schematics/angular/utility/dependencies'; 6 | import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks'; 7 | 8 | export function index(): Rule { 9 | return async function (tree, context) { 10 | addPackageJsonDependency(tree, { 11 | name: 'ngx-build-plus', 12 | type: NodeDependencyType.Dev, 13 | version: '^14.0.0', 14 | overwrite: true, 15 | }); 16 | 17 | context.addTask(new NodePackageInstallTask()); 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/nguniversal/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface NgUniversalSchema { 2 | project: string; 3 | } 4 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/nguniversal/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "$id": "mf", 4 | "title": "", 5 | "type": "object", 6 | "properties": { 7 | "project": { 8 | "type": "string", 9 | "description": "The project to add module federation", 10 | "$default": { 11 | "$source": "argv", 12 | "index": 0 13 | }, 14 | "x-prompt": "Project name (press enter for default project)" 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/patch/schematic.ts: -------------------------------------------------------------------------------- 1 | import { noop, Rule } from '@angular-devkit/schematics'; 2 | import { execSync } from 'child_process'; 3 | 4 | // 5 | // Schematic for patching Angular for rsbuild integration while experimental. 6 | // Will be removed when stable! 7 | // Called via the init-rspack schematic to execute it AFTER the task running 8 | // npm install 9 | // 10 | 11 | export default function init(options: { workspaceRoot: string }): Rule { 12 | return async function () { 13 | const cmd = 14 | 'node node_modules/@ng-rsbuild/plugin-angular/patch/patch-angular-build.js'; 15 | 16 | try { 17 | execSync(cmd, { 18 | cwd: options.workspaceRoot, 19 | }); 20 | } catch (e) { 21 | console.error('Error patching Angular for rspack'); 22 | console.error( 23 | 'This is only needed while the rspack integration is experimental' 24 | ); 25 | console.error('Try to run this command by hand:'); 26 | console.error('\t' + cmd); 27 | console.error('Error', e); 28 | } 29 | 30 | return noop(); 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/remove/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface RemoveSchema { 2 | project: string; 3 | } 4 | -------------------------------------------------------------------------------- /libs/mf/src/schematics/remove/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "$id": "mf", 4 | "title": "", 5 | "type": "object", 6 | "properties": { 7 | "project": { 8 | "type": "string", 9 | "description": "The project to add module federation", 10 | "x-prompt": "Project name (press enter for default project)" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /libs/mf/src/server/index.ts: -------------------------------------------------------------------------------- 1 | import './mf-dev-server'; 2 | -------------------------------------------------------------------------------- /libs/mf/src/server/mf-dev-server.ts: -------------------------------------------------------------------------------- 1 | import { exec } from 'child_process'; 2 | import { isWorkspace, ProjectInfo, readProjectInfos } from './workspace'; 3 | import { print } from './colors'; 4 | import { argv } from 'process'; 5 | 6 | let padding; 7 | 8 | function startCmd(name: string, cmd: string): void { 9 | const process = exec(cmd); 10 | process.stdout.on('data', (chunk) => { 11 | print(name, padding, chunk); 12 | }); 13 | process.stderr.on('data', (chunk) => { 14 | print(name, padding, chunk, true); 15 | }); 16 | } 17 | 18 | // tslint:disable-next-line: no-shadowed-variable 19 | function startApps(apps: ProjectInfo[]): void { 20 | for (const app of apps) { 21 | const cmd = `ng serve ${app.name} -o`; 22 | print('DEVSVR', padding, app.name + ' ' + (app.port || '4200')); 23 | startCmd(app.name, cmd); 24 | } 25 | } 26 | 27 | if (!isWorkspace()) { 28 | console.error('This needs to be started in the root of an Angular project!'); 29 | process.exit(0); 30 | } 31 | 32 | const [, , ...filter] = argv; 33 | const startAll = filter.length === 0; 34 | 35 | const projects = readProjectInfos(); 36 | const apps = projects.filter( 37 | (p) => 38 | p.projectType === 'application' && 39 | !p.name.endsWith('-e2e') && 40 | (startAll || filter.includes(p.name)) 41 | ); 42 | padding = apps.reduce((acc, p) => Math.max(acc, p.name.length), 0); 43 | padding = Math.max(6, padding); 44 | startApps(apps); 45 | -------------------------------------------------------------------------------- /libs/mf/src/server/task-queue.ts: -------------------------------------------------------------------------------- 1 | export type DoneFn = () => void; 2 | export type Task = (done: DoneFn) => void; 3 | 4 | const queue: Task[] = []; 5 | 6 | // tslint:disable-next-line: no-shadowed-variable 7 | function peek(queue: Array): T { 8 | if (queue.length === 0) { 9 | return null; 10 | } 11 | return queue[queue.length - 1]; 12 | } 13 | 14 | function startNext(): void { 15 | if (queue.length === 0) { 16 | return; 17 | } 18 | queue.pop(); 19 | const task = peek(queue); 20 | if (task) { 21 | task(startNext); 22 | } 23 | } 24 | 25 | export function enqueuTask(task: Task): void { 26 | if (queue.length === 0) { 27 | queue.unshift(task); 28 | task(startNext); 29 | } else { 30 | queue.unshift(task); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /libs/mf/src/utils/decl.d.ts: -------------------------------------------------------------------------------- 1 | declare const require: any; 2 | -------------------------------------------------------------------------------- /libs/mf/src/utils/modify-entry-plugin.ts: -------------------------------------------------------------------------------- 1 | export class ModifyEntryPlugin { 2 | config: unknown; 3 | constructor(config) { 4 | this.config = config; 5 | } 6 | 7 | apply(compiler) { 8 | const mergeEntry = (keyFn, key) => [ 9 | ...(keyFn(this.config[key]) || []), 10 | ...(keyFn(compiler.options.entry[key]) || []), 11 | ]; 12 | const cfgOrRemove = (objFn, valueFn, key) => { 13 | const values = mergeEntry(valueFn, key); 14 | return values.length > 0 ? objFn(values) : {}; 15 | }; 16 | Object.keys(this.config).forEach((key) => { 17 | compiler.options.entry[key] = { 18 | ...cfgOrRemove( 19 | (v) => ({ import: v }), 20 | (c) => c.import, 21 | key 22 | ), 23 | ...cfgOrRemove( 24 | (v) => ({ dependOn: v }), 25 | (c) => c.dependOn, 26 | key 27 | ), 28 | }; 29 | }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /libs/mf/src/utils/skip-list.ts: -------------------------------------------------------------------------------- 1 | import { SharedObject } from '@module-federation/enhanced/dist/src/declarations/plugins/sharing/SharePlugin'; 2 | 3 | export type CheckSkipFn = (packageName: string) => boolean; 4 | export type SkipListItem = string | RegExp | CheckSkipFn; 5 | export type SkipList = SkipListItem[]; 6 | export type NormalizedSkipList = CheckSkipFn[]; 7 | 8 | export function normalizeSkipList(skipList: SkipList = []): NormalizedSkipList { 9 | return skipList.map((item) => { 10 | if (typeof item === 'string') { 11 | return (p) => item === p; 12 | } else if (item instanceof RegExp) { 13 | return (p) => item.test(p); 14 | } else { 15 | return item; 16 | } 17 | }); 18 | } 19 | 20 | export function applySkipList( 21 | normalizedSkip: NormalizedSkipList, 22 | shared: SharedObject 23 | ) { 24 | const filtered: SharedObject = {}; 25 | for (const key in shared) { 26 | if (!normalizedSkip.find((f) => f(key))) { 27 | filtered[key] = shared[key]; 28 | } 29 | } 30 | return filtered; 31 | } 32 | -------------------------------------------------------------------------------- /libs/mf/src/webpack.ts: -------------------------------------------------------------------------------- 1 | export * from './utils/shared-mappings'; 2 | export * from './utils/share-utils'; 3 | export * from './utils/with-mf-plugin'; 4 | -------------------------------------------------------------------------------- /libs/mf/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "forceConsistentCasingInFileNames": true, 6 | // "strict": true, 7 | "noImplicitOverride": true, 8 | "noPropertyAccessFromIndexSignature": true, 9 | "noImplicitReturns": true, 10 | "noFallthroughCasesInSwitch": true 11 | }, 12 | "files": [], 13 | "include": [], 14 | "references": [ 15 | { 16 | "path": "./tsconfig.lib.json" 17 | }, 18 | { 19 | "path": "./tsconfig.spec.json" 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /libs/mf/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": ["node"] 7 | }, 8 | "include": ["**/*.ts"], 9 | "exclude": ["jest.config.ts", "**/*.spec.ts", "**/*.test.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /libs/mf/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "src/**/*.test.ts", 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /libs/mf/tutorial/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "spellright.language": ["en"], 3 | "spellright.documentTypes": ["markdown", "latex", "plaintext"] 4 | } 5 | -------------------------------------------------------------------------------- /libs/mf/tutorial/braindump-ssr.md: -------------------------------------------------------------------------------- 1 | ## Adding Angular Universal to an Module Federation Project 2 | 3 | This brain dump shows how to add Angular Universal to our [example](https://github.com/manfredsteyer/module-federation-plugin-example). 4 | 5 | ``` 6 | npm i @angular-architects/module-federation@latest --registry http://localhost:4873 7 | 8 | 9 | ng g @angular-architects/module-federation:boot-async false --project shell 10 | ng add @nguniversal/common --project shell 11 | ng g @angular-architects/module-federation:boot-async true --project shell 12 | ng g @angular-architects/module-federation:nguniversal --project shell 13 | 14 | 15 | ng g @angular-architects/module-federation:boot-async false --project mfe1 16 | ng add @nguniversal/common --project mfe1 17 | ng g @angular-architects/module-federation:boot-async true --project mfe1 18 | ng g @angular-architects/module-federation:nguniversal --project mfe1 19 | 20 | 21 | Adjust projects\shell\src\server.ts 22 | const PORT = 5000; 23 | 24 | Adjust projects\mfe1\src\server.ts 25 | const PORT = 3000; 26 | 27 | 28 | ng build mfe1 && ng run mfe1:server 29 | node dist/mfe1/server/main.js 30 | 31 | ng build shell && ng run shell:server 32 | node dist/shell/server/main.js 33 | ``` 34 | -------------------------------------------------------------------------------- /libs/mf/tutorial/mfe1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-architects/module-federation-plugin/31c8117df81fe7e8be388839a92cf369bd47eed9/libs/mf/tutorial/mfe1.png -------------------------------------------------------------------------------- /libs/mf/tutorial/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-architects/module-federation-plugin/31c8117df81fe7e8be388839a92cf369bd47eed9/libs/mf/tutorial/result.png -------------------------------------------------------------------------------- /libs/mf/tutorial/shell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-architects/module-federation-plugin/31c8117df81fe7e8be388839a92cf369bd47eed9/libs/mf/tutorial/shell.png -------------------------------------------------------------------------------- /libs/mf/webpack.ts: -------------------------------------------------------------------------------- 1 | export * from './src/webpack'; 2 | -------------------------------------------------------------------------------- /libs/native-federation-core/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.base.json"], 3 | "ignorePatterns": ["!**/*", "src/lib/core/build-adapter.js"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | }, 17 | { 18 | "files": ["*.json"], 19 | "parser": "jsonc-eslint-parser", 20 | "rules": { 21 | "@nx/dependency-checks": "warn" 22 | } 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /libs/native-federation-core/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Softarc Consulting GmbH 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /libs/native-federation-core/build.ts: -------------------------------------------------------------------------------- 1 | export * from './src/build'; 2 | -------------------------------------------------------------------------------- /libs/native-federation-core/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'native-federation-core', 4 | preset: '../../jest.preset.js', 5 | testEnvironment: 'node', 6 | transform: { 7 | '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], 8 | }, 9 | moduleFileExtensions: ['ts', 'js', 'html'], 10 | coverageDirectory: '../../coverage/libs/native-federation-core', 11 | }; 12 | -------------------------------------------------------------------------------- /libs/native-federation-core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@softarc/native-federation", 3 | "version": "3.0.2", 4 | "type": "commonjs", 5 | "license": "MIT", 6 | "dependencies": { 7 | "json5": "^2.2.0", 8 | "chalk": "^4.1.2", 9 | "@softarc/native-federation-runtime": "3.0.2" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /libs/native-federation-core/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "native-federation-core", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "libs/native-federation-core/src", 5 | "projectType": "library", 6 | "targets": { 7 | "build": { 8 | "executor": "@nx/js:tsc", 9 | "outputs": ["{options.outputPath}"], 10 | "options": { 11 | "outputPath": "dist/libs/native-federation-core", 12 | "main": "libs/native-federation-core/src/index.ts", 13 | "tsConfig": "libs/native-federation-core/tsconfig.lib.json", 14 | "assets": [ 15 | "libs/native-federation-core/*.md", 16 | "libs/native-federation-core/LICENSE" 17 | ] 18 | } 19 | }, 20 | "publish": { 21 | "dependsOn": ["build"], 22 | "executor": "nx:run-commands", 23 | "options": { 24 | "command": "node tools/scripts/publish.mjs native-federation-core npm {args.ver} {args.tag}" 25 | } 26 | }, 27 | "publish-local": { 28 | "dependsOn": ["build"], 29 | "executor": "nx:run-commands", 30 | "options": { 31 | "command": "node tools/scripts/publish.mjs native-federation-core verdaccio {args.ver}" 32 | } 33 | } 34 | }, 35 | "tags": ["org:softarc", "scope:nf"] 36 | } 37 | -------------------------------------------------------------------------------- /libs/native-federation-core/src/config.ts: -------------------------------------------------------------------------------- 1 | // For parity with our other libs 2 | export * from './build'; 3 | -------------------------------------------------------------------------------- /libs/native-federation-core/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from '@softarc/native-federation-runtime'; 2 | -------------------------------------------------------------------------------- /libs/native-federation-core/src/lib/config/configuration-context.ts: -------------------------------------------------------------------------------- 1 | export interface ConfigurationContext { 2 | workspaceRoot?: string; 3 | packageJson?: string; 4 | } 5 | 6 | let _context: ConfigurationContext = {}; 7 | 8 | export function useWorkspace(workspaceRoot: string): void { 9 | _context = { ..._context, workspaceRoot }; 10 | } 11 | 12 | export function usePackageJson(packageJson?: string): void { 13 | _context = { ..._context, packageJson }; 14 | } 15 | 16 | export function getConfigContext(): ConfigurationContext { 17 | return _context; 18 | } 19 | -------------------------------------------------------------------------------- /libs/native-federation-core/src/lib/core/build-adapter.d.ts: -------------------------------------------------------------------------------- 1 | import { MappedPath } from '../utils/mapped-paths'; 2 | export type BuildKind = 'shared-package' | 'shared-mapping' | 'exposed' | 'mapping-or-exposed'; 3 | export interface EntryPoint { 4 | fileName: string; 5 | outName: string; 6 | } 7 | export interface BuildAdapterOptions { 8 | entryPoints: EntryPoint[]; 9 | tsConfigPath?: string; 10 | external: Array; 11 | outdir: string; 12 | mappedPaths: MappedPath[]; 13 | packageName?: string; 14 | esm?: boolean; 15 | dev?: boolean; 16 | watch?: boolean; 17 | kind: BuildKind; 18 | hash: boolean; 19 | } 20 | export interface BuildResult { 21 | fileName: string; 22 | } 23 | export type BuildAdapter = (options: BuildAdapterOptions) => Promise; 24 | export declare function setBuildAdapter(buildAdapter: BuildAdapter): void; 25 | export declare function getBuildAdapter(): BuildAdapter; 26 | -------------------------------------------------------------------------------- /libs/native-federation-core/src/lib/core/build-adapter.ts: -------------------------------------------------------------------------------- 1 | import { logger } from '../utils/logger'; 2 | import { MappedPath } from '../utils/mapped-paths'; 3 | 4 | let _buildAdapter: BuildAdapter = async () => { 5 | // TODO: add logger 6 | logger.error('Please set a BuildAdapter!'); 7 | return []; 8 | }; 9 | 10 | export type BuildKind = 11 | | 'shared-package' 12 | | 'shared-mapping' 13 | | 'exposed' 14 | | 'mapping-or-exposed'; 15 | 16 | export interface EntryPoint { 17 | fileName: string; 18 | outName: string; 19 | } 20 | 21 | export interface BuildAdapterOptions { 22 | entryPoints: EntryPoint[]; 23 | tsConfigPath?: string; 24 | external: Array; 25 | outdir: string; 26 | mappedPaths: MappedPath[]; 27 | packageName?: string; 28 | esm?: boolean; 29 | dev?: boolean; 30 | watch?: boolean; 31 | kind: BuildKind; 32 | hash: boolean; 33 | platform?: 'browser' | 'node'; 34 | } 35 | 36 | export interface BuildResult { 37 | fileName: string; 38 | } 39 | 40 | export type BuildAdapter = ( 41 | options: BuildAdapterOptions 42 | ) => Promise; 43 | 44 | export function setBuildAdapter(buildAdapter: BuildAdapter): void { 45 | _buildAdapter = buildAdapter; 46 | } 47 | 48 | export function getBuildAdapter(): BuildAdapter { 49 | return _buildAdapter; 50 | } 51 | -------------------------------------------------------------------------------- /libs/native-federation-core/src/lib/core/default-external-list.ts: -------------------------------------------------------------------------------- 1 | const NODE_PACKAGES = [ 2 | 'assert', 3 | 'buffer', 4 | 'child_process', 5 | 'cluster', 6 | 'crypto', 7 | 'dgram', 8 | 'dns', 9 | 'events', 10 | 'fs', 11 | 'http', 12 | 'https', 13 | 'module', 14 | 'net', 15 | 'os', 16 | 'path', 17 | 'querystring', 18 | 'readline', 19 | 'stream', 20 | 'timers', 21 | 'tls', 22 | 'tty', 23 | 'url', 24 | 'util', 25 | 'v8', 26 | 'vm', 27 | 'zlib', 28 | ]; 29 | 30 | export const DEFAULT_EXTERNAL_LIST = NODE_PACKAGES.flatMap((p) => [ 31 | p, 32 | 'node:' + p, 33 | ]); 34 | -------------------------------------------------------------------------------- /libs/native-federation-core/src/lib/core/default-server-deps-list.ts: -------------------------------------------------------------------------------- 1 | 2 | export const DEFAULT_SERVER_DEPS_LIST: string[] = [ 3 | '@angular/platform-server', 4 | '@angular/platform-server/init', 5 | '@angular/ssr', 6 | ]; 7 | 8 | export const DEFAULT_SERVER_DEPS_SET = new Set(DEFAULT_SERVER_DEPS_LIST); -------------------------------------------------------------------------------- /libs/native-federation-core/src/lib/core/federation-options.ts: -------------------------------------------------------------------------------- 1 | export interface FederationOptions { 2 | workspaceRoot: string; 3 | outputPath: string; 4 | federationConfig: string; 5 | tsConfig?: string; 6 | verbose?: boolean; 7 | dev?: boolean; 8 | watch?: boolean; 9 | packageJson?: string; 10 | } 11 | -------------------------------------------------------------------------------- /libs/native-federation-core/src/lib/core/get-externals.ts: -------------------------------------------------------------------------------- 1 | import { NormalizedFederationConfig } from '../config/federation-config'; 2 | 3 | export function getExternals(config: NormalizedFederationConfig) { 4 | const shared = Object.keys(config.shared); 5 | const sharedMappings = config.sharedMappings.map((m) => m.key); 6 | const externals = [...shared, ...sharedMappings, ...config.externals]; 7 | return externals; 8 | } 9 | -------------------------------------------------------------------------------- /libs/native-federation-core/src/lib/core/load-federation-config.ts: -------------------------------------------------------------------------------- 1 | import { NormalizedFederationConfig } from '../config/federation-config'; 2 | import { FederationOptions } from './federation-options'; 3 | import * as path from 'path'; 4 | import * as fs from 'fs'; 5 | 6 | export async function loadFederationConfig( 7 | fedOptions: FederationOptions 8 | ): Promise { 9 | const fullConfigPath = path.join( 10 | fedOptions.workspaceRoot, 11 | fedOptions.federationConfig 12 | ); 13 | 14 | if (!fs.existsSync(fullConfigPath)) { 15 | throw new Error('Expected ' + fullConfigPath); 16 | } 17 | 18 | const config = (await import(fullConfigPath)) as NormalizedFederationConfig; 19 | return config; 20 | } 21 | -------------------------------------------------------------------------------- /libs/native-federation-core/src/lib/core/write-federation-info.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as fs from 'fs'; 3 | import { FederationInfo } from '@softarc/native-federation-runtime'; 4 | import { FederationOptions } from './federation-options'; 5 | 6 | export function writeFederationInfo( 7 | federationInfo: FederationInfo, 8 | fedOptions: FederationOptions 9 | ) { 10 | const metaDataPath = path.join( 11 | fedOptions.workspaceRoot, 12 | fedOptions.outputPath, 13 | 'remoteEntry.json' 14 | ); 15 | fs.writeFileSync(metaDataPath, JSON.stringify(federationInfo, null, 2)); 16 | } 17 | -------------------------------------------------------------------------------- /libs/native-federation-core/src/lib/core/write-import-map.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as fs from 'fs'; 3 | import { SharedInfo } from '@softarc/native-federation-runtime'; 4 | import { FederationOptions } from './federation-options'; 5 | 6 | export function writeImportMap( 7 | sharedInfo: SharedInfo[], 8 | fedOption: FederationOptions 9 | ) { 10 | const imports = sharedInfo.reduce((acc, cur) => { 11 | return { 12 | ...acc, 13 | [cur.packageName]: cur.outFileName, 14 | }; 15 | }, {}); 16 | 17 | const importMap = { imports }; 18 | const importMapPath = path.join( 19 | fedOption.workspaceRoot, 20 | fedOption.outputPath, 21 | 'importmap.json' 22 | ); 23 | fs.writeFileSync(importMapPath, JSON.stringify(importMap, null, 2)); 24 | } 25 | -------------------------------------------------------------------------------- /libs/native-federation-core/src/lib/utils/build-result-map.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { BuildResult } from '../core/build-adapter'; 3 | 4 | export function createBuildResultMap( 5 | buildResult: BuildResult[], 6 | isHashed: boolean 7 | ): Record { 8 | const map: Record = {}; 9 | 10 | for (const item of buildResult) { 11 | const resultName = path.basename(item.fileName); 12 | let requestName = resultName; 13 | 14 | if (isHashed) { 15 | const start = resultName.lastIndexOf('-'); 16 | const end = resultName.lastIndexOf('.'); 17 | 18 | const part1 = resultName.substring(0, start); 19 | const part2 = resultName.substring(end); 20 | 21 | requestName = part1 + part2; 22 | } 23 | map[requestName] = resultName; 24 | } 25 | 26 | return map; 27 | } 28 | 29 | export function lookupInResultMap( 30 | map: Record, 31 | requestName: string 32 | ): string { 33 | const key = path.basename(requestName); 34 | return map[key]; 35 | } 36 | -------------------------------------------------------------------------------- /libs/native-federation-core/src/lib/utils/build-utils.ts: -------------------------------------------------------------------------------- 1 | import { BuildAdapterOptions, getBuildAdapter } from '../core/build-adapter'; 2 | 3 | export async function bundle(options: BuildAdapterOptions) { 4 | const adapter = getBuildAdapter(); 5 | return await adapter(options); 6 | } 7 | -------------------------------------------------------------------------------- /libs/native-federation-core/src/lib/utils/copy-src-map-if-exists.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | 3 | export function copySrcMapIfExists(cachedFile: string, fullOutputPath: string) { 4 | const mapSrc = cachedFile + '.map'; 5 | const mapDest = fullOutputPath + '.map'; 6 | 7 | if (fs.existsSync(mapSrc)) { 8 | fs.copyFileSync(mapSrc, mapDest); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /libs/native-federation-core/src/lib/utils/hash-file.ts: -------------------------------------------------------------------------------- 1 | import * as crypto from 'crypto'; 2 | import * as fs from 'fs'; 3 | 4 | export function hashFile(fileName: string): string { 5 | const fileBuffer = fs.readFileSync(fileName); 6 | const hashSum = crypto.createHash('md5'); 7 | hashSum.update(fileBuffer); 8 | return hashSum.digest('hex'); 9 | } 10 | -------------------------------------------------------------------------------- /libs/native-federation-core/src/lib/utils/logger.d.ts: -------------------------------------------------------------------------------- 1 | import { LogLevels } from 'npmlog'; 2 | export declare const logger: { 3 | error: (msg: any) => void; 4 | warn: (msg: any) => void; 5 | notice: (msg: any) => void; 6 | info: (msg: any) => void; 7 | verbose: (msg: any) => void; 8 | debug: (msg: any) => void; 9 | }; 10 | export declare const setLogLevel: (level: LogLevels | 'debug') => void; 11 | -------------------------------------------------------------------------------- /libs/native-federation-core/src/lib/utils/logger.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | 3 | import chalk from 'chalk'; 4 | 5 | let verbose = false; 6 | 7 | export const logger = { 8 | warn: (msg: any) => console.warn(chalk.bgYellow.ansi256(15)(' WARN '), msg), 9 | error: (msg: any) => console.error(chalk.bgRed.ansi256(15)(' ERRR '), msg), 10 | notice: (msg: any) => console.log(chalk.bgYellowBright.black(' NOTE '), msg), 11 | info: (msg: any) => console.log(chalk.bgGreen.ansi256(15)(' INFO '), msg), 12 | verbose: (msg: any) => 13 | verbose && console.log(chalk.bgGreen.ansi256(15)(' DBG! '), msg), 14 | debug: (msg: any) => 15 | verbose && console.log(chalk.bgGreen.ansi256(15)(' DBG! '), msg), 16 | }; 17 | 18 | export const setLogLevel = (level: string) => { 19 | verbose = level === 'verbose'; 20 | }; 21 | -------------------------------------------------------------------------------- /libs/native-federation-core/src/lib/utils/mapped-paths.d.ts: -------------------------------------------------------------------------------- 1 | export interface MappedPath { 2 | key: string; 3 | path: string; 4 | } 5 | export interface GetMappedPathsOptions { 6 | rootTsConfigPath: string; 7 | sharedMappings?: string[]; 8 | rootPath?: string; 9 | } 10 | export declare function getMappedPaths({ rootTsConfigPath, sharedMappings, rootPath, }: GetMappedPathsOptions): Array; 11 | -------------------------------------------------------------------------------- /libs/native-federation-core/src/lib/utils/mapped-paths.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"mapped-paths.js","sourceRoot":"","sources":["mapped-paths.ts"],"names":[],"mappings":";;;;AAAA,mDAA6B;AAC7B,+CAAyB;AACzB,qDAA+B;AAa/B,SAAgB,cAAc,CAAC,EAC7B,gBAAgB,EAChB,cAAc,EACd,QAAQ,GACc;;IACtB,MAAM,MAAM,GAAsB,EAAE,CAAC;IAErC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE;QACtC,MAAM,IAAI,KAAK,CACb,qEAAqE,CACtE,CAAC;KACH;IAED,IAAI,CAAC,QAAQ,EAAE;QACb,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC;KAC3D;IACD,MAAM,QAAQ,GAAG,CAAC,cAAc,CAAC;IAEjC,IAAI,CAAC,cAAc,EAAE;QACnB,cAAc,GAAG,EAAE,CAAC;KACrB;IAED,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAC1B,EAAE,CAAC,YAAY,CAAC,gBAAgB,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CACzD,CAAC;IAEF,MAAM,QAAQ,GAAG,MAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,eAAe,0CAAE,KAAK,CAAC;IAElD,IAAI,CAAC,QAAQ,EAAE;QACb,OAAO,MAAM,CAAC;KACf;IAED,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE;QAC1B,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAEtE,IAAI,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,QAAQ,EAAE;YAC5C,MAAM,CAAC,IAAI,CAAC;gBACV,GAAG;gBACH,IAAI,EAAE,OAAO;aACd,CAAC,CAAC;SACJ;KACF;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AA5CD,wCA4CC"} -------------------------------------------------------------------------------- /libs/native-federation-core/src/lib/utils/normalize.ts: -------------------------------------------------------------------------------- 1 | export function normalize(path: string, trailingSlash?: boolean): string { 2 | let cand = path.replace(/\\/g, '/'); 3 | 4 | if (typeof trailingSlash === 'undefined') { 5 | return cand; 6 | } 7 | 8 | while (cand.endsWith('/')) { 9 | cand = cand.substring(0, cand.length - 1); 10 | } 11 | 12 | if (trailingSlash) { 13 | return cand + '/'; 14 | } 15 | 16 | return cand; 17 | } 18 | -------------------------------------------------------------------------------- /libs/native-federation-core/src/lib/utils/resolve-glob.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | import * as path from 'path'; 3 | 4 | export function resolveGlobSync( 5 | pattern: string, 6 | baseDir = process.cwd() 7 | ): string[] { 8 | if (pattern.startsWith('./')) { 9 | pattern = pattern.substring(2); 10 | } 11 | 12 | const segments = pattern.split('/').filter(Boolean); 13 | const results: string[] = []; 14 | 15 | function search(dir: string, segmentIndex: number) { 16 | if (segmentIndex >= segments.length) { 17 | results.push(dir); 18 | return; 19 | } 20 | 21 | const segment = segments[segmentIndex]; 22 | const entries = fs.readdirSync(dir, { withFileTypes: true }); 23 | 24 | if (segment === '*') { 25 | entries 26 | .filter((entry) => entry.isDirectory()) 27 | .forEach((entry) => 28 | search(path.join(dir, entry.name), segmentIndex + 1) 29 | ); 30 | } else { 31 | entries 32 | .filter((entry) => entry.name === segment) 33 | .forEach((entry) => 34 | search(path.join(dir, entry.name), segmentIndex + 1) 35 | ); 36 | } 37 | } 38 | 39 | search(baseDir, 0); 40 | return results; 41 | } 42 | -------------------------------------------------------------------------------- /libs/native-federation-core/stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-architects/module-federation-plugin/31c8117df81fe7e8be388839a92cf369bd47eed9/libs/native-federation-core/stack.png -------------------------------------------------------------------------------- /libs/native-federation-core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "forceConsistentCasingInFileNames": true, 6 | "strict": true, 7 | "noImplicitOverride": true, 8 | "noPropertyAccessFromIndexSignature": true, 9 | "noImplicitReturns": true, 10 | "noFallthroughCasesInSwitch": true 11 | }, 12 | "files": [], 13 | "include": [], 14 | "references": [ 15 | { 16 | "path": "./tsconfig.lib.json" 17 | }, 18 | { 19 | "path": "./tsconfig.spec.json" 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /libs/native-federation-core/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": ["node"] 7 | }, 8 | "include": ["**/*.ts"], 9 | "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /libs/native-federation-core/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "src/**/*.test.ts", 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /libs/native-federation-esbuild/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.base.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | }, 17 | { 18 | "files": ["*.json"], 19 | "parser": "jsonc-eslint-parser", 20 | "rules": { 21 | "@nx/dependency-checks": "warn" 22 | } 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /libs/native-federation-esbuild/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Softarc Consulting GmbH 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /libs/native-federation-esbuild/README.md: -------------------------------------------------------------------------------- 1 | # native-federation-esbuild 2 | 3 | As Native Federation is tooling agnostic, we need an adapter to make it work with specific build tools. This library contains such an adapter for esbuild. 4 | -------------------------------------------------------------------------------- /libs/native-federation-esbuild/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'native-federation-esbuild', 4 | preset: '../../jest.preset.js', 5 | testEnvironment: 'node', 6 | transform: { 7 | '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], 8 | }, 9 | moduleFileExtensions: ['ts', 'js', 'html'], 10 | coverageDirectory: '../../coverage/libs/native-federation-esbuild', 11 | }; 12 | -------------------------------------------------------------------------------- /libs/native-federation-esbuild/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@softarc/native-federation-esbuild", 3 | "version": "3.0.2", 4 | "type": "commonjs", 5 | "dependencies": { 6 | "@rollup/plugin-commonjs": "^22.0.2", 7 | "@rollup/plugin-node-resolve": "^13.3.0", 8 | "@rollup/plugin-replace": "^4.0.0", 9 | "rollup": "^2.79.0", 10 | "rollup-plugin-node-externals": "^4.1.1", 11 | "esbuild": "^0.25.1", 12 | "signale": "^1.4.0", 13 | "acorn": "^8.8.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /libs/native-federation-esbuild/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "native-federation-esbuild", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "libs/native-federation-esbuild/src", 5 | "projectType": "library", 6 | "targets": { 7 | "build": { 8 | "executor": "@nx/js:tsc", 9 | "outputs": ["{options.outputPath}"], 10 | "options": { 11 | "outputPath": "dist/libs/native-federation-esbuild", 12 | "main": "libs/native-federation-esbuild/src/index.ts", 13 | "tsConfig": "libs/native-federation-esbuild/tsconfig.lib.json", 14 | "assets": [ 15 | "libs/native-federation-esbuild/*.md", 16 | "libs/native-federation-esbuild/LICENSE" 17 | ] 18 | } 19 | }, 20 | "publish": { 21 | "dependsOn": ["build"], 22 | "executor": "nx:run-commands", 23 | "options": { 24 | "command": "node tools/scripts/publish.mjs native-federation-esbuild npm {args.ver} {args.tag}" 25 | } 26 | }, 27 | "publish-local": { 28 | "dependsOn": ["build"], 29 | "executor": "nx:run-commands", 30 | "options": { 31 | "command": "node tools/scripts/publish.mjs native-federation-esbuild verdaccio {args.ver}" 32 | } 33 | } 34 | }, 35 | "tags": ["org:softarc", "scope:nf"] 36 | } 37 | -------------------------------------------------------------------------------- /libs/native-federation-esbuild/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/adapter'; 2 | -------------------------------------------------------------------------------- /libs/native-federation-esbuild/src/lib/react-replacements.ts: -------------------------------------------------------------------------------- 1 | import { ReplacementConfig } from './adapter'; 2 | 3 | export const reactReplacements: Record< 4 | string, 5 | Record 6 | > = { 7 | dev: { 8 | 'node_modules/react/index.js': { 9 | file: 'node_modules/react/cjs/react.development.js', 10 | }, 11 | 'node_modules/react/jsx-dev-runtime.js': { 12 | file: 'node_modules/react/cjs/react-jsx-dev-runtime.development.js', 13 | }, 14 | 'node_modules/react/jsx-runtime.js': { 15 | file: 'node_modules/react/cjs/react-jsx-runtime.development.js', 16 | }, 17 | 'node_modules/react-dom/index.js': { 18 | file: 'node_modules/react-dom/cjs/react-dom.development.js', 19 | }, 20 | }, 21 | prod: { 22 | 'node_modules/react/index.js': { 23 | file: 'node_modules/react/cjs/react.production.min.js', 24 | }, 25 | 'node_modules/react/jsx-dev-runtime.js': { 26 | file: 'node_modules/react/cjs/react-jsx-dev-runtime.production.min.js', 27 | }, 28 | 'node_modules/react/jsx-runtime.js': { 29 | file: 'node_modules/react/cjs/react-jsx-runtime.production.min.js', 30 | }, 31 | 'node_modules/react-dom/index.js': { 32 | file: 'node_modules/react-dom/cjs/react-dom.production.min.js', 33 | }, 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /libs/native-federation-esbuild/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "forceConsistentCasingInFileNames": true, 6 | // "strict": true, 7 | "noImplicitOverride": true, 8 | "noPropertyAccessFromIndexSignature": true, 9 | "noImplicitReturns": true, 10 | "noFallthroughCasesInSwitch": true 11 | }, 12 | "files": [], 13 | "include": [], 14 | "references": [ 15 | { 16 | "path": "./tsconfig.lib.json" 17 | }, 18 | { 19 | "path": "./tsconfig.spec.json" 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /libs/native-federation-esbuild/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": ["node"] 7 | }, 8 | "include": ["src/**/*.ts"], 9 | "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /libs/native-federation-esbuild/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "src/**/*.test.ts", 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /libs/native-federation-node/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.base.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | }, 17 | { 18 | "files": ["*.json"], 19 | "parser": "jsonc-eslint-parser", 20 | "rules": { 21 | "@nx/dependency-checks": "error" 22 | } 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /libs/native-federation-node/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Softarc Consulting GmbH 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /libs/native-federation-node/README.md: -------------------------------------------------------------------------------- 1 | # native-federation-node 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Building 6 | 7 | Run `nx build native-federation-node` to build the library. 8 | 9 | ## Running unit tests 10 | 11 | Run `nx test native-federation-node` to execute the unit tests via [Jest](https://jestjs.io). 12 | -------------------------------------------------------------------------------- /libs/native-federation-node/build/create-data-url.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | const loaderSource = '../src/lib/utils/import-map-loader.js'; 5 | const dataUrlFile = '../src/lib/utils/loader-as-data-url.js'; 6 | 7 | const filePath = path.resolve(__dirname, loaderSource); 8 | const fileContent = fs.readFileSync(filePath, 'utf8'); 9 | const base64Content = Buffer.from(fileContent).toString('base64'); 10 | 11 | const dataUrl = `data:text/javascript;base64,${base64Content}`; 12 | 13 | const outputPath = path.resolve(__dirname, dataUrlFile); 14 | fs.writeFileSync(outputPath, `export const resolver = "${base64Content}";\n`); 15 | 16 | console.log('Created data url for loader'); 17 | -------------------------------------------------------------------------------- /libs/native-federation-node/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'native-federation-node', 4 | preset: '../../jest.preset.js', 5 | testEnvironment: 'node', 6 | transform: { 7 | '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], 8 | }, 9 | moduleFileExtensions: ['ts', 'js', 'html'], 10 | coverageDirectory: '../../coverage/libs/native-federation-node', 11 | }; 12 | -------------------------------------------------------------------------------- /libs/native-federation-node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@softarc/native-federation-node", 3 | "version": "3.0.2", 4 | "license": "MIT" 5 | } 6 | -------------------------------------------------------------------------------- /libs/native-federation-node/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/node/init-node-federation'; 2 | -------------------------------------------------------------------------------- /libs/native-federation-node/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "ES2020", 5 | "target": "ES2020", 6 | "allowJs": true 7 | }, 8 | "files": [], 9 | "include": [], 10 | "references": [ 11 | { 12 | "path": "./tsconfig.lib.json" 13 | }, 14 | { 15 | "path": "./tsconfig.spec.json" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /libs/native-federation-node/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "ES2015", 5 | "target": "ES2015", 6 | "outDir": "../../dist/out-tsc", 7 | "declaration": true, 8 | "types": ["node"] 9 | }, 10 | "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"], 11 | "include": [ 12 | "src/**/*.ts", 13 | "src/lib/node/import-map-store.ts.bak", 14 | "src/lib/node/federation-resolver.ts.bak" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /libs/native-federation-node/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "src/**/*.test.ts", 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /libs/native-federation-runtime/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json", "../../.eslintrc.base.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "extends": [ 8 | "plugin:@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": "angularArchitects", 17 | "style": "camelCase" 18 | } 19 | ], 20 | "@angular-eslint/component-selector": [ 21 | "error", 22 | { 23 | "type": "element", 24 | "prefix": "angular-architects", 25 | "style": "kebab-case" 26 | } 27 | ] 28 | } 29 | }, 30 | { 31 | "files": ["*.html"], 32 | "extends": ["plugin:@nx/angular-template"], 33 | "rules": {} 34 | }, 35 | { 36 | "files": ["*.json"], 37 | "parser": "jsonc-eslint-parser", 38 | "rules": { 39 | "@nx/dependency-checks": "warn" 40 | } 41 | } 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /libs/native-federation-runtime/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Softarc Consulting GmbH 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /libs/native-federation-runtime/README.md: -------------------------------------------------------------------------------- 1 | # native-federation-runtime 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test native-federation-runtime3` to execute the unit tests. 8 | -------------------------------------------------------------------------------- /libs/native-federation-runtime/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'native-federation-runtime', 4 | preset: '../../jest.preset.js', 5 | setupFilesAfterEnv: ['/src/test-setup.ts'], 6 | coverageDirectory: '../../coverage/libs/native-federation-runtime', 7 | transform: { 8 | '^.+\\.(ts|mjs|js|html)$': [ 9 | 'jest-preset-angular', 10 | { 11 | tsconfig: '/tsconfig.spec.json', 12 | stringifyContentPathRegex: '\\.(html|svg)$', 13 | }, 14 | ], 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/native-federation-runtime/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../dist/libs/native-federation-runtime", 4 | "lib": { 5 | "entryFile": "src/index.ts" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /libs/native-federation-runtime/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@softarc/native-federation-runtime", 3 | "version": "3.0.2", 4 | "dependencies": { 5 | "tslib": "^2.3.0" 6 | }, 7 | "devDependencies": { 8 | "@types/node": "^22.5.4" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /libs/native-federation-runtime/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "native-federation-runtime", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "projectType": "library", 5 | "sourceRoot": "libs/native-federation-runtime/src", 6 | "prefix": "angular-architects", 7 | "targets": { 8 | "build": { 9 | "executor": "@nx/angular:package", 10 | "outputs": ["{workspaceRoot}/dist/{projectRoot}"], 11 | "options": { 12 | "project": "libs/native-federation-runtime/ng-package.json" 13 | }, 14 | "configurations": { 15 | "production": { 16 | "tsConfig": "libs/native-federation-runtime/tsconfig.lib.prod.json" 17 | }, 18 | "development": { 19 | "tsConfig": "libs/native-federation-runtime/tsconfig.lib.json" 20 | } 21 | }, 22 | "defaultConfiguration": "production" 23 | }, 24 | "publish": { 25 | "dependsOn": ["build"], 26 | "executor": "nx:run-commands", 27 | "options": { 28 | "command": "node tools/scripts/publish.mjs native-federation-runtime npm {args.ver} {args.tag}" 29 | } 30 | }, 31 | "publish-local": { 32 | "dependsOn": ["build"], 33 | "executor": "nx:run-commands", 34 | "options": { 35 | "command": "node tools/scripts/publish.mjs native-federation-runtime verdaccio {args.ver}" 36 | } 37 | } 38 | }, 39 | "tags": ["org:softarc", "scope:nf"] 40 | } 41 | -------------------------------------------------------------------------------- /libs/native-federation-runtime/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/init-federation'; 2 | export * from './lib/load-remote-module'; 3 | export * from './lib/model/federation-info'; 4 | export * from './lib/model/import-map'; 5 | export * from './lib/get-shared'; 6 | -------------------------------------------------------------------------------- /libs/native-federation-runtime/src/lib/model/externals.ts: -------------------------------------------------------------------------------- 1 | import { SharedInfo } from './federation-info'; 2 | import { globalCache } from './global-cache'; 3 | 4 | const externals = globalCache.externals; 5 | 6 | function getExternalKey(shared: SharedInfo) { 7 | return `${shared.packageName}@${shared.version}`; 8 | } 9 | 10 | export function getExternalUrl(shared: SharedInfo): string | undefined { 11 | const packageKey = getExternalKey(shared); 12 | return externals.get(packageKey); 13 | } 14 | 15 | export function setExternalUrl(shared: SharedInfo, url: string): void { 16 | const packageKey = getExternalKey(shared); 17 | externals.set(packageKey, url); 18 | } 19 | -------------------------------------------------------------------------------- /libs/native-federation-runtime/src/lib/model/federation-info.ts: -------------------------------------------------------------------------------- 1 | export type SharedInfo = { 2 | singleton: boolean; 3 | strictVersion: boolean; 4 | requiredVersion: string; 5 | version?: string; 6 | packageName: string; 7 | outFileName: string; 8 | dev?: { 9 | entryPoint: string; 10 | }; 11 | }; 12 | 13 | export interface ExposesInfo { 14 | key: string; 15 | outFileName: string; 16 | dev?: { 17 | entryPoint: string; 18 | }; 19 | } 20 | 21 | export interface FederationInfo { 22 | name: string; 23 | exposes: ExposesInfo[]; 24 | shared: SharedInfo[]; 25 | } 26 | 27 | export interface InitFederationOptions { 28 | cacheTag?: string; 29 | } 30 | 31 | export interface ProcessRemoteInfoOptions extends InitFederationOptions { 32 | throwIfRemoteNotFound: boolean; 33 | } 34 | -------------------------------------------------------------------------------- /libs/native-federation-runtime/src/lib/model/global-cache.ts: -------------------------------------------------------------------------------- 1 | import { Remote } from './remotes'; 2 | 3 | export const nfNamespace = '__NATIVE_FEDERATION__'; 4 | 5 | export type NfCache = { 6 | externals: Map; 7 | remoteNamesToRemote: Map; 8 | baseUrlToRemoteNames: Map; 9 | }; 10 | 11 | export type Global = { 12 | [nfNamespace]: NfCache; 13 | }; 14 | 15 | const global = globalThis as unknown as Global; 16 | 17 | global[nfNamespace] ??= { 18 | externals: new Map(), 19 | remoteNamesToRemote: new Map(), 20 | baseUrlToRemoteNames: new Map(), 21 | }; 22 | 23 | export const globalCache = global[nfNamespace]; 24 | -------------------------------------------------------------------------------- /libs/native-federation-runtime/src/lib/model/import-map.ts: -------------------------------------------------------------------------------- 1 | export type Imports = Record; 2 | 3 | export type Scopes = Record; 4 | 5 | export type ImportMap = { 6 | imports: Imports; 7 | scopes: Scopes; 8 | }; 9 | 10 | export function mergeImportMaps(map1: ImportMap, map2: ImportMap): ImportMap { 11 | return { 12 | imports: { ...map1.imports, ...map2.imports }, 13 | scopes: { ...map1.scopes, ...map2.scopes }, 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /libs/native-federation-runtime/src/lib/model/remotes.ts: -------------------------------------------------------------------------------- 1 | import { FederationInfo } from './federation-info'; 2 | import { globalCache } from './global-cache'; 3 | 4 | export type Remote = FederationInfo & { 5 | baseUrl: string; 6 | }; 7 | 8 | const remoteNamesToRemote = globalCache.remoteNamesToRemote; 9 | const baseUrlToRemoteNames = globalCache.baseUrlToRemoteNames; 10 | 11 | export function addRemote(remoteName: string, remote: Remote): void { 12 | remoteNamesToRemote.set(remoteName, remote); 13 | baseUrlToRemoteNames.set(remote.baseUrl, remoteName); 14 | } 15 | 16 | export function getRemoteNameByBaseUrl(baseUrl: string): string | undefined { 17 | return baseUrlToRemoteNames.get(baseUrl); 18 | } 19 | 20 | export function isRemoteInitialized(baseUrl: string): boolean { 21 | return baseUrlToRemoteNames.has(baseUrl); 22 | } 23 | 24 | export function getRemote(remoteName: string): Remote | undefined { 25 | return remoteNamesToRemote.get(remoteName); 26 | } 27 | 28 | export function hasRemote(remoteName: string): boolean { 29 | return remoteNamesToRemote.has(remoteName); 30 | } 31 | -------------------------------------------------------------------------------- /libs/native-federation-runtime/src/lib/test-setup.ts: -------------------------------------------------------------------------------- 1 | // @ts-expect-error https://thymikee.github.io/jest-preset-angular/docs/getting-started/test-environment 2 | globalThis.ngJest = { 3 | testEnvironmentOptions: { 4 | errorOnUnknownElements: true, 5 | errorOnUnknownProperties: true, 6 | }, 7 | }; 8 | import 'jest-preset-angular/setup-jest'; 9 | -------------------------------------------------------------------------------- /libs/native-federation-runtime/src/lib/utils/add-import-map.ts: -------------------------------------------------------------------------------- 1 | import { ImportMap } from '../model/import-map'; 2 | 3 | export function appendImportMap(importMap: ImportMap) { 4 | document.head.appendChild( 5 | Object.assign(document.createElement('script'), { 6 | type: 'importmap-shim', 7 | innerHTML: JSON.stringify(importMap), 8 | }) 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /libs/native-federation-runtime/src/lib/utils/path-utils.ts: -------------------------------------------------------------------------------- 1 | export function getDirectory(url: string) { 2 | const parts = url.split('/'); 3 | parts.pop(); 4 | return parts.join('/'); 5 | } 6 | 7 | export function joinPaths(path1: string, path2: string): string { 8 | while (path1.endsWith('/')) { 9 | path1 = path1.substring(0, path1.length - 1); 10 | } 11 | if (path2.startsWith('./')) { 12 | path2 = path2.substring(2, path2.length); 13 | } 14 | 15 | return `${path1}/${path2}`; 16 | } 17 | -------------------------------------------------------------------------------- /libs/native-federation-runtime/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | -------------------------------------------------------------------------------- /libs/native-federation-runtime/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "target": "es2022", 5 | "useDefineForClassFields": false, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitOverride": true, 9 | "esModuleInterop": true, 10 | "noPropertyAccessFromIndexSignature": true, 11 | "noImplicitReturns": true, 12 | "noFallthroughCasesInSwitch": true 13 | }, 14 | "files": [], 15 | "include": [], 16 | "references": [ 17 | { 18 | "path": "./tsconfig.lib.json" 19 | }, 20 | { 21 | "path": "./tsconfig.spec.json" 22 | } 23 | ], 24 | "angularCompilerOptions": { 25 | "enableI18nLegacyMessageIdFormat": false, 26 | "strictInjectionParameters": true, 27 | "strictInputAccessModifiers": true, 28 | "strictTemplates": true 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /libs/native-federation-runtime/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/**/*.spec.ts", 12 | "src/test-setup.ts", 13 | "jest.config.ts", 14 | "src/**/*.test.ts" 15 | ], 16 | "include": ["src/**/*.ts"] 17 | } 18 | -------------------------------------------------------------------------------- /libs/native-federation-runtime/tsconfig.lib.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.lib.json", 3 | "compilerOptions": { 4 | "declarationMap": false 5 | }, 6 | "angularCompilerOptions": { 7 | "compilationMode": "partial" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /libs/native-federation-runtime/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "target": "es2016", 7 | "types": ["jest", "node"] 8 | }, 9 | "files": ["src/test-setup.ts"], 10 | "include": [ 11 | "jest.config.ts", 12 | "src/**/*.test.ts", 13 | "src/**/*.spec.ts", 14 | "src/**/*.d.ts" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /libs/native-federation/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.base.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | }, 17 | { 18 | "files": ["*.json"], 19 | "parser": "jsonc-eslint-parser", 20 | "rules": { 21 | "@nx/dependency-checks": "warn" 22 | } 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /libs/native-federation/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Softarc Consulting GmbH 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /libs/native-federation/builders.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/@angular-devkit/architect/src/builders-schema.json", 3 | "builders": { 4 | "build": { 5 | "implementation": "./src/builders/build/builder", 6 | "schema": "./src/builders/build/schema.json", 7 | "description": "native federation builder" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /libs/native-federation/collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/@angular-devkit/schematics/collection-schema.json", 3 | "name": "native-federation", 4 | "version": "0.0.1", 5 | "schematics": { 6 | "ng-add": { 7 | "factory": "./src/schematics/init/schematic", 8 | "schema": "./src/schematics/init/schema.json", 9 | "description": "Initialize an angular project for native federation" 10 | }, 11 | "init": { 12 | "factory": "./src/schematics/init/schematic", 13 | "schema": "./src/schematics/init/schema.json", 14 | "description": "Initialize an angular project for native federation" 15 | }, 16 | "remove": { 17 | "factory": "./src/schematics/remove/schematic", 18 | "schema": "./src/schematics/remove/schema.json", 19 | "description": "Removes native federation" 20 | }, 21 | "appbuilder": { 22 | "factory": "./src/schematics/appbuilder/schematic", 23 | "schema": "./src/schematics/appbuilder/schema.json", 24 | "description": "Migrates for using the appbuilder" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /libs/native-federation/config.ts: -------------------------------------------------------------------------------- 1 | export * from './src/config'; 2 | -------------------------------------------------------------------------------- /libs/native-federation/demo-repo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-architects/module-federation-plugin/31c8117df81fe7e8be388839a92cf369bd47eed9/libs/native-federation/demo-repo.png -------------------------------------------------------------------------------- /libs/native-federation/docs/update18.md: -------------------------------------------------------------------------------- 1 | # Update to Native Federation for Angular 18 2 | 3 | The package `@angular-architects/native-federation` version 18 was successfully tested with Angular 18. 4 | 5 | ## Option 1 6 | 7 | Just use `ng update`: 8 | 9 | ``` 10 | ng update @angular-architects/native-federation 11 | ``` 12 | 13 | ## Option 2 14 | 15 | Use npm install: 16 | 17 | ``` 18 | npm i @angular-architects/native-federation@^18 19 | ``` 20 | -------------------------------------------------------------------------------- /libs/native-federation/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angular-architects/module-federation-plugin/31c8117df81fe7e8be388839a92cf369bd47eed9/libs/native-federation/example.png -------------------------------------------------------------------------------- /libs/native-federation/executors.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "executors": { 4 | "build": { 5 | "implementation": "./src/executors/build/executor", 6 | "schema": "./src/executors/build/schema.json", 7 | "description": "build executor" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /libs/native-federation/generators.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "name": "native-federation", 4 | "version": "0.0.1", 5 | "generators": { 6 | "native-federation": { 7 | "factory": "./src/generators/native-federation/generator", 8 | "schema": "./src/generators/native-federation/schema.json", 9 | "description": "native-federation generator" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /libs/native-federation/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'native-federation', 4 | preset: '../../jest.preset.js', 5 | testEnvironment: 'node', 6 | transform: { 7 | '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], 8 | }, 9 | moduleFileExtensions: ['ts', 'js', 'html'], 10 | coverageDirectory: '../../coverage/libs/native-federation', 11 | }; 12 | -------------------------------------------------------------------------------- /libs/native-federation/migration-collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/@angular-devkit/schematics/collection-schema.json", 3 | "name": "native-federation", 4 | "version": "0.0.1", 5 | "schematics": { 6 | "update18": { 7 | "version": "18", 8 | "factory": "./src/schematics/update18/schematic", 9 | "schema": "./src/schematics/update18/schema.json", 10 | "description": "migrating to v18" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /libs/native-federation/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@angular-architects/native-federation", 3 | "version": "20.0.1", 4 | "main": "src/index.js", 5 | "generators": "./collection.json", 6 | "builders": "./builders.json", 7 | "schematics": "./collection.json", 8 | "license": "MIT", 9 | "author": { 10 | "name": "Manfred Steyer", 11 | "url": "http://www.angulararchitects.io" 12 | }, 13 | "homepage": "https://github.com/angular-architects/module-federation-plugin/tree/main/libs/native-federation", 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/angular-architects/module-federation-plugin" 17 | }, 18 | "ng-update": { 19 | "migrations": "./migration-collection.json" 20 | }, 21 | "dependencies": { 22 | "@babel/core": "^7.19.0", 23 | "@softarc/native-federation": "3.0.2", 24 | "@softarc/native-federation-runtime": "3.0.2", 25 | "@chialab/esbuild-plugin-commonjs": "^0.18.0", 26 | "esbuild": "^0.25.1", 27 | "mrmime": "^1.0.1", 28 | "signale": "^1.4.0", 29 | "process": "0.11.10" 30 | }, 31 | "peerDependencies": {} 32 | } 33 | -------------------------------------------------------------------------------- /libs/native-federation/post-build.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | const index = fs.readFileSync(path.join(__dirname, 'src/index.ts'), { 5 | encoding: 'utf-8', 6 | }); 7 | fs.writeFileSync( 8 | path.join(__dirname, '../../dist/libs/native-federation/src/index.js'), 9 | index 10 | ); 11 | -------------------------------------------------------------------------------- /libs/native-federation/src/builders/build/schema.d.ts: -------------------------------------------------------------------------------- 1 | import { JsonObject } from '@angular-devkit/core'; 2 | import type { ESMSInitOptions } from 'es-module-shims'; 3 | 4 | export interface NfBuilderSchema extends JsonObject { 5 | target: string; 6 | dev: boolean; 7 | port: number; 8 | open: boolean; 9 | rebuildDelay: number; 10 | shell: string; 11 | watch: boolean; 12 | skipHtmlTransform: boolean; 13 | esmsInitOptions: ESMSInitOptions; 14 | baseHref?: string; 15 | outputPath?: string; 16 | ssr: boolean; 17 | devServer?: boolean; 18 | } // eslint-disable-line 19 | -------------------------------------------------------------------------------- /libs/native-federation/src/config.ts: -------------------------------------------------------------------------------- 1 | export { withNativeFederation } from '@softarc/native-federation/build'; 2 | export { 3 | findRootTsConfigJson, 4 | share, 5 | shareAll, 6 | DEFAULT_SKIP_LIST, 7 | } from '@softarc/native-federation/build'; 8 | 9 | export { shareAngularLocales } from './utils/angular-locales'; 10 | -------------------------------------------------------------------------------- /libs/native-federation/src/executors/build/executor.spec.ts: -------------------------------------------------------------------------------- 1 | import { BuildExecutorSchema } from './schema'; 2 | import executor from './executor'; 3 | 4 | const options: BuildExecutorSchema = {}; 5 | 6 | describe('Build Executor', () => { 7 | it('can run', async () => { 8 | const output = await executor(options, {}); 9 | expect(output.success).toBe(true); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /libs/native-federation/src/executors/build/executor.ts: -------------------------------------------------------------------------------- 1 | import { BuildExecutorSchema } from './schema'; 2 | 3 | export default async function runExecutor( 4 | options: BuildExecutorSchema, 5 | nowos: unknown 6 | ) { 7 | console.log('Executor ran for Build', options, nowos); 8 | 9 | return { 10 | success: true, 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /libs/native-federation/src/executors/build/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface BuildExecutorSchema {} // eslint-disable-line 2 | -------------------------------------------------------------------------------- /libs/native-federation/src/executors/build/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "cli": "nx", 4 | "title": "Build executor", 5 | "description": "", 6 | "type": "object", 7 | "properties": {}, 8 | "required": [] 9 | } 10 | -------------------------------------------------------------------------------- /libs/native-federation/src/generators/native-federation/files/src/index.ts__template__: -------------------------------------------------------------------------------- 1 | const variable = "<%= projectName %>"; -------------------------------------------------------------------------------- /libs/native-federation/src/generators/native-federation/generator.spec.ts: -------------------------------------------------------------------------------- 1 | import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; 2 | import { Tree, readProjectConfiguration } from '@nx/devkit'; 3 | 4 | import generator from './generator'; 5 | import { NativeFederationGeneratorSchema } from './schema'; 6 | 7 | describe('native-federation generator', () => { 8 | let appTree: Tree; 9 | const options: NativeFederationGeneratorSchema = { name: 'test' }; 10 | 11 | beforeEach(() => { 12 | appTree = createTreeWithEmptyWorkspace(); 13 | }); 14 | 15 | it('should run successfully', async () => { 16 | await generator(appTree, options); 17 | const config = readProjectConfiguration(appTree, 'test'); 18 | expect(config).toBeDefined(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /libs/native-federation/src/generators/native-federation/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface NativeFederationGeneratorSchema { 2 | name: string; 3 | tags?: string; 4 | directory?: string; 5 | } 6 | -------------------------------------------------------------------------------- /libs/native-federation/src/generators/native-federation/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "cli": "nx", 4 | "$id": "NativeFederation", 5 | "title": "", 6 | "type": "object", 7 | "properties": { 8 | "name": { 9 | "type": "string", 10 | "description": "", 11 | "$default": { 12 | "$source": "argv", 13 | "index": 0 14 | }, 15 | "x-prompt": "What name would you like to use?" 16 | }, 17 | "tags": { 18 | "type": "string", 19 | "description": "Add tags to the project (used for linting)", 20 | "alias": "t" 21 | }, 22 | "directory": { 23 | "type": "string", 24 | "description": "A directory where the project is placed", 25 | "alias": "d" 26 | } 27 | }, 28 | "required": ["name"] 29 | } 30 | -------------------------------------------------------------------------------- /libs/native-federation/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from '@softarc/native-federation-runtime'; 2 | -------------------------------------------------------------------------------- /libs/native-federation/src/patch-angular-build.ts: -------------------------------------------------------------------------------- 1 | // import { patchAngularBuild } from './utils/patch-angular-build'; 2 | 3 | // const workspaceRoot = process.cwd(); 4 | // patchAngularBuild(workspaceRoot); 5 | 6 | console.log( 7 | 'Please remove the postbuild task calling patch-angular-build. This is not needed since Native Federation 18.1 anymore!' 8 | ); 9 | -------------------------------------------------------------------------------- /libs/native-federation/src/plugin/dev-externals-mixin.ts: -------------------------------------------------------------------------------- 1 | import { federationBuilder } from '@softarc/native-federation/build'; 2 | import { filterExternals } from './externals-skip-list'; 3 | 4 | // see: https://github.com/vitejs/vite/issues/6393#issuecomment-1006819717 5 | 6 | export const devExternalsMixin = { 7 | enforce: 'pre', 8 | config(config) { 9 | config.optimizeDeps = { 10 | ...(config.optimizeDeps ?? {}), 11 | exclude: [ 12 | ...(config.optimizeDeps?.exclude ?? []), 13 | ...filterExternals(federationBuilder.externals), 14 | ], 15 | }; 16 | }, 17 | configResolved(resolvedConfig) { 18 | const VALID_ID_PREFIX = `/@id/`; 19 | const reg = new RegExp( 20 | `${VALID_ID_PREFIX}(${federationBuilder.externals.join('|')})`, 21 | 'g' 22 | ); 23 | resolvedConfig.plugins.push({ 24 | name: 'vite-plugin-ignore-static-import-replace-idprefix', 25 | transform: (code) => 26 | reg.test(code) ? code.replace(reg, (m, s1) => s1) : code, 27 | }); 28 | }, 29 | resolveId: (id) => { 30 | if (filterExternals(federationBuilder.externals).includes(id)) { 31 | return { id, external: true }; 32 | } 33 | }, 34 | } as any; 35 | -------------------------------------------------------------------------------- /libs/native-federation/src/plugin/externals-skip-list.ts: -------------------------------------------------------------------------------- 1 | export const externalsSkipList = new Set(['tslib']); 2 | 3 | export function filterExternals(deps: string[]): string[] { 4 | return deps.filter((d) => !externalsSkipList.has(d)); 5 | } 6 | -------------------------------------------------------------------------------- /libs/native-federation/src/schematics/appbuilder/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface MfSchematicSchema { 2 | project: string; 3 | } 4 | -------------------------------------------------------------------------------- /libs/native-federation/src/schematics/appbuilder/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "$id": "mf", 4 | "title": "", 5 | "type": "object", 6 | "properties": { 7 | "project": { 8 | "type": "string", 9 | "description": "The project to add module federation", 10 | "$default": { 11 | "$source": "argv", 12 | "index": 0 13 | }, 14 | "x-prompt": "Project name (press enter for default project)" 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /libs/native-federation/src/schematics/init/files/federation.config.js__tmpl__: -------------------------------------------------------------------------------- 1 | const { withNativeFederation, shareAll } = require('@angular-architects/native-federation/config'); 2 | 3 | module.exports = withNativeFederation({ 4 | <% if (type === 'remote') { %> 5 | name: '<%=project%>', 6 | 7 | exposes: { 8 | './Component': './<%=appComponentPath%>', 9 | }, 10 | <% } %> 11 | shared: { 12 | ...shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }), 13 | }, 14 | 15 | skip: [ 16 | 'rxjs/ajax', 17 | 'rxjs/fetch', 18 | 'rxjs/testing', 19 | 'rxjs/webSocket', 20 | // Add further packages you don't need at runtime 21 | ] 22 | 23 | // Please read our FAQ about sharing libs: 24 | // https://shorturl.at/jmzH0 25 | 26 | }); 27 | -------------------------------------------------------------------------------- /libs/native-federation/src/schematics/init/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface MfSchematicSchema { 2 | project: string; 3 | port: string; 4 | nxBuilders: boolean | undefined; 5 | type: 'host' | 'dynamic-host' | 'remote'; 6 | } 7 | -------------------------------------------------------------------------------- /libs/native-federation/src/schematics/init/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "$id": "mf", 4 | "title": "", 5 | "type": "object", 6 | "properties": { 7 | "project": { 8 | "type": "string", 9 | "description": "The project to add module federation", 10 | "$default": { 11 | "$source": "argv", 12 | "index": 0 13 | }, 14 | "x-prompt": "Project name (press enter for default project)" 15 | }, 16 | "port": { 17 | "type": "number", 18 | "description": "The port to use for the federated module (remote, micro frontend, etc.)", 19 | "$default": { 20 | "$source": "argv", 21 | "index": 1 22 | } 23 | }, 24 | "type": { 25 | "enum": ["host", "dynamic-host", "remote"], 26 | "type": "string", 27 | "default": "remote" 28 | }, 29 | "nxBuilders": { 30 | "type": "boolean", 31 | "description": "Use builders provided by Nx instead of ngx-build-plus? Defaults to true for Nx workspaces and false for CLI workspaces." 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /libs/native-federation/src/schematics/remove/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface MfSchematicSchema { 2 | project: string; 3 | } 4 | -------------------------------------------------------------------------------- /libs/native-federation/src/schematics/remove/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "$id": "mf", 4 | "title": "", 5 | "type": "object", 6 | "properties": { 7 | "project": { 8 | "type": "string", 9 | "description": "The project to add module federation", 10 | "$default": { 11 | "$source": "argv", 12 | "index": 0 13 | }, 14 | "x-prompt": "Project name (press enter for default project)" 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /libs/native-federation/src/schematics/update18/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "$id": "mf", 4 | "title": "", 5 | "type": "object", 6 | "properties": {} 7 | } 8 | -------------------------------------------------------------------------------- /libs/native-federation/src/schematics/update18/schematic.ts: -------------------------------------------------------------------------------- 1 | import { Rule, Tree } from '@angular-devkit/schematics'; 2 | 3 | import { patchAngularBuild, updatePackageJson } from '../init/schematic'; 4 | 5 | export default function update18(): Rule { 6 | return async function (tree: Tree) { 7 | updatePackageJson(tree); 8 | patchAngularBuild(tree); 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /libs/native-federation/src/utils/angular-locales.ts: -------------------------------------------------------------------------------- 1 | import { share, SharedConfig } from '@softarc/native-federation/build'; 2 | 3 | export function shareAngularLocales( 4 | keys, 5 | config: SharedConfig = { 6 | singleton: true, 7 | strictVersion: true, 8 | requiredVersion: 'auto', 9 | } 10 | ) { 11 | return keys.reduce((acc, key) => { 12 | acc[`@angular/common/locales/${key}`] = { 13 | ...config, 14 | packageInfo: config.packageInfo || { 15 | ...config.packageInfo, 16 | entryPoint: 17 | config.packageInfo?.entryPoint || 18 | `node_modules/@angular/common/locales/${key}.mjs`, 19 | }, 20 | }; 21 | return share(acc); 22 | }, {}); 23 | } 24 | -------------------------------------------------------------------------------- /libs/native-federation/src/utils/event-sorce.ts: -------------------------------------------------------------------------------- 1 | export type EventHandler = () => Promise; 2 | 3 | export interface EventSource { 4 | register(handler: EventHandler): void; 5 | } 6 | 7 | export class EventHub implements EventSource { 8 | private handlers: EventHandler[] = []; 9 | 10 | register(handler: EventHandler): void { 11 | this.handlers.push(handler); 12 | } 13 | 14 | async emit(): Promise { 15 | const promises = this.handlers.map((h) => h()); 16 | await Promise.all(promises); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /libs/native-federation/src/utils/patch-angular-build.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as fs from 'fs'; 3 | 4 | export const privateEntrySrc = ` 5 | exports = require('./src/private.js'); 6 | `; 7 | 8 | export function patchAngularBuildPackageJson(packageJson: unknown): void { 9 | const exportsMap = packageJson['exports']; 10 | 11 | if (!exportsMap) { 12 | console.log('No need to patch @angular/build/package.json'); 13 | return; 14 | } 15 | 16 | packageJson['_exports'] = exportsMap; 17 | delete packageJson['exports']; 18 | 19 | packageJson['types'] = './src/index.d.ts'; 20 | packageJson['main'] = './src/index.js'; 21 | packageJson['module'] = './src/index.js'; 22 | } 23 | 24 | export function patchAngularBuild(workspaceRoot: string): void { 25 | const packagePath = path.join( 26 | workspaceRoot, 27 | 'node_modules/@angular/build/package.json' 28 | ); 29 | 30 | const privatePath = path.join( 31 | workspaceRoot, 32 | 'node_modules/@angular/build/private.js' 33 | ); 34 | 35 | if (!fs.existsSync(packagePath)) { 36 | return; 37 | } 38 | 39 | const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf-8')); 40 | 41 | patchAngularBuildPackageJson(packageJson); 42 | 43 | fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2)); 44 | fs.writeFileSync(privatePath, privateEntrySrc); 45 | 46 | console.log('@angular/build/package.json patched'); 47 | } 48 | -------------------------------------------------------------------------------- /libs/native-federation/src/utils/rebuild-events.ts: -------------------------------------------------------------------------------- 1 | import { EventHub, EventSource } from './event-sorce'; 2 | 3 | export interface RebuildEvents { 4 | readonly rebuild: EventSource; 5 | } 6 | 7 | export class RebuildHubs implements RebuildEvents { 8 | readonly rebuild = new EventHub(); 9 | } 10 | -------------------------------------------------------------------------------- /libs/native-federation/src/utils/shared-mappings-plugin.ts: -------------------------------------------------------------------------------- 1 | import { Plugin, PluginBuild } from 'esbuild'; 2 | import * as path from 'path'; 3 | import { MappedPath } from '@softarc/native-federation/build'; 4 | 5 | export function createSharedMappingsPlugin(mappedPaths: MappedPath[]): Plugin { 6 | return { 7 | name: 'custom', 8 | setup(build: PluginBuild) { 9 | build.onResolve({ filter: /^[.]/ }, async (args) => { 10 | let mappedPath: MappedPath | null = null; 11 | let isSelf = false; 12 | 13 | if (args.kind === 'import-statement') { 14 | const importPath = path.join(args.resolveDir, args.path); 15 | mappedPath = mappedPaths.find((p) => 16 | importPath.startsWith(path.dirname(p.path)) 17 | ); 18 | } 19 | 20 | if (mappedPath) { 21 | isSelf = args.importer.startsWith(path.dirname(mappedPath.path)); 22 | } 23 | 24 | if (mappedPath && !isSelf) { 25 | return { 26 | path: mappedPath.key, 27 | external: true, 28 | }; 29 | } 30 | 31 | return {}; 32 | }); 33 | }, 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /libs/native-federation/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "NodeNext", 5 | "moduleResolution": "NodeNext", 6 | "forceConsistentCasingInFileNames": true, 7 | "allowJs": true, 8 | // "strict": true, 9 | "noImplicitOverride": true, 10 | "noPropertyAccessFromIndexSignature": true, 11 | // "noImplicitReturns": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "types": ["node"] 14 | }, 15 | "files": [], 16 | "include": [], 17 | "references": [ 18 | { 19 | "path": "./tsconfig.lib.json" 20 | }, 21 | { 22 | "path": "./tsconfig.spec.json" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /libs/native-federation/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "composite": true, 5 | "outDir": "../../dist/out-tsc", 6 | "declaration": true, 7 | "types": ["node"] 8 | }, 9 | "include": ["**/*.ts", "**/*.js"], 10 | "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /libs/native-federation/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "composite": true, 5 | "outDir": "../../dist/out-tsc", 6 | "module": "commonjs", 7 | "types": ["jest", "node"] 8 | }, 9 | "include": [ 10 | "jest.config.ts", 11 | "src/**/*.test.ts", 12 | "src/**/*.spec.ts", 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /libs/playground-lib/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts"], 7 | "extends": [ 8 | "plugin:@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": "angularArchitects", 17 | "style": "camelCase" 18 | } 19 | ], 20 | "@angular-eslint/component-selector": [ 21 | "error", 22 | { 23 | "type": "element", 24 | "prefix": "angular-architects", 25 | "style": "kebab-case" 26 | } 27 | ], 28 | "@angular-eslint/prefer-standalone": "off" 29 | } 30 | }, 31 | { 32 | "files": ["*.html"], 33 | "extends": ["plugin:@nx/angular-template"], 34 | "rules": {} 35 | } 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /libs/playground-lib/README.md: -------------------------------------------------------------------------------- 1 | # playground-lib 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test playground-lib` to execute the unit tests. 8 | -------------------------------------------------------------------------------- /libs/playground-lib/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'playground-lib', 4 | preset: '../../jest.preset.js', 5 | setupFilesAfterEnv: ['/src/test-setup.ts'], 6 | globals: {}, 7 | coverageDirectory: '../../coverage/libs/playground-lib', 8 | transform: { 9 | '^.+\\.(ts|mjs|js|html)$': [ 10 | 'jest-preset-angular', 11 | { 12 | tsconfig: '/tsconfig.spec.json', 13 | stringifyContentPathRegex: '\\.(html|svg)$', 14 | }, 15 | ], 16 | }, 17 | transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], 18 | snapshotSerializers: [ 19 | 'jest-preset-angular/build/serializers/no-ng-attributes', 20 | 'jest-preset-angular/build/serializers/ng-snapshot', 21 | 'jest-preset-angular/build/serializers/html-comment', 22 | ], 23 | }; 24 | -------------------------------------------------------------------------------- /libs/playground-lib/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "playground-lib", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "projectType": "library", 5 | "sourceRoot": "libs/playground-lib/src", 6 | "prefix": "angular-architects", 7 | "targets": {}, 8 | "tags": [] 9 | } 10 | -------------------------------------------------------------------------------- /libs/playground-lib/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/playground-lib.module'; 2 | export * from './lib/auth.service'; 3 | export * from './lib/auth.component'; 4 | -------------------------------------------------------------------------------- /libs/playground-lib/src/lib/auth.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { AuthService } from './auth.service'; 3 | 4 | @Component({ 5 | selector: 'angular-architects-auth', 6 | template: ` 7 |

AuthComponent

8 |

User Name: {{ userName }}

9 | `, 10 | styles: [ 11 | ` 12 | p { 13 | color: blue; 14 | } 15 | `, 16 | ], 17 | }) 18 | export class AuthComponent { 19 | userName = ''; 20 | 21 | constructor(authService: AuthService) { 22 | this.userName = authService.userName; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /libs/playground-lib/src/lib/auth.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | @Injectable({ providedIn: 'root' }) 4 | export class AuthService { 5 | userName = ''; 6 | } 7 | -------------------------------------------------------------------------------- /libs/playground-lib/src/lib/playground-lib.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { AuthComponent } from './auth.component'; 4 | 5 | @NgModule({ 6 | imports: [CommonModule], 7 | declarations: [AuthComponent], 8 | exports: [AuthComponent], 9 | }) 10 | export class PlaygroundLibModule {} 11 | -------------------------------------------------------------------------------- /libs/playground-lib/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | -------------------------------------------------------------------------------- /libs/playground-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/playground-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 | "**/*.test.ts", 14 | "jest.config.ts" 15 | ], 16 | "include": ["**/*.ts"] 17 | } 18 | -------------------------------------------------------------------------------- /libs/playground-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 | -------------------------------------------------------------------------------- /migration-guide.md: -------------------------------------------------------------------------------- 1 | # Migration Guides 2 | 3 | Our goal is to introduce as little breaking changes as possible. However, sometimes we need to adjust to new developments. 4 | 5 | - [From version 12 and 13](./migration-guide-13.md) 6 | - [From version 13 and 14](./migration-guide-14.md) 7 | -------------------------------------------------------------------------------- /project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-architects", 3 | "$schema": "node_modules/nx/schemas/project-schema.json", 4 | "targets": { 5 | "local-registry": { 6 | "executor": "@nx/js:verdaccio", 7 | "options": { 8 | "port": 4873, 9 | "config": ".verdaccio/config.yml", 10 | "storage": "tmp/local-registry/storage" 11 | } 12 | }, 13 | "test": { 14 | "command": "echo Noop" 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /serve.js: -------------------------------------------------------------------------------- 1 | const dist = 'dist/apps/playground'; 2 | const src = 'apps/playground'; 3 | const appName = 'playground'; 4 | const port = 3000; 5 | 6 | const watch = require('node-watch'); 7 | const spawn = require('cross-spawn'); 8 | 9 | var browserSync = require('browser-sync'); 10 | 11 | function build(appName) { 12 | spawn.sync('npx', ['nx', 'build', appName], { stdio: 'inherit' }); 13 | } 14 | 15 | build(appName); 16 | 17 | const bsInstance = browserSync.create(); 18 | bsInstance.init({ 19 | server: { 20 | baseDir: dist, 21 | index: 'index.html', 22 | }, 23 | port: port, 24 | cors: true, 25 | browser: true, 26 | }); 27 | 28 | watch(src, { recursive: true }, () => { 29 | build(appName); 30 | bsInstance.reload(); 31 | }); 32 | -------------------------------------------------------------------------------- /tools/scripts/start-local-registry.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This script starts a local registry for e2e testing purposes. 3 | * It is meant to be called in jest's globalSetup. 4 | */ 5 | import { startLocalRegistry } from '@nx/js/plugins/jest/local-registry'; 6 | import { execFileSync } from 'child_process'; 7 | 8 | export default async () => { 9 | // local registry target to run 10 | const localRegistryTarget = 11 | '@module-federation-plugin-duplicate/source:local-registry'; 12 | // storage folder for the local registry 13 | const storage = './tmp/local-registry/storage'; 14 | 15 | global.stopLocalRegistry = await startLocalRegistry({ 16 | localRegistryTarget, 17 | storage, 18 | verbose: false, 19 | }); 20 | const nx = require.resolve('nx'); 21 | execFileSync( 22 | nx, 23 | ['run-many', '--targets', 'publish', '--ver', '0.0.0-e2e', '--tag', 'e2e'], 24 | { env: process.env, stdio: 'inherit' } 25 | ); 26 | }; 27 | -------------------------------------------------------------------------------- /tools/scripts/stop-local-registry.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This script stops the local registry for e2e testing purposes. 3 | * It is meant to be called in jest's globalTeardown. 4 | */ 5 | 6 | export default () => { 7 | if (global.stopLocalRegistry) { 8 | global.stopLocalRegistry(); 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /update-local-mf.bat: -------------------------------------------------------------------------------- 1 | npm run publish-local:mf 2 | -------------------------------------------------------------------------------- /update-local-nf.sh: -------------------------------------------------------------------------------- 1 | node libs/native-federation-node/build/create-data-url.js 2 | npm run publish-local:nf 3 | --------------------------------------------------------------------------------