├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .vscode └── extensions.json ├── README.md ├── apps ├── .gitkeep ├── about-e2e │ ├── .eslintrc.json │ ├── cypress.json │ ├── project.json │ ├── src │ │ ├── fixtures │ │ │ └── example.json │ │ ├── integration │ │ │ └── app.spec.ts │ │ └── support │ │ │ ├── app.po.ts │ │ │ ├── commands.ts │ │ │ └── index.ts │ └── tsconfig.json ├── about │ ├── .babelrc │ ├── .browserslistrc │ ├── .eslintrc.json │ ├── jest.config.ts │ ├── module-federation.config.js │ ├── project.json │ ├── src │ │ ├── app │ │ │ ├── app.module.css │ │ │ └── app.tsx │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── bootstrap.tsx │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main.ts │ │ ├── polyfills.ts │ │ ├── remote-entry.ts │ │ └── styles.css │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ ├── webpack.config.js │ └── webpack.config.prod.js ├── cart-e2e │ ├── .eslintrc.json │ ├── cypress.json │ ├── project.json │ ├── src │ │ ├── fixtures │ │ │ └── example.json │ │ ├── integration │ │ │ └── app.spec.ts │ │ └── support │ │ │ ├── app.po.ts │ │ │ ├── commands.ts │ │ │ └── index.ts │ └── tsconfig.json ├── cart │ ├── .babelrc │ ├── .browserslistrc │ ├── .eslintrc.json │ ├── jest.config.ts │ ├── module-federation.config.js │ ├── project.json │ ├── src │ │ ├── app │ │ │ ├── app.module.css │ │ │ └── app.tsx │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── bootstrap.tsx │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main.ts │ │ ├── polyfills.ts │ │ ├── remote-entry.ts │ │ └── styles.css │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ ├── webpack.config.js │ └── webpack.config.prod.js ├── host-e2e │ ├── .eslintrc.json │ ├── cypress.json │ ├── project.json │ ├── src │ │ ├── fixtures │ │ │ └── example.json │ │ ├── integration │ │ │ └── app.spec.ts │ │ └── support │ │ │ ├── app.po.ts │ │ │ ├── commands.ts │ │ │ └── index.ts │ └── tsconfig.json ├── host │ ├── .babelrc │ ├── .browserslistrc │ ├── .eslintrc.json │ ├── jest.config.ts │ ├── module-federation.config.js │ ├── project.json │ ├── src │ │ ├── app │ │ │ ├── app.module.css │ │ │ └── app.tsx │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── bootstrap.tsx │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main.ts │ │ ├── polyfills.ts │ │ ├── remotes.d.ts │ │ └── styles.css │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ ├── webpack.config.js │ └── webpack.config.prod.js ├── shop-e2e │ ├── .eslintrc.json │ ├── cypress.json │ ├── project.json │ ├── src │ │ ├── fixtures │ │ │ └── example.json │ │ ├── integration │ │ │ └── app.spec.ts │ │ └── support │ │ │ ├── app.po.ts │ │ │ ├── commands.ts │ │ │ └── index.ts │ └── tsconfig.json └── shop │ ├── .babelrc │ ├── .browserslistrc │ ├── .eslintrc.json │ ├── jest.config.ts │ ├── module-federation.config.js │ ├── project.json │ ├── src │ ├── app │ │ ├── app.module.css │ │ ├── app.spec.tsx │ │ ├── app.tsx │ │ └── nx-welcome.tsx │ ├── assets │ │ └── .gitkeep │ ├── bootstrap.tsx │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── remote-entry.ts │ └── styles.css │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ ├── webpack.config.js │ └── webpack.config.prod.js ├── babel.config.json ├── jest.config.ts ├── jest.preset.js ├── libs ├── .gitkeep ├── about-main │ ├── .babelrc │ ├── .eslintrc.json │ ├── README.md │ ├── jest.config.ts │ ├── project.json │ ├── src │ │ ├── index.ts │ │ └── lib │ │ │ ├── about-main.module.css │ │ │ └── about-main.tsx │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── cart-main │ ├── .babelrc │ ├── .eslintrc.json │ ├── README.md │ ├── jest.config.ts │ ├── project.json │ ├── src │ │ ├── index.ts │ │ └── lib │ │ │ ├── cart-main.module.css │ │ │ └── cart-main.tsx │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── shared-components │ ├── .babelrc │ ├── .eslintrc.json │ ├── README.md │ ├── jest.config.ts │ ├── project.json │ ├── src │ │ ├── index.ts │ │ └── lib │ │ │ └── greeting │ │ │ ├── greeting.module.css │ │ │ ├── greeting.spec.tsx │ │ │ └── greeting.tsx │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json └── shop-main │ ├── .babelrc │ ├── .eslintrc.json │ ├── README.md │ ├── jest.config.ts │ ├── project.json │ ├── src │ ├── index.ts │ └── lib │ │ ├── shop-main.module.css │ │ └── shop-main.tsx │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── migrations.json ├── nx.json ├── package.json ├── readme-assets └── graph.png ├── tools └── tsconfig.tools.json ├── tsconfig.base.json └── yarn.lock /.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.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "ignorePatterns": ["**/*"], 4 | "plugins": ["@nx"], 5 | "overrides": [ 6 | { 7 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 8 | "rules": { 9 | "@nx/enforce-module-boundaries": [ 10 | "error", 11 | { 12 | "enforceBuildableLibDependency": true, 13 | "allow": [], 14 | "depConstraints": [ 15 | { 16 | "sourceTag": "*", 17 | "onlyDependOnLibsWithTags": ["*"] 18 | } 19 | ] 20 | } 21 | ] 22 | } 23 | }, 24 | { 25 | "files": ["*.ts", "*.tsx"], 26 | "extends": ["plugin:@nx/typescript"], 27 | "rules": {} 28 | }, 29 | { 30 | "files": ["*.js", "*.jsx"], 31 | "extends": ["plugin:@nx/javascript"], 32 | "rules": {} 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | main: 11 | name: Nx Cloud - Main Job 12 | uses: nrwl/ci/.github/workflows/nx-cloud-main.yml@v0.2 13 | with: 14 | parallel-commands: | 15 | npx nx-cloud record -- npx nx workspace-lint 16 | npx nx-cloud record -- npx nx format:check 17 | parallel-commands-on-agents: | 18 | npx nx affected --target=lint --parallel=3 19 | npx nx affected --target=test --parallel=3 --ci --code-coverage 20 | npx nx affected --target=build --configuration=development && npx nx affected --target=e2e --max-parallel=1 --no-watch 21 | agents: 22 | name: Nx Cloud - Agents 23 | uses: nrwl/ci/.github/workflows/nx-cloud-agents.yml@v0.2 24 | with: 25 | number-of-agents: 3 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | 3 | # See http://help.github.com/ignore-files/ for more about ignoring files. 4 | 5 | # compiled output 6 | /dist 7 | /tmp 8 | /out-tsc 9 | 10 | # dependencies 11 | node_modules 12 | 13 | # IDEs and editors 14 | /.idea 15 | .project 16 | .classpath 17 | .c9/ 18 | *.launch 19 | .settings/ 20 | *.sublime-workspace 21 | 22 | # IDE - VSCode 23 | .vscode/* 24 | !.vscode/settings.json 25 | !.vscode/tasks.json 26 | !.vscode/launch.json 27 | !.vscode/extensions.json 28 | 29 | # misc 30 | /.sass-cache 31 | /connect.lock 32 | /coverage 33 | /libpeerconnection.log 34 | npm-debug.log 35 | yarn-error.log 36 | testem.log 37 | /typings 38 | 39 | # System Files 40 | .DS_Store 41 | Thumbs.db -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Add files here to ignore them from prettier formatting 2 | 3 | /dist 4 | /coverage 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "nrwl.angular-console", 4 | "esbenp.prettier-vscode", 5 | "firsttris.vscode-jest-runner", 6 | "dbaeumer.vscode-eslint" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Speeding Up React Builds Using Module Federation 2 | 3 | WebPack module federation can be used to develop independently deployable micro frontends and speed up the build commands. This repo demonstrates the latter. 4 | 5 | This repo contains an application built out of 4 libraries: `about-main`, `cart-main`, `shop-main` and `shared-components`. 6 | It illustrates a system created by three teams who works on each feature: 7 | - `shop` 8 | - `cart` 9 | - `about` 10 | 11 | > We have a single lib in the repo, but each team could have hundreds of libs 12 | 13 | Typically, all the four libraries would be included into the same application and bundled as part of a single WebPack 14 | build. This means: 15 | 16 | * All the libraries have to be compiled and bundled together, on one machine, from scratch. Nothing can be reused across CI runs, and nothing can be split across multiple machines. This means that the build time will increase as the application grows and can easily reach 20-30m. 17 | 18 | * All the libraries have to be compiled and served when running the serve command locally. This means that the serve 19 | command will keep getting slower as the application gets larger and can easily reach 5-10m. 20 | 21 | Module federation can solve both the problems. 22 | 23 | To show how, we split the application into 3 remotes: `about`, `cart`, and `shop`, and the `host` project. The `host` 24 | project has an implicit dependency on each remote. The repo also makes the `shared-components` library buildable. 25 | 26 | ![Project graph](./readme-assets/graph.png) 27 | 28 | ## Serving Locally 29 | 30 | If you run `nx serve host`, the executor will build all the remotes first. Then, if the remotes are available in the 31 | cache (local or remote), the executor will restore them from the cache. All the remotes in the case are loaded and are 32 | available in the application, but they are static and cannot be changed. This is great for running e2e tests in CI 33 | but not useful for local development. 34 | 35 | If you run `nx serve host --devRemotes=shop,cart`, the executor will build (or fetch from cache) `about`. Additionally, it will start two dev servers, one for `shop` and another one for `cart`. This is because the `about` remote is static, while `shop` and `cart` will watch 36 | for file changes. 37 | 38 | In an extensive enough system (with say 10-20 remotes), you will often only work on 1 of them, but you still need the rest for the system to work. For instance, the remote you are working on might be only accessible via other remotes. 39 | Because you will only run your remote in the dev mode, and other remotes will be retrieved from the cache, you will be able 40 | to run the serve command, 10-20 times faster and see the app reflect your file changes 10-20 times faster. 41 | 42 | This gives you a good developer experience: the whole app is available, but only the part you are working on is 43 | served and watched. The rest is "served" from the cache, so it is *free* (CPU and RAM wise). So your serve command now can take a minute instead of 10 minutes and only require 4GB of RAM instead of 16. 44 | 45 | Note, for this to work well in practice; you should get cache hits for other remotes most of the time (rebuilding every remote independently is slower than building everything together), which means that you should have some distributed caching set up. 46 | 47 | ## Building in CI 48 | 49 | Using this approach improves the CI performance for two reasons: 50 | 51 | * Most PRs will only rebuild a few remotes, not all of them, and the remaining will be retrieved from the cache. 52 | * Every remote can be built on a separate machine, in parallel. So even PRs that change most/all remotes will get 53 | significantly faster. 54 | 55 | This repo enables Nx Cloud's distributed tasks execution. For example this is what is going to happen if you say change every single lib in the repo. 56 | 57 | One of the agents will start building `shared-components`. While the components are being built, no remotes can be built cause they consume `shared-components` from its dist folder. So other agents will start running unit tests and lint checks. When `shared-components` is built, one agent will start building the about remote, another one will start on cart, etc. When all the remotes are build, some agent is going to build the host, which then can be deployed or used for e2e tests. Note all of this happens transparently without your having to configure anything. 58 | 59 | As a result, the worst case scenario build time is: `buildOf(shared-components) + buildOf(slowest remote) + buildOf(host)` which in practice ends up being significantly faster than building the whole system (often 3-4 times faster). The average build time (where components haven't changed) gets even faster: `buildOf(average remote) + buildOf(host)`. 60 | 61 | ## E2E tests 62 | 63 | As you can see in the project graph above, there are four e2e test projects in the repo: one for each remote and one for the host. Having a suite per remote allows us to distribute e2e tests across machines to make them faster and only to run the suites that could be affected by a PR. 64 | 65 | Because of Nx Cloud's caching, every e2e test suite isn't going to rebuild the system from scratch. Instead will get it from the cache. 66 | 67 | ## Read More 68 | 69 | * [Read this guide about module federation and faster builds](https://nx.dev/module-federation/faster-builds) -------------------------------------------------------------------------------- /apps/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrwl/react-module-federation/2bab6893a84df97aed50a8e674362ff33a46105d/apps/.gitkeep -------------------------------------------------------------------------------- /apps/about-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/about-e2e/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileServerFolder": ".", 3 | "fixturesFolder": "./src/fixtures", 4 | "integrationFolder": "./src/integration", 5 | "modifyObstructiveCode": false, 6 | "supportFile": "./src/support/index.ts", 7 | "pluginsFile": false, 8 | "video": true, 9 | "videosFolder": "../../dist/cypress/apps/about-e2e/videos", 10 | "screenshotsFolder": "../../dist/cypress/apps/about-e2e/screenshots", 11 | "chromeWebSecurity": false 12 | } 13 | -------------------------------------------------------------------------------- /apps/about-e2e/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "about-e2e", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "apps/about-e2e/src", 5 | "projectType": "application", 6 | "targets": { 7 | "e2e": { 8 | "executor": "@nx/cypress:cypress", 9 | "options": { 10 | "cypressConfig": "apps/about-e2e/cypress.json", 11 | "devServerTarget": "about:serve:development" 12 | }, 13 | "configurations": { 14 | "production": { 15 | "devServerTarget": "about:serve:production" 16 | } 17 | } 18 | }, 19 | "lint": { 20 | "executor": "@nx/linter:eslint", 21 | "outputs": ["{options.outputFile}"], 22 | "options": { 23 | "lintFilePatterns": ["apps/about-e2e/**/*.{js,ts}"] 24 | } 25 | } 26 | }, 27 | "tags": [], 28 | "implicitDependencies": ["about"] 29 | } 30 | -------------------------------------------------------------------------------- /apps/about-e2e/src/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io" 4 | } 5 | -------------------------------------------------------------------------------- /apps/about-e2e/src/integration/app.spec.ts: -------------------------------------------------------------------------------- 1 | import { getGreeting } from '../support/app.po'; 2 | 3 | describe('about', () => { 4 | beforeEach(() => cy.visit('/about')); 5 | 6 | it('should display welcome message', () => { 7 | getGreeting().contains('Welcome about'); 8 | }) 9 | 10 | }); 11 | -------------------------------------------------------------------------------- /apps/about-e2e/src/support/app.po.ts: -------------------------------------------------------------------------------- 1 | export const getGreeting = () => cy.get('h1'); 2 | -------------------------------------------------------------------------------- /apps/about-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/about-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/about-e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "sourceMap": false, 5 | "outDir": "../../dist/out-tsc", 6 | "allowJs": true, 7 | "types": ["cypress", "node"] 8 | }, 9 | "include": ["src/**/*.ts", "src/**/*.js"] 10 | } 11 | -------------------------------------------------------------------------------- /apps/about/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@nx/react/babel", 5 | { 6 | "runtime": "automatic" 7 | } 8 | ] 9 | ], 10 | "plugins": [] 11 | } 12 | -------------------------------------------------------------------------------- /apps/about/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by: 2 | # 1. autoprefixer to adjust CSS to support the below specified browsers 3 | # 2. babel preset-env to adjust included polyfills 4 | # 5 | # For additional information regarding the format and rule options, please see: 6 | # https://github.com/browserslist/browserslist#queries 7 | # 8 | # If you need to support different browsers in production, you may tweak the list below. 9 | 10 | last 1 Chrome version 11 | last 1 Firefox version 12 | last 2 Edge major versions 13 | last 2 Safari major version 14 | last 2 iOS major versions 15 | Firefox ESR 16 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /apps/about/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:@nx/react", "../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /apps/about/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'about', 4 | preset: '../../jest.preset.js', 5 | transform: { 6 | '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest', 7 | '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }], 8 | }, 9 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 10 | coverageDirectory: '../../coverage/apps/about', 11 | }; 12 | -------------------------------------------------------------------------------- /apps/about/module-federation.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'about', 3 | exposes: { 4 | './Module': './src/remote-entry.ts', 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /apps/about/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "about", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "apps/about/src", 5 | "projectType": "application", 6 | "targets": { 7 | "build": { 8 | "executor": "@nx/webpack:webpack", 9 | "outputs": ["{options.outputPath}"], 10 | "defaultConfiguration": "production", 11 | "options": { 12 | "compiler": "babel", 13 | "outputPath": "dist/apps/about", 14 | "index": "apps/about/src/index.html", 15 | "baseHref": "/", 16 | "main": "apps/about/src/main.ts", 17 | "polyfills": "apps/about/src/polyfills.ts", 18 | "tsConfig": "apps/about/tsconfig.app.json", 19 | "assets": ["apps/about/src/favicon.ico", "apps/about/src/assets"], 20 | "styles": ["apps/about/src/styles.css"], 21 | "scripts": [], 22 | "webpackConfig": "apps/about/webpack.config.js" 23 | }, 24 | "configurations": { 25 | "development": { 26 | "extractLicenses": false, 27 | "optimization": false, 28 | "sourceMap": true, 29 | "vendorChunk": true 30 | }, 31 | "production": { 32 | "fileReplacements": [ 33 | { 34 | "replace": "apps/about/src/environments/environment.ts", 35 | "with": "apps/about/src/environments/environment.prod.ts" 36 | } 37 | ], 38 | "optimization": true, 39 | "outputHashing": "all", 40 | "sourceMap": false, 41 | "namedChunks": false, 42 | "extractLicenses": true, 43 | "vendorChunk": false, 44 | "webpackConfig": "apps/about/webpack.config.prod.js" 45 | } 46 | } 47 | }, 48 | "serve": { 49 | "executor": "@nx/react:module-federation-dev-server", 50 | "defaultConfiguration": "development", 51 | "options": { 52 | "buildTarget": "about:build", 53 | "hmr": true, 54 | "port": 4201 55 | }, 56 | "configurations": { 57 | "development": { 58 | "buildTarget": "about:build:development" 59 | }, 60 | "production": { 61 | "buildTarget": "about:build:production", 62 | "hmr": false 63 | } 64 | } 65 | }, 66 | "lint": { 67 | "executor": "@nx/linter:eslint", 68 | "outputs": ["{options.outputFile}"], 69 | "options": { 70 | "lintFilePatterns": ["apps/about/**/*.{ts,tsx,js,jsx}"] 71 | } 72 | }, 73 | "test": { 74 | "executor": "@nx/jest:jest", 75 | "outputs": ["{workspaceRoot}/coverage/apps/about"], 76 | "options": { 77 | "jestConfig": "apps/about/jest.config.ts", 78 | "passWithNoTests": true 79 | } 80 | }, 81 | "serve-static": { 82 | "executor": "@nx/web:file-server", 83 | "defaultConfiguration": "development", 84 | "options": { 85 | "buildTarget": "about:build", 86 | "port": 4201 87 | }, 88 | "configurations": { 89 | "development": { 90 | "buildTarget": "about:build:development" 91 | }, 92 | "production": { 93 | "buildTarget": "about:build:production" 94 | } 95 | } 96 | } 97 | }, 98 | "tags": [] 99 | } 100 | -------------------------------------------------------------------------------- /apps/about/src/app/app.module.css: -------------------------------------------------------------------------------- 1 | /* Your styles goes here. */ 2 | -------------------------------------------------------------------------------- /apps/about/src/app/app.tsx: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 2 | import { AboutMain } from '@react-module-federation/about-main'; 3 | 4 | export function App() { 5 | return ( 6 | <> 7 | 8 |
9 | 10 | ); 11 | } 12 | 13 | export default App; 14 | -------------------------------------------------------------------------------- /apps/about/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrwl/react-module-federation/2bab6893a84df97aed50a8e674362ff33a46105d/apps/about/src/assets/.gitkeep -------------------------------------------------------------------------------- /apps/about/src/bootstrap.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import * as ReactDOM from 'react-dom/client'; 3 | 4 | import App from './app/app'; 5 | 6 | const root = ReactDOM.createRoot( 7 | document.getElementById('root') as HTMLElement 8 | ); 9 | root.render( 10 | 11 | 12 | 13 | ); 14 | -------------------------------------------------------------------------------- /apps/about/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | }; 4 | -------------------------------------------------------------------------------- /apps/about/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // When building for production, this file is replaced with `environment.prod.ts`. 3 | 4 | export const environment = { 5 | production: false, 6 | }; 7 | -------------------------------------------------------------------------------- /apps/about/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrwl/react-module-federation/2bab6893a84df97aed50a8e674362ff33a46105d/apps/about/src/favicon.ico -------------------------------------------------------------------------------- /apps/about/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | About 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /apps/about/src/main.ts: -------------------------------------------------------------------------------- 1 | import('./bootstrap'); 2 | -------------------------------------------------------------------------------- /apps/about/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Polyfill stable language features. These imports will be optimized by `@babel/preset-env`. 3 | * 4 | * See: https://github.com/zloirock/core-js#babel 5 | */ 6 | import 'core-js/stable'; 7 | import 'regenerator-runtime/runtime'; 8 | -------------------------------------------------------------------------------- /apps/about/src/remote-entry.ts: -------------------------------------------------------------------------------- 1 | export { default } from './app/app'; 2 | -------------------------------------------------------------------------------- /apps/about/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /apps/about/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": ["node"] 6 | }, 7 | "files": [ 8 | "../../node_modules/@nx/react/typings/cssmodule.d.ts", 9 | "../../node_modules/@nx/react/typings/image.d.ts" 10 | ], 11 | "exclude": [ 12 | "jest.config.ts", 13 | "**/*.spec.ts", 14 | "**/*.test.ts", 15 | "**/*.spec.tsx", 16 | "**/*.test.tsx", 17 | "**/*.spec.js", 18 | "**/*.test.js", 19 | "**/*.spec.jsx", 20 | "**/*.test.jsx" 21 | ], 22 | "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] 23 | } 24 | -------------------------------------------------------------------------------- /apps/about/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "allowJs": true, 6 | "esModuleInterop": true, 7 | "allowSyntheticDefaultImports": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "strict": true, 10 | "noImplicitOverride": true, 11 | "noPropertyAccessFromIndexSignature": true, 12 | "noImplicitReturns": true, 13 | "noFallthroughCasesInSwitch": true 14 | }, 15 | "files": [], 16 | "include": [], 17 | "references": [ 18 | { 19 | "path": "./tsconfig.app.json" 20 | }, 21 | { 22 | "path": "./tsconfig.spec.json" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /apps/about/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 | "**/*.test.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.tsx", 13 | "**/*.spec.tsx", 14 | "**/*.test.js", 15 | "**/*.spec.js", 16 | "**/*.test.jsx", 17 | "**/*.spec.jsx", 18 | "**/*.d.ts" 19 | ], 20 | "files": [ 21 | "../../node_modules/@nx/react/typings/cssmodule.d.ts", 22 | "../../node_modules/@nx/react/typings/image.d.ts" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /apps/about/webpack.config.js: -------------------------------------------------------------------------------- 1 | const withModuleFederation = require('@nx/react/module-federation'); 2 | const moduleFederationConfig = require('./module-federation.config'); 3 | 4 | module.exports = withModuleFederation({ 5 | ...moduleFederationConfig, 6 | }); 7 | -------------------------------------------------------------------------------- /apps/about/webpack.config.prod.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./webpack.config'); 2 | -------------------------------------------------------------------------------- /apps/cart-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/cart-e2e/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileServerFolder": ".", 3 | "fixturesFolder": "./src/fixtures", 4 | "integrationFolder": "./src/integration", 5 | "modifyObstructiveCode": false, 6 | "supportFile": "./src/support/index.ts", 7 | "pluginsFile": false, 8 | "video": true, 9 | "videosFolder": "../../dist/cypress/apps/cart-e2e/videos", 10 | "screenshotsFolder": "../../dist/cypress/apps/cart-e2e/screenshots", 11 | "chromeWebSecurity": false 12 | } 13 | -------------------------------------------------------------------------------- /apps/cart-e2e/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cart-e2e", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "apps/cart-e2e/src", 5 | "projectType": "application", 6 | "targets": { 7 | "e2e": { 8 | "executor": "@nx/cypress:cypress", 9 | "options": { 10 | "cypressConfig": "apps/cart-e2e/cypress.json", 11 | "devServerTarget": "cart:serve:development" 12 | }, 13 | "configurations": { 14 | "production": { 15 | "devServerTarget": "cart:serve:production" 16 | } 17 | } 18 | }, 19 | "lint": { 20 | "executor": "@nx/linter:eslint", 21 | "outputs": ["{options.outputFile}"], 22 | "options": { 23 | "lintFilePatterns": ["apps/cart-e2e/**/*.{js,ts}"] 24 | } 25 | } 26 | }, 27 | "tags": [], 28 | "implicitDependencies": ["cart"] 29 | } 30 | -------------------------------------------------------------------------------- /apps/cart-e2e/src/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io" 4 | } 5 | -------------------------------------------------------------------------------- /apps/cart-e2e/src/integration/app.spec.ts: -------------------------------------------------------------------------------- 1 | import { getGreeting } from '../support/app.po'; 2 | 3 | describe('cart', () => { 4 | beforeEach(() => cy.visit('/cart')); 5 | 6 | it('should display welcome message', () => { 7 | getGreeting().contains('Welcome cart'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /apps/cart-e2e/src/support/app.po.ts: -------------------------------------------------------------------------------- 1 | export const getGreeting = () => cy.get('h1'); 2 | -------------------------------------------------------------------------------- /apps/cart-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/cart-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/cart-e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "sourceMap": false, 5 | "outDir": "../../dist/out-tsc", 6 | "allowJs": true, 7 | "types": ["cypress", "node"] 8 | }, 9 | "include": ["src/**/*.ts", "src/**/*.js"] 10 | } 11 | -------------------------------------------------------------------------------- /apps/cart/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@nx/react/babel", 5 | { 6 | "runtime": "automatic" 7 | } 8 | ] 9 | ], 10 | "plugins": [] 11 | } 12 | -------------------------------------------------------------------------------- /apps/cart/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by: 2 | # 1. autoprefixer to adjust CSS to support the below specified browsers 3 | # 2. babel preset-env to adjust included polyfills 4 | # 5 | # For additional information regarding the format and rule options, please see: 6 | # https://github.com/browserslist/browserslist#queries 7 | # 8 | # If you need to support different browsers in production, you may tweak the list below. 9 | 10 | last 1 Chrome version 11 | last 1 Firefox version 12 | last 2 Edge major versions 13 | last 2 Safari major version 14 | last 2 iOS major versions 15 | Firefox ESR 16 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /apps/cart/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:@nx/react", "../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /apps/cart/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'cart', 4 | preset: '../../jest.preset.js', 5 | transform: { 6 | '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest', 7 | '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }], 8 | }, 9 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 10 | coverageDirectory: '../../coverage/apps/cart', 11 | }; 12 | -------------------------------------------------------------------------------- /apps/cart/module-federation.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'cart', 3 | exposes: { 4 | './Module': './src/remote-entry.ts', 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /apps/cart/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cart", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "apps/cart/src", 5 | "projectType": "application", 6 | "targets": { 7 | "build": { 8 | "executor": "@nx/webpack:webpack", 9 | "outputs": ["{options.outputPath}"], 10 | "defaultConfiguration": "production", 11 | "options": { 12 | "compiler": "babel", 13 | "outputPath": "dist/apps/cart", 14 | "index": "apps/cart/src/index.html", 15 | "baseHref": "/", 16 | "main": "apps/cart/src/main.ts", 17 | "polyfills": "apps/cart/src/polyfills.ts", 18 | "tsConfig": "apps/cart/tsconfig.app.json", 19 | "assets": ["apps/cart/src/favicon.ico", "apps/cart/src/assets"], 20 | "styles": ["apps/cart/src/styles.css"], 21 | "scripts": [], 22 | "webpackConfig": "apps/cart/webpack.config.js" 23 | }, 24 | "configurations": { 25 | "development": { 26 | "extractLicenses": false, 27 | "optimization": false, 28 | "sourceMap": true, 29 | "vendorChunk": true 30 | }, 31 | "production": { 32 | "fileReplacements": [ 33 | { 34 | "replace": "apps/cart/src/environments/environment.ts", 35 | "with": "apps/cart/src/environments/environment.prod.ts" 36 | } 37 | ], 38 | "optimization": true, 39 | "outputHashing": "all", 40 | "sourceMap": false, 41 | "namedChunks": false, 42 | "extractLicenses": true, 43 | "vendorChunk": false, 44 | "webpackConfig": "apps/cart/webpack.config.prod.js" 45 | } 46 | } 47 | }, 48 | "serve": { 49 | "executor": "@nx/react:module-federation-dev-server", 50 | "defaultConfiguration": "development", 51 | "options": { 52 | "buildTarget": "cart:build", 53 | "hmr": true, 54 | "port": 4202 55 | }, 56 | "configurations": { 57 | "development": { 58 | "buildTarget": "cart:build:development" 59 | }, 60 | "production": { 61 | "buildTarget": "cart:build:production", 62 | "hmr": false 63 | } 64 | } 65 | }, 66 | "lint": { 67 | "executor": "@nx/linter:eslint", 68 | "outputs": ["{options.outputFile}"], 69 | "options": { 70 | "lintFilePatterns": ["apps/cart/**/*.{ts,tsx,js,jsx}"] 71 | } 72 | }, 73 | "test": { 74 | "executor": "@nx/jest:jest", 75 | "outputs": ["{workspaceRoot}/coverage/apps/cart"], 76 | "options": { 77 | "jestConfig": "apps/cart/jest.config.ts", 78 | "passWithNoTests": true 79 | } 80 | }, 81 | "serve-static": { 82 | "executor": "@nx/web:file-server", 83 | "defaultConfiguration": "development", 84 | "options": { 85 | "buildTarget": "cart:build", 86 | "port": 4202 87 | }, 88 | "configurations": { 89 | "development": { 90 | "buildTarget": "cart:build:development" 91 | }, 92 | "production": { 93 | "buildTarget": "cart:build:production" 94 | } 95 | } 96 | } 97 | }, 98 | "tags": [] 99 | } 100 | -------------------------------------------------------------------------------- /apps/cart/src/app/app.module.css: -------------------------------------------------------------------------------- 1 | /* Your styles goes here. */ 2 | -------------------------------------------------------------------------------- /apps/cart/src/app/app.tsx: -------------------------------------------------------------------------------- 1 | import { CartMain } from "@react-module-federation/cart-main"; 2 | 3 | 4 | export function App() { 5 | return ( 6 | <> 7 | 8 |
9 | 10 | ); 11 | } 12 | 13 | export default App; 14 | -------------------------------------------------------------------------------- /apps/cart/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrwl/react-module-federation/2bab6893a84df97aed50a8e674362ff33a46105d/apps/cart/src/assets/.gitkeep -------------------------------------------------------------------------------- /apps/cart/src/bootstrap.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import * as ReactDOM from 'react-dom/client'; 3 | 4 | import App from './app/app'; 5 | 6 | const root = ReactDOM.createRoot( 7 | document.getElementById('root') as HTMLElement 8 | ); 9 | root.render( 10 | 11 | 12 | 13 | ); 14 | -------------------------------------------------------------------------------- /apps/cart/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | }; 4 | -------------------------------------------------------------------------------- /apps/cart/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // When building for production, this file is replaced with `environment.prod.ts`. 3 | 4 | export const environment = { 5 | production: false, 6 | }; 7 | -------------------------------------------------------------------------------- /apps/cart/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrwl/react-module-federation/2bab6893a84df97aed50a8e674362ff33a46105d/apps/cart/src/favicon.ico -------------------------------------------------------------------------------- /apps/cart/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Cart 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /apps/cart/src/main.ts: -------------------------------------------------------------------------------- 1 | import('./bootstrap'); 2 | -------------------------------------------------------------------------------- /apps/cart/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Polyfill stable language features. These imports will be optimized by `@babel/preset-env`. 3 | * 4 | * See: https://github.com/zloirock/core-js#babel 5 | */ 6 | import 'core-js/stable'; 7 | import 'regenerator-runtime/runtime'; 8 | -------------------------------------------------------------------------------- /apps/cart/src/remote-entry.ts: -------------------------------------------------------------------------------- 1 | export { default } from './app/app'; 2 | -------------------------------------------------------------------------------- /apps/cart/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /apps/cart/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": ["node"] 6 | }, 7 | "files": [ 8 | "../../node_modules/@nx/react/typings/cssmodule.d.ts", 9 | "../../node_modules/@nx/react/typings/image.d.ts" 10 | ], 11 | "exclude": [ 12 | "jest.config.ts", 13 | "**/*.spec.ts", 14 | "**/*.test.ts", 15 | "**/*.spec.tsx", 16 | "**/*.test.tsx", 17 | "**/*.spec.js", 18 | "**/*.test.js", 19 | "**/*.spec.jsx", 20 | "**/*.test.jsx" 21 | ], 22 | "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] 23 | } 24 | -------------------------------------------------------------------------------- /apps/cart/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "allowJs": true, 6 | "esModuleInterop": true, 7 | "allowSyntheticDefaultImports": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "strict": true, 10 | "noImplicitOverride": true, 11 | "noPropertyAccessFromIndexSignature": true, 12 | "noImplicitReturns": true, 13 | "noFallthroughCasesInSwitch": true 14 | }, 15 | "files": [], 16 | "include": [], 17 | "references": [ 18 | { 19 | "path": "./tsconfig.app.json" 20 | }, 21 | { 22 | "path": "./tsconfig.spec.json" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /apps/cart/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 | "**/*.test.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.tsx", 13 | "**/*.spec.tsx", 14 | "**/*.test.js", 15 | "**/*.spec.js", 16 | "**/*.test.jsx", 17 | "**/*.spec.jsx", 18 | "**/*.d.ts" 19 | ], 20 | "files": [ 21 | "../../node_modules/@nx/react/typings/cssmodule.d.ts", 22 | "../../node_modules/@nx/react/typings/image.d.ts" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /apps/cart/webpack.config.js: -------------------------------------------------------------------------------- 1 | const withModuleFederation = require('@nx/react/module-federation'); 2 | const moduleFederationConfig = require('./module-federation.config'); 3 | 4 | module.exports = withModuleFederation({ 5 | ...moduleFederationConfig, 6 | }); 7 | -------------------------------------------------------------------------------- /apps/cart/webpack.config.prod.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./webpack.config'); 2 | -------------------------------------------------------------------------------- /apps/host-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/host-e2e/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileServerFolder": ".", 3 | "fixturesFolder": "./src/fixtures", 4 | "integrationFolder": "./src/integration", 5 | "modifyObstructiveCode": false, 6 | "supportFile": "./src/support/index.ts", 7 | "pluginsFile": false, 8 | "video": true, 9 | "videosFolder": "../../dist/cypress/apps/host-e2e/videos", 10 | "screenshotsFolder": "../../dist/cypress/apps/host-e2e/screenshots", 11 | "chromeWebSecurity": false 12 | } 13 | -------------------------------------------------------------------------------- /apps/host-e2e/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "host-e2e", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "apps/host-e2e/src", 5 | "projectType": "application", 6 | "targets": { 7 | "e2e": { 8 | "executor": "@nx/cypress:cypress", 9 | "options": { 10 | "cypressConfig": "apps/host-e2e/cypress.json", 11 | "devServerTarget": "host:serve:development", 12 | "baseUrl": "http://localhost:4200" 13 | }, 14 | "configurations": { 15 | "production": { 16 | "devServerTarget": "host:serve:production" 17 | } 18 | } 19 | }, 20 | "lint": { 21 | "executor": "@nx/linter:eslint", 22 | "outputs": ["{options.outputFile}"], 23 | "options": { 24 | "lintFilePatterns": ["apps/host-e2e/**/*.{js,ts}"] 25 | } 26 | } 27 | }, 28 | "tags": [], 29 | "implicitDependencies": ["host"] 30 | } 31 | -------------------------------------------------------------------------------- /apps/host-e2e/src/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io" 4 | } 5 | -------------------------------------------------------------------------------- /apps/host-e2e/src/integration/app.spec.ts: -------------------------------------------------------------------------------- 1 | import { getGreeting } from '../support/app.po'; 2 | 3 | describe('host', () => { 4 | beforeEach(() => cy.visit('/')); 5 | 6 | it('should display welcome message', () => { 7 | getGreeting().contains('Welcome shop'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /apps/host-e2e/src/support/app.po.ts: -------------------------------------------------------------------------------- 1 | export const getGreeting = () => cy.get('h1'); 2 | -------------------------------------------------------------------------------- /apps/host-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/host-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/host-e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "sourceMap": false, 5 | "outDir": "../../dist/out-tsc", 6 | "allowJs": true, 7 | "types": ["cypress", "node"] 8 | }, 9 | "include": ["src/**/*.ts", "src/**/*.js"] 10 | } 11 | -------------------------------------------------------------------------------- /apps/host/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@nx/react/babel", 5 | { 6 | "runtime": "automatic" 7 | } 8 | ] 9 | ], 10 | "plugins": [] 11 | } 12 | -------------------------------------------------------------------------------- /apps/host/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by: 2 | # 1. autoprefixer to adjust CSS to support the below specified browsers 3 | # 2. babel preset-env to adjust included polyfills 4 | # 5 | # For additional information regarding the format and rule options, please see: 6 | # https://github.com/browserslist/browserslist#queries 7 | # 8 | # If you need to support different browsers in production, you may tweak the list below. 9 | 10 | last 1 Chrome version 11 | last 1 Firefox version 12 | last 2 Edge major versions 13 | last 2 Safari major version 14 | last 2 iOS major versions 15 | Firefox ESR 16 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /apps/host/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:@nx/react", "../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /apps/host/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'host', 4 | preset: '../../jest.preset.js', 5 | transform: { 6 | '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest', 7 | '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }], 8 | }, 9 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 10 | coverageDirectory: '../../coverage/apps/host', 11 | }; 12 | -------------------------------------------------------------------------------- /apps/host/module-federation.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'host', 3 | remotes: ['about', 'cart', 'shop'], 4 | }; 5 | -------------------------------------------------------------------------------- /apps/host/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "host", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "apps/host/src", 5 | "projectType": "application", 6 | "targets": { 7 | "build": { 8 | "executor": "@nx/webpack:webpack", 9 | "outputs": ["{options.outputPath}"], 10 | "defaultConfiguration": "production", 11 | "options": { 12 | "compiler": "babel", 13 | "outputPath": "dist/apps/host", 14 | "index": "apps/host/src/index.html", 15 | "baseHref": "/", 16 | "main": "apps/host/src/main.ts", 17 | "polyfills": "apps/host/src/polyfills.ts", 18 | "tsConfig": "apps/host/tsconfig.app.json", 19 | "assets": ["apps/host/src/favicon.ico", "apps/host/src/assets"], 20 | "styles": ["apps/host/src/styles.css"], 21 | "scripts": [], 22 | "webpackConfig": "apps/host/webpack.config.js" 23 | }, 24 | "configurations": { 25 | "development": { 26 | "extractLicenses": false, 27 | "optimization": false, 28 | "sourceMap": true, 29 | "vendorChunk": true 30 | }, 31 | "production": { 32 | "fileReplacements": [ 33 | { 34 | "replace": "apps/host/src/environments/environment.ts", 35 | "with": "apps/host/src/environments/environment.prod.ts" 36 | } 37 | ], 38 | "optimization": true, 39 | "outputHashing": "all", 40 | "sourceMap": false, 41 | "namedChunks": false, 42 | "extractLicenses": true, 43 | "vendorChunk": false, 44 | "webpackConfig": "apps/host/webpack.config.prod.js" 45 | } 46 | } 47 | }, 48 | "serve": { 49 | "executor": "@nx/react:module-federation-dev-server", 50 | "defaultConfiguration": "development", 51 | "options": { 52 | "buildTarget": "host:build", 53 | "hmr": true, 54 | "port": 4200 55 | }, 56 | "configurations": { 57 | "development": { 58 | "buildTarget": "host:build:development" 59 | }, 60 | "production": { 61 | "buildTarget": "host:build:production", 62 | "hmr": false 63 | } 64 | } 65 | }, 66 | "lint": { 67 | "executor": "@nx/linter:eslint", 68 | "outputs": ["{options.outputFile}"], 69 | "options": { 70 | "lintFilePatterns": ["apps/host/**/*.{ts,tsx,js,jsx}"] 71 | } 72 | }, 73 | "test": { 74 | "executor": "@nx/jest:jest", 75 | "outputs": ["{workspaceRoot}/coverage/apps/host"], 76 | "options": { 77 | "jestConfig": "apps/host/jest.config.ts", 78 | "passWithNoTests": true 79 | } 80 | }, 81 | "serve-static": { 82 | "executor": "@nx/web:file-server", 83 | "defaultConfiguration": "development", 84 | "options": { 85 | "buildTarget": "host:build", 86 | "port": 4200 87 | }, 88 | "configurations": { 89 | "development": { 90 | "buildTarget": "host:build:development" 91 | }, 92 | "production": { 93 | "buildTarget": "host:build:production" 94 | } 95 | } 96 | } 97 | }, 98 | "tags": [], 99 | "implicitDependencies": ["cart", "shop", "about"] 100 | } 101 | -------------------------------------------------------------------------------- /apps/host/src/app/app.module.css: -------------------------------------------------------------------------------- 1 | /* Your styles goes here. */ 2 | -------------------------------------------------------------------------------- /apps/host/src/app/app.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { Link, Route, Routes } from 'react-router-dom'; 4 | 5 | const About = React.lazy(() => import('about/Module')); 6 | 7 | const Cart = React.lazy(() => import('cart/Module')); 8 | 9 | const Shop = React.lazy(() => import('shop/Module')); 10 | 11 | export function App() { 12 | return ( 13 | 14 |

Store

15 |
    16 |
  • 17 | Shop 18 |
  • 19 | 20 |
  • 21 | About 22 |
  • 23 | 24 |
  • 25 | Cart 26 |
  • 27 |
28 | 29 | } /> 30 | 31 | } /> 32 | 33 | } /> 34 | 35 | 36 |
37 | ); 38 | } 39 | 40 | export default App; 41 | -------------------------------------------------------------------------------- /apps/host/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrwl/react-module-federation/2bab6893a84df97aed50a8e674362ff33a46105d/apps/host/src/assets/.gitkeep -------------------------------------------------------------------------------- /apps/host/src/bootstrap.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import * as ReactDOM from 'react-dom/client'; 3 | import { BrowserRouter } from 'react-router-dom'; 4 | 5 | import App from './app/app'; 6 | 7 | const root = ReactDOM.createRoot( 8 | document.getElementById('root') as HTMLElement 9 | ); 10 | root.render( 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | -------------------------------------------------------------------------------- /apps/host/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | }; 4 | -------------------------------------------------------------------------------- /apps/host/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // When building for production, this file is replaced with `environment.prod.ts`. 3 | 4 | export const environment = { 5 | production: false, 6 | }; 7 | -------------------------------------------------------------------------------- /apps/host/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrwl/react-module-federation/2bab6893a84df97aed50a8e674362ff33a46105d/apps/host/src/favicon.ico -------------------------------------------------------------------------------- /apps/host/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Host 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /apps/host/src/main.ts: -------------------------------------------------------------------------------- 1 | import('./bootstrap'); 2 | -------------------------------------------------------------------------------- /apps/host/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Polyfill stable language features. These imports will be optimized by `@babel/preset-env`. 3 | * 4 | * See: https://github.com/zloirock/core-js#babel 5 | */ 6 | import 'core-js/stable'; 7 | import 'regenerator-runtime/runtime'; 8 | -------------------------------------------------------------------------------- /apps/host/src/remotes.d.ts: -------------------------------------------------------------------------------- 1 | // Declare your remote Modules here 2 | // Example declare module 'about/Module'; 3 | 4 | declare module 'about/Module'; 5 | declare module 'cart/Module'; 6 | declare module 'shop/Module'; 7 | -------------------------------------------------------------------------------- /apps/host/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /apps/host/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": ["node"] 6 | }, 7 | "files": [ 8 | "../../node_modules/@nx/react/typings/cssmodule.d.ts", 9 | "../../node_modules/@nx/react/typings/image.d.ts" 10 | ], 11 | "exclude": [ 12 | "jest.config.ts", 13 | "**/*.spec.ts", 14 | "**/*.test.ts", 15 | "**/*.spec.tsx", 16 | "**/*.test.tsx", 17 | "**/*.spec.js", 18 | "**/*.test.js", 19 | "**/*.spec.jsx", 20 | "**/*.test.jsx" 21 | ], 22 | "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] 23 | } 24 | -------------------------------------------------------------------------------- /apps/host/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "allowJs": true, 6 | "esModuleInterop": true, 7 | "allowSyntheticDefaultImports": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "strict": true, 10 | "noImplicitOverride": true, 11 | "noPropertyAccessFromIndexSignature": true, 12 | "noImplicitReturns": true, 13 | "noFallthroughCasesInSwitch": true 14 | }, 15 | "files": [], 16 | "include": [], 17 | "references": [ 18 | { 19 | "path": "./tsconfig.app.json" 20 | }, 21 | { 22 | "path": "./tsconfig.spec.json" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /apps/host/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 | "**/*.test.ts", 11 | "**/*.spec.ts", 12 | "**/*.test.tsx", 13 | "**/*.spec.tsx", 14 | "**/*.test.js", 15 | "**/*.spec.js", 16 | "**/*.test.jsx", 17 | "**/*.spec.jsx", 18 | "**/*.d.ts" 19 | ], 20 | "files": [ 21 | "../../node_modules/@nx/react/typings/cssmodule.d.ts", 22 | "../../node_modules/@nx/react/typings/image.d.ts" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /apps/host/webpack.config.js: -------------------------------------------------------------------------------- 1 | const withModuleFederation = require('@nx/react/module-federation'); 2 | const moduleFederationConfig = require('./module-federation.config'); 3 | 4 | module.exports = withModuleFederation({ 5 | ...moduleFederationConfig, 6 | }); 7 | -------------------------------------------------------------------------------- /apps/host/webpack.config.prod.js: -------------------------------------------------------------------------------- 1 | const withModuleFederation = require('@nx/react/module-federation'); 2 | const moduleFederationConfig = require('./module-federation.config'); 3 | 4 | module.exports = withModuleFederation({ 5 | ...moduleFederationConfig, 6 | /* 7 | * Remote overrides for production. 8 | * Each entry is a pair of an unique name and the URL where it is deployed. 9 | * 10 | * e.g. 11 | * remotes: [ 12 | * ['app1', '//app1.example.com'], 13 | * ['app2', '//app2.example.com'], 14 | * ] 15 | * 16 | * You can also use a full path to the remoteEntry.js file if desired. 17 | * 18 | * remotes: [ 19 | * ['app1', '//example.com/path/to/app1/remoteEntry.js'], 20 | * ['app2', '//example.com/path/to/app2/remoteEntry.js'], 21 | * ] 22 | */ 23 | remotes: [ 24 | ['about', '//localhost:4201/'], 25 | ['cart', '//localhost:4202/'], 26 | ['shop', '//localhost:4203/'], 27 | ], 28 | }); 29 | -------------------------------------------------------------------------------- /apps/shop-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/shop-e2e/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileServerFolder": ".", 3 | "fixturesFolder": "./src/fixtures", 4 | "integrationFolder": "./src/integration", 5 | "modifyObstructiveCode": false, 6 | "supportFile": "./src/support/index.ts", 7 | "pluginsFile": false, 8 | "video": true, 9 | "videosFolder": "../../dist/cypress/apps/shop-e2e/videos", 10 | "screenshotsFolder": "../../dist/cypress/apps/shop-e2e/screenshots", 11 | "chromeWebSecurity": false 12 | } 13 | -------------------------------------------------------------------------------- /apps/shop-e2e/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shop-e2e", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "apps/shop-e2e/src", 5 | "projectType": "application", 6 | "targets": { 7 | "e2e": { 8 | "executor": "@nx/cypress:cypress", 9 | "options": { 10 | "cypressConfig": "apps/shop-e2e/cypress.json", 11 | "devServerTarget": "shop:serve:development" 12 | }, 13 | "configurations": { 14 | "production": { 15 | "devServerTarget": "shop:serve:production" 16 | } 17 | } 18 | }, 19 | "lint": { 20 | "executor": "@nx/linter:eslint", 21 | "outputs": ["{options.outputFile}"], 22 | "options": { 23 | "lintFilePatterns": ["apps/shop-e2e/**/*.{js,ts}"] 24 | } 25 | } 26 | }, 27 | "tags": [], 28 | "implicitDependencies": ["shop"] 29 | } 30 | -------------------------------------------------------------------------------- /apps/shop-e2e/src/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io" 4 | } 5 | -------------------------------------------------------------------------------- /apps/shop-e2e/src/integration/app.spec.ts: -------------------------------------------------------------------------------- 1 | import { getGreeting } from '../support/app.po'; 2 | 3 | describe('shop', () => { 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 shop'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /apps/shop-e2e/src/support/app.po.ts: -------------------------------------------------------------------------------- 1 | export const getGreeting = () => cy.get('h1'); 2 | -------------------------------------------------------------------------------- /apps/shop-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/shop-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/shop-e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "sourceMap": false, 5 | "outDir": "../../dist/out-tsc", 6 | "allowJs": true, 7 | "types": ["cypress", "node"] 8 | }, 9 | "include": ["src/**/*.ts", "src/**/*.js"] 10 | } 11 | -------------------------------------------------------------------------------- /apps/shop/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@nx/react/babel", 5 | { 6 | "runtime": "automatic" 7 | } 8 | ] 9 | ], 10 | "plugins": [] 11 | } 12 | -------------------------------------------------------------------------------- /apps/shop/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by: 2 | # 1. autoprefixer to adjust CSS to support the below specified browsers 3 | # 2. babel preset-env to adjust included polyfills 4 | # 5 | # For additional information regarding the format and rule options, please see: 6 | # https://github.com/browserslist/browserslist#queries 7 | # 8 | # If you need to support different browsers in production, you may tweak the list below. 9 | 10 | last 1 Chrome version 11 | last 1 Firefox version 12 | last 2 Edge major versions 13 | last 2 Safari major version 14 | last 2 iOS major versions 15 | Firefox ESR 16 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /apps/shop/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:@nx/react", "../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.ts", "*.tsx"], 11 | "rules": {} 12 | }, 13 | { 14 | "files": ["*.js", "*.jsx"], 15 | "rules": {} 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /apps/shop/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'shop', 4 | preset: '../../jest.preset.js', 5 | transform: { 6 | '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest', 7 | '^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }], 8 | }, 9 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 10 | coverageDirectory: '../../coverage/apps/shop', 11 | }; 12 | -------------------------------------------------------------------------------- /apps/shop/module-federation.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'shop', 3 | exposes: { 4 | './Module': './src/remote-entry.ts', 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /apps/shop/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shop", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "apps/shop/src", 5 | "projectType": "application", 6 | "targets": { 7 | "build": { 8 | "executor": "@nx/webpack:webpack", 9 | "outputs": ["{options.outputPath}"], 10 | "defaultConfiguration": "production", 11 | "options": { 12 | "compiler": "babel", 13 | "outputPath": "dist/apps/shop", 14 | "index": "apps/shop/src/index.html", 15 | "baseHref": "/", 16 | "main": "apps/shop/src/main.ts", 17 | "polyfills": "apps/shop/src/polyfills.ts", 18 | "tsConfig": "apps/shop/tsconfig.app.json", 19 | "assets": ["apps/shop/src/favicon.ico", "apps/shop/src/assets"], 20 | "styles": ["apps/shop/src/styles.css"], 21 | "scripts": [], 22 | "webpackConfig": "apps/shop/webpack.config.js" 23 | }, 24 | "configurations": { 25 | "development": { 26 | "extractLicenses": false, 27 | "optimization": false, 28 | "sourceMap": true, 29 | "vendorChunk": true 30 | }, 31 | "production": { 32 | "fileReplacements": [ 33 | { 34 | "replace": "apps/shop/src/environments/environment.ts", 35 | "with": "apps/shop/src/environments/environment.prod.ts" 36 | } 37 | ], 38 | "optimization": true, 39 | "outputHashing": "all", 40 | "sourceMap": false, 41 | "namedChunks": false, 42 | "extractLicenses": true, 43 | "vendorChunk": false, 44 | "webpackConfig": "apps/shop/webpack.config.prod.js" 45 | } 46 | } 47 | }, 48 | "serve": { 49 | "executor": "@nx/react:module-federation-dev-server", 50 | "defaultConfiguration": "development", 51 | "options": { 52 | "buildTarget": "shop:build", 53 | "hmr": true, 54 | "port": 4203 55 | }, 56 | "configurations": { 57 | "development": { 58 | "buildTarget": "shop:build:development" 59 | }, 60 | "production": { 61 | "buildTarget": "shop:build:production", 62 | "hmr": false 63 | } 64 | } 65 | }, 66 | "lint": { 67 | "executor": "@nx/linter:eslint", 68 | "outputs": ["{options.outputFile}"], 69 | "options": { 70 | "lintFilePatterns": ["apps/shop/**/*.{ts,tsx,js,jsx}"] 71 | } 72 | }, 73 | "test": { 74 | "executor": "@nx/jest:jest", 75 | "outputs": ["{workspaceRoot}/coverage/apps/shop"], 76 | "options": { 77 | "jestConfig": "apps/shop/jest.config.ts", 78 | "passWithNoTests": true 79 | } 80 | }, 81 | "serve-static": { 82 | "executor": "@nx/web:file-server", 83 | "defaultConfiguration": "development", 84 | "options": { 85 | "buildTarget": "shop:build", 86 | "port": 4203 87 | }, 88 | "configurations": { 89 | "development": { 90 | "buildTarget": "shop:build:development" 91 | }, 92 | "production": { 93 | "buildTarget": "shop:build:production" 94 | } 95 | } 96 | } 97 | }, 98 | "tags": [] 99 | } 100 | -------------------------------------------------------------------------------- /apps/shop/src/app/app.module.css: -------------------------------------------------------------------------------- 1 | /* Your styles goes here. */ 2 | -------------------------------------------------------------------------------- /apps/shop/src/app/app.spec.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react'; 2 | 3 | import App from './app'; 4 | 5 | describe('App', () => { 6 | it('should render successfully', () => { 7 | const { baseElement } = render(); 8 | 9 | expect(baseElement).toBeTruthy(); 10 | }); 11 | 12 | it('should have a greeting as the title', () => { 13 | const { getByText } = render(); 14 | 15 | expect(getByText(/Welcome shop/gi)).toBeTruthy(); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /apps/shop/src/app/app.tsx: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 2 | import { ShopMain } from '@react-module-federation/shop-main'; 3 | 4 | export function App() { 5 | return ( 6 | <> 7 | 8 | 9 | ); 10 | } 11 | 12 | export default App; 13 | -------------------------------------------------------------------------------- /apps/shop/src/app/nx-welcome.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * 3 | This is a starter component and can be deleted. 4 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * 5 | Delete this file and get started with your project! 6 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * 7 | */ 8 | export function NxWelcome({ title }: { title: string }) { 9 | return ( 10 | <> 11 |