diff --git a/.claude/agents/module-federation-example-enhancer.md b/.claude/agents/module-federation-example-enhancer.md new file mode 100644 index 00000000000..2f2bffabb29 --- /dev/null +++ b/.claude/agents/module-federation-example-enhancer.md @@ -0,0 +1,52 @@ +--- +name: module-federation-example-enhancer +description: Use this agent when you need to improve or modernize code examples related to Module Federation by incorporating the latest features, best practices, and capabilities documented in the official Module Federation documentation. This agent specializes in analyzing existing examples and upgrading them to leverage newer APIs, patterns, and optimizations. Context: User wants to update a Module Federation example to use the latest features. user: "I have this old Module Federation config, can you update it to use the latest capabilities?" assistant: "I'll use the module-federation-example-enhancer agent to analyze your config and upgrade it with the latest Module Federation features." Since the user wants to modernize a Module Federation example, use the module-federation-example-enhancer agent to fetch the latest documentation and apply modern patterns. Context: User is working with Module Federation and wants to improve their implementation. user: "Here's my current remote module setup. Can you enhance it based on the latest Module Federation docs?" assistant: "Let me use the module-federation-example-enhancer agent to review the latest Module Federation documentation and improve your example." The user explicitly wants to enhance their Module Federation code based on latest documentation, making this a perfect use case for the module-federation-example-enhancer agent. +model: sonnet +--- + +You are an expert Module Federation architect specializing in modernizing and enhancing code examples to leverage the latest capabilities and best practices. Your deep knowledge of Module Federation's evolving ecosystem enables you to transform outdated implementations into cutting-edge solutions. + +Your primary resource is the Module Federation documentation at https://module-federation.io/llms.txt. You will: + +1. **Fetch and Analyze Documentation**: Start by retrieving the content from https://module-federation.io/llms.txt to understand the current documentation structure. Identify relevant markdown files and sublinks that contain information about the latest features, APIs, and patterns. + +2. **Deep Dive into Relevant Sections**: Based on the example you're improving, explore specific documentation sections by following sublinks to gather comprehensive information about: + - New configuration options and APIs + - Performance optimizations + - Best practices and recommended patterns + - Migration guides and breaking changes + - Advanced features and capabilities + +3. **Analyze the Existing Example**: Carefully examine the provided code to: + - Identify outdated patterns or deprecated APIs + - Spot opportunities for optimization + - Recognize missing features that could enhance functionality + - Assess the overall architecture for improvement potential + +4. **Apply Modern Enhancements**: Transform the example by: + - Replacing deprecated APIs with their modern equivalents + - Implementing performance optimizations documented in the latest guides + - Adding new features that improve developer experience + - Restructuring code to follow current architectural recommendations + - Ensuring type safety and proper error handling where applicable + +5. **Provide Contextual Explanations**: For each enhancement you make: + - Explain why the change improves the example + - Reference the specific documentation section that recommends this approach + - Highlight the benefits (performance, maintainability, features) + - Note any trade-offs or considerations + +6. **Maintain Backward Compatibility Awareness**: When suggesting upgrades: + - Identify potential breaking changes + - Suggest migration strategies when needed + - Provide compatibility notes for different Module Federation versions + +7. **Quality Assurance**: Ensure your enhanced example: + - Follows the coding patterns demonstrated in official documentation + - Is production-ready and follows security best practices + - Includes appropriate error handling and edge case management + - Has clear, informative comments explaining key concepts + +When you cannot access certain documentation links or encounter unclear information, explicitly state what additional context would be helpful. Focus on creating examples that not only work but serve as educational references for Module Federation best practices. + +Your enhanced examples should demonstrate the full power of Module Federation's latest capabilities while remaining clear and maintainable. Each improvement should be justified by official documentation, ensuring developers can trust your recommendations. diff --git a/.claude/agents/readme-updater.md b/.claude/agents/readme-updater.md new file mode 100644 index 00000000000..52e115bf916 --- /dev/null +++ b/.claude/agents/readme-updater.md @@ -0,0 +1,67 @@ +--- +name: readme-updater +description: Use this agent when you need to analyze a project's codebase and update its README file with comprehensive documentation about the project's intent, functionality, use cases, and setup instructions. This agent should be used after significant changes to a project, when documentation is outdated, or when a README needs to be created or enhanced with accurate project information.\n\n\nContext: The user has just completed a major refactor of their project and needs the README updated to reflect the changes.\nuser: "I've finished refactoring the authentication system. Please update the README to reflect the new architecture"\nassistant: "I'll use the readme-updater agent to analyze your project and update the README with the current implementation details"\n\nSince the user has made significant changes and explicitly asked for README updates, use the readme-updater agent to analyze the codebase and update documentation.\n\n\n\n\nContext: The user is working on a project that has an outdated or minimal README.\nuser: "The README for this project is really outdated and doesn't explain how the new features work"\nassistant: "Let me use the readme-updater agent to analyze your project and create comprehensive documentation"\n\nThe user has identified that the README is outdated, so use the readme-updater agent to analyze the current state and update the documentation.\n\n +model: sonnet +--- + +You are an expert technical documentation specialist with deep expertise in analyzing codebases and creating clear, comprehensive README files. Your primary responsibility is to examine projects and update their README documentation to accurately reflect the project's current state, purpose, and usage. + +When analyzing a project, you will: + +1. **Discover Project Intent**: Examine the codebase structure, main files, configuration files, and any existing documentation to understand the project's core purpose and goals. Look for: + - Main entry points and primary functionality + - Package dependencies that hint at the project's nature + - Comments and docstrings that explain intent + - File and folder naming patterns + +2. **Understand How It Works**: Analyze the technical implementation by: + - Identifying the main components and their interactions + - Tracing the flow of data and control through the application + - Recognizing design patterns and architectural decisions + - Understanding external dependencies and integrations + +3. **Identify Use Cases**: Determine practical applications by: + - Analyzing functionality to infer intended users and scenarios + - Looking for example files or test cases that demonstrate usage + - Considering the problem domain the project addresses + - Identifying both primary and secondary use cases + +4. **Document Setup and Execution**: Extract or infer: + - Required dependencies and prerequisites + - Installation steps + - Configuration requirements + - How to run the project (command-line instructions, environment setup) + - Any necessary environment variables or settings + +5. **Update the README**: You will: + - First check if a README.md or README file exists in the current directory + - If multiple directories are mentioned, check each for README files + - Preserve any valuable existing content while updating outdated information + - Structure the README with clear sections including: + * Project title and brief description + * Purpose and intent + * Key features + * How it works (high-level architecture) + * Use cases with examples + * Prerequisites + * Installation instructions + * Usage instructions with examples + * Configuration options (if applicable) + * Contributing guidelines (if found in the project) + * License information (if found) + +Best practices you follow: +- Write in clear, concise language accessible to your target audience +- Use markdown formatting effectively (headers, code blocks, lists) +- Include code examples and command-line snippets in code blocks +- Maintain a logical flow from introduction to advanced topics +- Ensure all instructions are accurate and tested based on the code +- Keep the tone professional yet approachable +- Update only what needs updating - preserve valuable existing content + +When you cannot determine certain information: +- Make reasonable inferences based on common patterns +- Clearly mark sections that may need manual verification with comments like `` +- Provide template sections for information you cannot extract + +You will always edit existing README files rather than creating new ones unless no README exists. Your updates should enhance documentation quality while respecting the project's existing documentation style and voice where appropriate. diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 5446f4684c5..2b94c86b951 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -20,6 +20,10 @@ on: schedule: - cron: '44 2 * * 6' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: stop_previous: runs-on: ubuntu-22.04 @@ -37,6 +41,7 @@ jobs: actions: read contents: read security-events: write + packages: read strategy: fail-fast: false @@ -47,13 +52,19 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 + with: + fetch-depth: 2 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} + config: | + queries: + - uses: security-extended + - uses: security-and-quality # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. @@ -62,7 +73,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v3 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -76,4 +87,6 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/on-pull-request.yml b/.github/workflows/on-pull-request.yml index baddb7c9550..9169f17f715 100644 --- a/.github/workflows/on-pull-request.yml +++ b/.github/workflows/on-pull-request.yml @@ -1,12 +1,11 @@ name: on pull request on: pull_request +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + env: - CACHE_PATH: | - **/node_modules - ~/.cache/Cypress - YARN_CACHE_PATH: | - ~/.pnpm-store FILES_TO_DELETE: | sudo rm -rf "/usr/share/dotnet" sudo rm -rf "/usr/share/swift" @@ -48,7 +47,7 @@ jobs: echo "${{ github.repository_owner }}" > ./workflow/ownerName - name: Upload artifact id: upload-artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: env_for_comment path: workflow/ @@ -60,7 +59,7 @@ jobs: steps: - name: Checkout id: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: token: ${{ secrets.GITHUB_TOKEN }} repository: ${{ github.event.pull_request.head.repo.full_name }} @@ -98,16 +97,81 @@ jobs: steps: - name: Checkout id: checkout-matrix - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: ${{ github.event.pull_request.head.repo.full_name }} ref: ${{ github.event.pull_request.head.ref }} fetch-depth: 0 + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + run_install: false + + - name: Setup Node.js with caching + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'pnpm' + cache-dependency-path: '**/pnpm-lock.yaml' + + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT + + - name: Setup pnpm cache + uses: actions/cache@v4 + with: + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: pnpm-store-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + pnpm-store-${{ runner.os }}- + + - name: Cache Cypress binary + uses: actions/cache@v4 + with: + path: ~/.cache/Cypress + key: cypress-${{ runner.os }}-cypress-13.12.0 + restore-keys: | + cypress-${{ runner.os }}- + + - name: Cache Playwright browsers + uses: actions/cache@v4 + id: playwright-cache + with: + path: ~/.cache/ms-playwright + key: playwright-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + playwright-${{ runner.os }}- + + - name: Set Playwright cache status + run: echo "PLAYWRIGHT_CACHE_HIT=${{ steps.playwright-cache.outputs.cache-hit }}" >> $GITHUB_ENV + + - name: Install dependencies + run: | + echo "Installing all dependencies to populate cache..." + pnpm install --frozen-lockfile --prefer-offline + + - name: Install Cypress + run: npx cypress install + + - name: Install Playwright browsers + run: | + # Install Playwright browsers for projects that have it as a dependency + # This prepares the cache for future migration + if command -v playwright &> /dev/null || [ -f "$(npm root -g)/playwright/cli.js" ]; then + echo "Installing Playwright browsers..." + npx playwright install --with-deps chromium + else + echo "Playwright not found in dependencies, skipping browser installation" + fi + - name: Create matrix id: set-matrix run: | - npm i pnpm -g all="$(pnpm list --filter '*' --only-projects --depth -1 --json)" diff="$(pnpm list --filter '...[origin/master]' --only-projects --depth -1 --json)" matrix="$(node checkChangedWorkspaces.js "$all" "$diff")" @@ -125,34 +189,98 @@ jobs: steps: - name: Checkout id: checkout-e2e - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: ${{ github.event.pull_request.head.repo.full_name }} ref: ${{ github.event.pull_request.head.ref }} fetch-depth: 1 - - name: Install PNPM - id: check-disk-space-before-install-e2e - run: corepack enable + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + run_install: false - - name: Set up node + - name: Setup Node.js with caching id: setup-node - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 cache: 'pnpm' + cache-dependency-path: '**/pnpm-lock.yaml' + + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT + + - name: Restore pnpm cache + uses: actions/cache/restore@v4 + id: pnpm-store-cache + with: + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: pnpm-store-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + pnpm-store-${{ runner.os }}- + fail-on-cache-miss: false - - name: Install deps + - name: Restore Cypress cache + uses: actions/cache/restore@v4 + id: cypress-cache + with: + path: ~/.cache/Cypress + key: cypress-${{ runner.os }}-cypress-13.12.0 + restore-keys: | + cypress-${{ runner.os }}- + fail-on-cache-miss: false + + - name: Restore Playwright cache + if: matrix.container == 'bi-directional' + uses: actions/cache/restore@v4 + id: playwright-cache + with: + path: ~/.cache/ms-playwright + key: playwright-${{ runner.os }}-1.54.2 + restore-keys: | + playwright-${{ runner.os }}- + fail-on-cache-miss: false + + - name: Install dependencies id: install-deps-e2e - if: steps.restore-yarn-global-cache-e2e.outputs.cache-hit != 'true' env: - NODE_OPTIONS: '--max_old_space_size=4096' + NODE_OPTIONS: '--max_old_space_size=6144' + FORCE_COLOR: 3 run: | - echo "PNPM changed - install deps ... " - npm i pnpm -g - pnpm i --frozen-lockfile - npx cypress install - npx cypress verify + echo "Installing dependencies from cached pnpm store..." + pnpm install --frozen-lockfile --prefer-offline + + # Verify Cypress if needed + if [ "${{ steps.cypress-cache.outputs.cache-hit }}" != "true" ]; then + echo "Installing Cypress binary..." + npx cypress install + else + echo "Cypress binary already cached" + npx cypress verify || true + fi + + - name: Install Playwright for projects that need it + run: | + if [ "${{ matrix.container }}" = "bi-directional" ]; then + echo "Setting up Playwright for bi-directional example..." + cd ${{ matrix.container }} + + # Check if we need to install Playwright browsers + if [ ! -d "$HOME/.cache/ms-playwright" ] || [ -z "$(ls -A $HOME/.cache/ms-playwright 2>/dev/null)" ]; then + echo "Installing Playwright browsers and dependencies..." + npx playwright install --with-deps chromium + else + echo "Playwright browsers already cached, installing system dependencies only..." + npx playwright install-deps chromium + fi + + cd .. + fi - name: Run sample webpack e2e tests timeout-minutes: 30 @@ -172,7 +300,7 @@ jobs: - name: Create artifacts for Allure report id: create-artifacts-allure-report - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: allure-results diff --git a/.github/workflows/on-push.yml b/.github/workflows/on-push.yml index e40ece98391..df61da4cae1 100644 --- a/.github/workflows/on-push.yml +++ b/.github/workflows/on-push.yml @@ -4,11 +4,11 @@ on: branches: - master +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + env: - CACHE_PATH: | - **/node_modules - ~/.cache/Cypress - ~/.pnpm-store FILES_TO_DELETE: | sudo rm -rf "/usr/share/dotnet" sudo rm -rf "/usr/share/swift" @@ -42,7 +42,7 @@ jobs: yarnHash: ${{ steps.set-matrix.outputs.matrix }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: ${{ github.event.pull_request.head.repo.full_name }} ref: ${{ github.event.pull_request.head.ref }} @@ -58,17 +58,78 @@ jobs: yarnHash="$(npx hash-files -f '["**/pnpm-lock.yaml"]' -a sha256)" echo "yarnHash=$yarnHash" >> $GITHUB_OUTPUT - - name: Cache Yarn and Cypress - uses: actions/cache@v3 - id: yarn-cache + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + run_install: false + + - name: Setup Node.js with caching + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'pnpm' + cache-dependency-path: '**/pnpm-lock.yaml' + + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT + + - name: Setup pnpm cache + uses: actions/cache@v4 + id: pnpm-store-cache with: - path: ${{ env.CACHE_PATH }} - key: e2e-cache-${{ steps.yarn-hash.outputs.yarnHash }} + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: pnpm-store-${{ runner.os }}-${{ steps.yarn-hash.outputs.yarnHash }} + restore-keys: | + pnpm-store-${{ runner.os }}- + + - name: Cache Cypress binary + uses: actions/cache@v4 + with: + path: ~/.cache/Cypress + key: cypress-${{ runner.os }}-cypress-13.12.0 + restore-keys: | + cypress-${{ runner.os }}- + + - name: Cache Playwright browsers + uses: actions/cache@v4 + id: playwright-cache + with: + path: ~/.cache/ms-playwright + key: playwright-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + playwright-${{ runner.os }}- + + - name: Set Playwright cache status + run: echo "PLAYWRIGHT_CACHE_HIT=${{ steps.playwright-cache.outputs.cache-hit }}" >> $GITHUB_ENV - name: Install deps - if: steps.yarn-cache.outputs.cache-hit != 'true' env: - NODE_OPTIONS: '--max_old_space_size=4096' + NODE_OPTIONS: '--max_old_space_size=6144' + FORCE_COLOR: 3 + run: | + echo "Installing dependencies from pnpm store..." + pnpm install --frozen-lockfile --prefer-offline + + - name: Install Cypress + run: | + # Install Cypress binary if not cached + if [ -z "$(ls -A ~/.cache/Cypress 2>/dev/null)" ]; then + echo "Installing Cypress binary..." + npx cypress install + else + echo "Cypress binary already cached" + fi + + - name: Install Playwright browsers run: | - echo "Yarn changed - install deps ... " - pnpm install + # Install Playwright browsers for projects that have it as a dependency + if command -v playwright &> /dev/null || [ -f "$(npm root -g)/playwright/cli.js" ]; then + echo "Installing Playwright browsers..." + npx playwright install --with-deps chromium + else + echo "Playwright not found in dependencies, skipping browser installation" + fi diff --git a/.github/workflows/on-schedule.yml b/.github/workflows/on-schedule.yml index 4409f1e8d09..37a65bbd0de 100644 --- a/.github/workflows/on-schedule.yml +++ b/.github/workflows/on-schedule.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Cleanup unused cache - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/on-workflow-run.yml b/.github/workflows/on-workflow-run.yml index 71be7a9c58f..ed486917b5e 100644 --- a/.github/workflows/on-workflow-run.yml +++ b/.github/workflows/on-workflow-run.yml @@ -26,7 +26,7 @@ jobs: steps: - name: Check if allure artifacts exist id: check-artifacts-exist - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const artifacts = await github.rest.actions.listWorkflowRunArtifacts({ @@ -47,7 +47,7 @@ jobs: if: ${{ needs.check-if-allure-artifacts-exist.outputs.artifacts-exist != 'false' }} steps: - name: Dowload artifacts - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const artifacts = await github.rest.actions.listWorkflowRunArtifacts({ @@ -69,7 +69,7 @@ jobs: fs.writeFileSync('${{github.workspace}}/allure-results.zip', Buffer.from(download.data)); - run: unzip allure-results.zip - name: Get Allure history - uses: actions/checkout@v3 + uses: actions/checkout@v4 if: always() continue-on-error: true with: @@ -86,11 +86,11 @@ jobs: - name: Deploy report to Github Pages if: always() - uses: peaceiris/actions-gh-pages@v2 - env: - PERSONAL_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PUBLISH_BRANCH: gh-pages - PUBLISH_DIR: allure-history + uses: peaceiris/actions-gh-pages@v4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_branch: gh-pages + publish_dir: allure-history # Comment to PR, Add labels to PR, Remove unnecessary labels actions-with-pr: @@ -99,7 +99,7 @@ jobs: if: always() && github.event.workflow_run.event == 'pull_request' steps: - name: 'Download artifact' - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const artifacts = await github.rest.actions.listWorkflowRunArtifacts({ @@ -125,7 +125,7 @@ jobs: - name: 'Comment to PR -- if report generated' if: needs.generate-allure-report.result == 'success' - uses: actions/github-script@v6 + uses: actions/github-script@v7 env: WORKFLOW_CONCLUSION: ${{ github.event.workflow_run.conclusion }} with: @@ -148,7 +148,7 @@ jobs: - name: 'Comment to PR -- if report wasnt generated' if: needs.generate-allure-report.result == 'skipped' - uses: actions/github-script@v6 + uses: actions/github-script@v7 env: WORKFLOW_CONCLUSION: ${{ github.event.workflow_run.conclusion }} with: @@ -171,7 +171,7 @@ jobs: - name: Remove old lables if: always() - uses: actions/github-script@v6 + uses: actions/github-script@v7 env: WORKFLOW_CONCLUSION: ${{ github.event.workflow_run.conclusion }} GENERAT_ALLURE_REPORT_STATUS: ${{ needs.generate-allure-report.result }} @@ -207,7 +207,7 @@ jobs: - name: 'Add e2e label to PR -- if report generated' if: needs.generate-allure-report.result == 'success' - uses: actions/github-script@v6 + uses: actions/github-script@v7 env: WORKFLOW_CONCLUSION: ${{ github.event.workflow_run.conclusion }} with: @@ -225,7 +225,7 @@ jobs: - name: 'Add workflow label to PR' if: always() - uses: actions/github-script@v6 + uses: actions/github-script@v7 env: WORKFLOW_CONCLUSION: ${{ github.event.workflow_run.conclusion }} with: diff --git a/.gitignore b/.gitignore index 04683cc5d43..e5a6966746d 100644 --- a/.gitignore +++ b/.gitignore @@ -130,6 +130,10 @@ buildServer **/cypress/screenshots/** **/cypress/results/** **/cypress/report/** + +# Playwright folders +**/playwright-report/** +**/test-results/** /federated-express-routes/host/build/ /federated-express-routes/remote/build/ /comprehensive-demo-react*/**/public/*.js diff --git a/advanced-api/automatic-vendor-sharing/app1/package.json b/advanced-api/automatic-vendor-sharing/app1/package.json index f0cb9258113..fd6ab8552a6 100644 --- a/advanced-api/automatic-vendor-sharing/app1/package.json +++ b/advanced-api/automatic-vendor-sharing/app1/package.json @@ -4,14 +4,14 @@ "devDependencies": { "@babel/core": "7.24.7", "@babel/preset-react": "7.24.7", - "@module-federation/enhanced": "0.7.3", - "@rspack/cli": "1.1.1", - "@rspack/core": "1.1.1", - "@rspack/dev-server": "1.0.9", + "@module-federation/enhanced": "0.17.1", + "@rspack/cli": "1.4.11", + "@rspack/core": "1.4.11", + "@rspack/dev-server": "1.1.3", "babel-loader": "9.1.3", "html-webpack-plugin": "5.6.0", "serve": "14.2.3", - "webpack": "5.96.1", + "webpack": "5.101.0", "webpack-cli": "5.1.4", "webpack-dev-server": "5.0.4" }, diff --git a/advanced-api/automatic-vendor-sharing/app2/package.json b/advanced-api/automatic-vendor-sharing/app2/package.json index 2253c2f2482..a7891c71277 100644 --- a/advanced-api/automatic-vendor-sharing/app2/package.json +++ b/advanced-api/automatic-vendor-sharing/app2/package.json @@ -4,14 +4,14 @@ "devDependencies": { "@babel/core": "7.24.7", "@babel/preset-react": "7.24.7", - "@module-federation/enhanced": "0.7.3", - "@rspack/cli": "1.1.1", - "@rspack/core": "1.1.1", - "@rspack/dev-server": "1.0.9", + "@module-federation/enhanced": "0.17.1", + "@rspack/cli": "1.4.11", + "@rspack/core": "1.4.11", + "@rspack/dev-server": "1.1.3", "babel-loader": "9.1.3", "html-webpack-plugin": "5.6.0", "serve": "14.2.3", - "webpack": "5.96.1", + "webpack": "5.101.0", "webpack-cli": "5.1.4", "webpack-dev-server": "5.0.4" }, diff --git a/advanced-api/dynamic-remotes-runtime-environment-variables/host/package.json b/advanced-api/dynamic-remotes-runtime-environment-variables/host/package.json index a9bcc7b187b..d44809eeb1f 100644 --- a/advanced-api/dynamic-remotes-runtime-environment-variables/host/package.json +++ b/advanced-api/dynamic-remotes-runtime-environment-variables/host/package.json @@ -4,16 +4,16 @@ "devDependencies": { "@babel/core": "7.24.7", "@babel/preset-react": "7.24.7", - "@module-federation/enhanced": "0.7.3", - "@module-federation/runtime": "0.7.3", - "@rspack/cli": "1.1.1", - "@rspack/core": "1.1.1", - "@rspack/dev-server": "1.0.9", + "@module-federation/enhanced": "0.17.1", + "@module-federation/runtime": "0.17.1", + "@rspack/cli": "1.4.11", + "@rspack/core": "1.4.11", + "@rspack/dev-server": "1.1.3", "babel-loader": "9.1.3", "copy-webpack-plugin": "12.0.2", "html-webpack-plugin": "5.6.0", "serve": "14.2.3", - "webpack": "5.96.1", + "webpack": "5.101.0", "webpack-cli": "5.1.4", "webpack-dev-server": "5.0.4" }, diff --git a/advanced-api/dynamic-remotes-runtime-environment-variables/remote/package.json b/advanced-api/dynamic-remotes-runtime-environment-variables/remote/package.json index ae4ccd5acb2..c9251ce7571 100644 --- a/advanced-api/dynamic-remotes-runtime-environment-variables/remote/package.json +++ b/advanced-api/dynamic-remotes-runtime-environment-variables/remote/package.json @@ -4,14 +4,14 @@ "devDependencies": { "@babel/core": "7.24.7", "@babel/preset-react": "7.24.7", - "@module-federation/enhanced": "0.7.3", - "@rspack/cli": "1.1.1", - "@rspack/core": "1.1.1", - "@rspack/dev-server": "1.0.9", + "@module-federation/enhanced": "0.17.1", + "@rspack/cli": "1.4.11", + "@rspack/core": "1.4.11", + "@rspack/dev-server": "1.1.3", "babel-loader": "9.1.3", "html-webpack-plugin": "5.6.0", "serve": "14.2.3", - "webpack": "5.96.1", + "webpack": "5.101.0", "webpack-cli": "5.1.4", "webpack-dev-server": "5.0.4" }, diff --git a/advanced-api/dynamic-remotes-synchronous-imports/app1/package.json b/advanced-api/dynamic-remotes-synchronous-imports/app1/package.json index 1cb74505824..77ec3a77036 100644 --- a/advanced-api/dynamic-remotes-synchronous-imports/app1/package.json +++ b/advanced-api/dynamic-remotes-synchronous-imports/app1/package.json @@ -4,11 +4,11 @@ "devDependencies": { "@babel/core": "7.24.7", "@babel/preset-react": "7.24.7", - "@module-federation/enhanced": "0.7.3", + "@module-federation/enhanced": "0.17.1", "babel-loader": "9.1.3", "html-webpack-plugin": "5.6.0", "serve": "14.2.3", - "webpack": "5.96.1", + "webpack": "5.101.0", "webpack-cli": "5.1.4", "webpack-dev-server": "5.0.4" }, diff --git a/advanced-api/dynamic-remotes-synchronous-imports/app2/package.json b/advanced-api/dynamic-remotes-synchronous-imports/app2/package.json index 189342548a5..e4de469391f 100644 --- a/advanced-api/dynamic-remotes-synchronous-imports/app2/package.json +++ b/advanced-api/dynamic-remotes-synchronous-imports/app2/package.json @@ -4,11 +4,11 @@ "devDependencies": { "@babel/core": "7.24.7", "@babel/preset-react": "7.24.7", - "@module-federation/enhanced": "0.7.3", + "@module-federation/enhanced": "0.17.1", "babel-loader": "9.1.3", "html-webpack-plugin": "5.6.0", "serve": "14.2.3", - "webpack": "5.96.1", + "webpack": "5.101.0", "webpack-cli": "5.1.4", "webpack-dev-server": "5.0.4" }, diff --git a/advanced-api/dynamic-remotes/app1/package.json b/advanced-api/dynamic-remotes/app1/package.json index a517f920d59..272b987efb9 100644 --- a/advanced-api/dynamic-remotes/app1/package.json +++ b/advanced-api/dynamic-remotes/app1/package.json @@ -4,15 +4,15 @@ "devDependencies": { "@babel/core": "7.24.7", "@babel/preset-react": "7.24.7", - "@module-federation/enhanced": "0.7.3", - "@module-federation/runtime": "0.7.3", - "@rspack/cli": "1.1.1", - "@rspack/core": "1.1.1", - "@rspack/dev-server": "1.0.9", + "@module-federation/enhanced": "0.17.1", + "@module-federation/runtime": "0.17.1", + "@rspack/cli": "1.4.11", + "@rspack/core": "1.4.11", + "@rspack/dev-server": "1.1.3", "babel-loader": "9.1.3", "html-webpack-plugin": "5.6.0", "serve": "14.2.3", - "webpack": "5.96.1", + "webpack": "5.101.0", "webpack-cli": "5.1.4", "webpack-dev-server": "5.0.4" }, diff --git a/advanced-api/dynamic-remotes/app2/package.json b/advanced-api/dynamic-remotes/app2/package.json index 65d72861caa..59b1abb1e5a 100644 --- a/advanced-api/dynamic-remotes/app2/package.json +++ b/advanced-api/dynamic-remotes/app2/package.json @@ -4,14 +4,14 @@ "devDependencies": { "@babel/core": "7.24.7", "@babel/preset-react": "7.24.7", - "@module-federation/enhanced": "0.7.3", - "@rspack/cli": "1.1.1", - "@rspack/core": "1.1.1", - "@rspack/dev-server": "1.0.9", + "@module-federation/enhanced": "0.17.1", + "@rspack/cli": "1.4.11", + "@rspack/core": "1.4.11", + "@rspack/dev-server": "1.1.3", "babel-loader": "9.1.3", "html-webpack-plugin": "5.6.0", "serve": "14.2.3", - "webpack": "5.96.1", + "webpack": "5.101.0", "webpack-cli": "5.1.4", "webpack-dev-server": "5.0.4" }, diff --git a/advanced-api/dynamic-remotes/app3/package.json b/advanced-api/dynamic-remotes/app3/package.json index 68f55ff3524..7cb78abf367 100644 --- a/advanced-api/dynamic-remotes/app3/package.json +++ b/advanced-api/dynamic-remotes/app3/package.json @@ -4,14 +4,14 @@ "devDependencies": { "@babel/core": "7.24.7", "@babel/preset-react": "7.24.7", - "@module-federation/enhanced": "0.7.3", - "@rspack/cli": "1.1.1", - "@rspack/core": "1.1.1", - "@rspack/dev-server": "1.0.9", + "@module-federation/enhanced": "0.17.1", + "@rspack/cli": "1.4.11", + "@rspack/core": "1.4.11", + "@rspack/dev-server": "1.1.3", "babel-loader": "9.1.3", "html-webpack-plugin": "5.6.0", "serve": "14.2.3", - "webpack": "5.96.1", + "webpack": "5.101.0", "webpack-cli": "5.1.4", "webpack-dev-server": "5.0.4" }, diff --git a/angular-universal-ssr/client-app/package.json b/angular-universal-ssr/client-app/package.json index 309fc8f62f5..5072fc4ca24 100644 --- a/angular-universal-ssr/client-app/package.json +++ b/angular-universal-ssr/client-app/package.json @@ -40,7 +40,7 @@ "ts-node": "10.9.2", "tslint": "6.1.3", "typescript": "5.5.3", - "webpack": "5.96.1", + "webpack": "5.101.0", "webpack-cli": "5.1.4" } } \ No newline at end of file diff --git a/angular-universal-ssr/host-app/package.json b/angular-universal-ssr/host-app/package.json index ef27235ac99..ce70dffdf72 100644 --- a/angular-universal-ssr/host-app/package.json +++ b/angular-universal-ssr/host-app/package.json @@ -44,7 +44,7 @@ "ts-node": "10.9.2", "tslint": "6.1.3", "typescript": "5.5.3", - "webpack": "5.96.1", + "webpack": "5.101.0", "webpack-cli": "5.1.4" } } \ No newline at end of file diff --git a/apollo-client/app1/package.json b/apollo-client/app1/package.json index 1c40ee14661..bdeef431fa8 100644 --- a/apollo-client/app1/package.json +++ b/apollo-client/app1/package.json @@ -31,10 +31,10 @@ "@babel/preset-env": "7.24.7", "@babel/preset-react": "7.24.7", "@babel/preset-typescript": "7.24.7", - "@module-federation/node": "2.6.8", - "@rspack/cli": "1.1.1", - "@rspack/core": "1.1.1", - "@rspack/dev-server": "1.0.9", + "@module-federation/node": "2.7.10", + "@rspack/cli": "1.4.11", + "@rspack/core": "1.4.11", + "@rspack/dev-server": "1.1.3", "@types/express": "4.17.21", "@types/react": "18.3.3", "@types/react-dom": "18.3.0", @@ -42,7 +42,7 @@ "@types/serialize-javascript": "5.0.4", "babel-loader": "9.1.3", "rimraf": "5.0.8", - "webpack": "5.96.1", + "webpack": "5.101.0", "webpack-cli": "5.1.4", "webpack-merge": "6.0.1" } diff --git a/apollo-client/app2/package.json b/apollo-client/app2/package.json index f96bca72e31..48901f21691 100644 --- a/apollo-client/app2/package.json +++ b/apollo-client/app2/package.json @@ -31,10 +31,10 @@ "@babel/preset-env": "7.24.7", "@babel/preset-react": "7.24.7", "@babel/preset-typescript": "7.24.7", - "@module-federation/node": "2.6.8", - "@rspack/cli": "1.1.1", - "@rspack/core": "1.1.1", - "@rspack/dev-server": "1.0.9", + "@module-federation/node": "2.7.10", + "@rspack/cli": "1.4.11", + "@rspack/core": "1.4.11", + "@rspack/dev-server": "1.1.3", "@types/express": "4.17.21", "@types/react": "18.3.3", "@types/react-dom": "18.3.0", @@ -42,7 +42,7 @@ "@types/serialize-javascript": "5.0.4", "babel-loader": "9.1.3", "rimraf": "5.0.8", - "webpack": "5.96.1", + "webpack": "5.101.0", "webpack-cli": "5.1.4", "webpack-merge": "6.0.1" } diff --git a/basic-host-remote/app1/package.json b/basic-host-remote/app1/package.json index 3f8437b49a7..385598611bd 100644 --- a/basic-host-remote/app1/package.json +++ b/basic-host-remote/app1/package.json @@ -37,7 +37,7 @@ "@modern-js/builder-rspack-provider": "2.46.1", "@modern-js/eslint-config": "2.54.6", "@modern-js/tsconfig": "2.54.6", - "@module-federation/enhanced": "0.7.3", + "@module-federation/enhanced": "0.17.1", "husky": "9.0.11", "lint-staged": "15.2.10", "prettier": "3.3.2", diff --git a/basic-host-remote/app2/package.json b/basic-host-remote/app2/package.json index f401662842e..3bda4e0b63a 100644 --- a/basic-host-remote/app2/package.json +++ b/basic-host-remote/app2/package.json @@ -37,7 +37,7 @@ "@modern-js/builder-rspack-provider": "2.46.1", "@modern-js/eslint-config": "2.54.6", "@modern-js/tsconfig": "2.54.6", - "@module-federation/enhanced": "0.7.3", + "@module-federation/enhanced": "0.17.1", "husky": "9.0.11", "lint-staged": "15.2.7", "prettier": "3.3.2", diff --git a/bi-directional/README.md b/bi-directional/README.md index 4c04c6c94cf..f08bd015a34 100644 --- a/bi-directional/README.md +++ b/bi-directional/README.md @@ -1,24 +1,81 @@ # Bi-Directional Hosts Example -This example demos bi-directional hosts each with their own remote `Button` components. +This example demonstrates bi-directional module federation using Modern.js, where each application can both expose and consume federated modules from each other. -- `app1` exposes a red `` component. -- `app2` exposes a blue `` component. +- `app1` exposes a red `` component and consumes `app2`'s button. +- `app2` exposes a blue `` component and consumes `app1`'s button. -# Running Demo +## Technology Stack -Run `pnpm run start`. This will build and serve both `app1` and `app2` on ports 3001 and 3002 respectively. +- **Framework**: Modern.js v2.68.6 +- **Module Federation**: @module-federation/modern-js v0.17.1 +- **Testing**: Playwright for end-to-end testing +- **Build Tool**: Rspack (via Modern.js) -- [localhost:3001](http://localhost:3001/) -- [localhost:3002](http://localhost:3002/) +## Running Demo -Notice that `app1` will asynchronously load `app2`'s button and vice versa. - +Run `pnpm run start`. This will start both `app1` and `app2` in development mode on ports 3001 and 3002 respectively. -# Running Cypress E2E Tests +- [localhost:3001](http://localhost:3001/) - App1 hosting App2's button +- [localhost:3002](http://localhost:3002/) - App2 hosting App1's button -To run tests in interactive mode, run `npm run cypress:debug` from the root directory of the project. It will open Cypress Test Runner and allow to run tests in interactive mode. [More info about "How to run tests"](../../cypress-e2e/README.md#how-to-run-tests) +Notice that each app will asynchronously load the other app's federated button component using React Suspense. -To build app and run test in headless mode, run `yarn e2e:ci`. It will build app and run tests for this workspace in headless mode. If tets failed cypress will create `cypress` directory in sample root folder with screenshots and videos. +## Available Scripts -["Best Practices, Rules amd more interesting information here](../../cypress-e2e/README.md) +- `pnpm start` - Start both apps in development mode +- `pnpm build` - Build both apps for production +- `pnpm serve` - Serve built apps in production mode +- `pnpm test:e2e` - Run Playwright tests in headless mode +- `pnpm test:e2e:ui` - Run Playwright tests with UI mode +- `pnpm test:e2e:debug` - Run Playwright tests in debug mode +- `pnpm e2e:ci` - Build and run tests for CI + +## Module Federation Configuration + +Each app uses a `module-federation.config.ts` file to configure: +- **Exposed modules**: Components shared with other apps +- **Remote modules**: Components consumed from other apps +- **Shared dependencies**: React and React-DOM with singleton strategy + +## End-to-End Testing with Playwright + +This example includes comprehensive Playwright tests that verify: + +- ✅ Both applications load correctly +- ✅ Federated components render properly +- ✅ Bi-directional communication works +- ✅ Error handling for module loading failures +- ✅ Cross-app interaction and state management + +### Running Tests + +```bash +# Run tests in headless mode +pnpm test:e2e + +# Run tests with interactive UI +pnpm test:e2e:ui + +# Run tests in debug mode +pnpm test:e2e:debug + +# Run tests for CI (build first) +pnpm e2e:ci +``` + +### Test Architecture + +The test suite includes: +- **Page Objects**: Reusable test utilities in `e2e/utils/` +- **Test Fixtures**: Shared setup and teardown logic +- **Comprehensive Coverage**: All module federation scenarios +- **Error Scenarios**: Graceful handling of federation failures + +## Key Features Demonstrated + +1. **Bi-directional Federation**: Apps both expose and consume modules +2. **React Suspense Integration**: Lazy loading with fallback UI +3. **Modern.js Framework**: Latest patterns and best practices +4. **Production-Ready Testing**: Comprehensive Playwright test suite +5. **TypeScript Support**: Full type safety across federated modules diff --git a/bi-directional/app1/.vscode/extensions.json b/bi-directional/app1/.vscode/extensions.json deleted file mode 100644 index f5aedcc3580..00000000000 --- a/bi-directional/app1/.vscode/extensions.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "recommendations": [ - "styled-components.vscode-styled-components", - "cpylua.language-postcss", - "EditorConfig.editorconfig", - "dbaeumer.vscode-eslint", - "esbenp.prettier-vscode", - "drKnoxy.eslint-disable-snippets", - "mkaufman.htmlhint", - "streetsidesoftware.code-spell-checker", - "codezombiech.gitignore", - "aaron-bond.better-comments", - "jasonnutter.search-node-modules", - "jock.svg", - "mikestead.dotenv", - "vscode-icons-team.vscode-icons" - ] -} diff --git a/bi-directional/app1/.vscode/settings.json b/bi-directional/app1/.vscode/settings.json deleted file mode 100644 index 34a83cee798..00000000000 --- a/bi-directional/app1/.vscode/settings.json +++ /dev/null @@ -1,83 +0,0 @@ -{ - "files.associations": { - ".code-workspace": "jsonc", - ".babelrc": "json", - ".eslintrc": "jsonc", - ".eslintrc*.json": "jsonc", - ".stylelintrc": "jsonc", - "stylelintrc": "jsonc", - ".htmlhintrc": "jsonc", - "htmlhintrc": "jsonc", - "Procfile*": "shellscript", - "README": "markdown" - }, - "search.useIgnoreFiles": true, - "search.exclude": { - "**/dist": true, - "**/*.log": true, - "**/*.pid": true, - "**/.git": true, - "**/node_modules": true, - "**/bower_components": true - }, - // - "editor.rulers": [80, 120], - "files.eol": "\n", - "files.trimTrailingWhitespace": true, - "files.insertFinalNewline": true, - // - "cSpell.diagnosticLevel": "Hint", - "eslint.alwaysShowStatus": true, - "eslint.run": "onType", - "eslint.probe": [ - "javascript", - "javascriptreact", - "typescript", - "typescriptreact", - "vue" - ], - "eslint.format.enable": true, - "eslint.lintTask.enable": true, - "javascript.validate.enable": false, - "typescript.validate.enable": true, - "css.validate": false, - "scss.validate": false, - "less.validate": false, - "[css]": { - "editor.formatOnType": true, - "editor.formatOnPaste": true, - "editor.formatOnSave": true - }, - "[scss]": { - "editor.formatOnType": true, - "editor.formatOnPaste": true, - "editor.formatOnSave": true - }, - "[less]": { - "editor.formatOnType": true, - "editor.formatOnPaste": true, - "editor.formatOnSave": true - }, - "editor.codeActionsOnSave": { - "source.fixAll.eslint": true - }, - "editor.defaultFormatter": "esbenp.prettier-vscode", - "javascript.format.enable": false, - "typescript.format.enable": false, - // - "json.format.enable": false, - "[json]": { - "editor.tabSize": 2, - "editor.formatOnType": true, - "editor.formatOnPaste": true, - "editor.formatOnSave": true - }, - "[jsonc]": { - "editor.tabSize": 2, - "editor.formatOnType": true, - "editor.formatOnPaste": true, - "editor.formatOnSave": true - }, - "emmet.triggerExpansionOnTab": true, - "typescript.tsdk": "node_modules/typescript/lib" -} diff --git a/bi-directional/app1/README.md b/bi-directional/app1/README.md index cafe03f77ba..d848748b897 100644 --- a/bi-directional/app1/README.md +++ b/bi-directional/app1/README.md @@ -1,37 +1,71 @@ -# Modern.js App +# App1 - Module Federation Host/Remote + +This is the first application in the bi-directional module federation example. It both exposes and consumes federated modules. + +## Module Federation Setup + +**Exposes:** +- `./Button` - Red button component (`src/components/button.js`) + +**Consumes:** +- `app2/Button` - Blue button component from App2 + +**Port:** 3001 ## Setup Install the dependencies: ```bash -yarn install +pnpm install ``` ## Get Started Start the dev server: -``` -yarn dev -``` - -Enable optional features or add a new entry: - -``` -yarn new +```bash +pnpm dev ``` Build the app for production: -``` -yarn build +```bash +pnpm build ``` Preview the production build locally: +```bash +pnpm serve ``` -yarn serve + +## Module Federation Configuration + +The module federation setup is configured in `module-federation.config.ts`: + +```typescript +export default createModuleFederationConfig({ + name: 'app1', + remotes: { + app2: 'app2@http://localhost:3002/mf-manifest.json', + }, + exposes: { + './Button': './src/components/button.js', + }, + shared: { + react: { singleton: true }, + 'react-dom': { singleton: true }, + }, + dts: false, +}); ``` +## Key Features + +- **React Suspense**: Uses lazy loading for federated components +- **Modern.js Framework**: Built with Modern.js v2.68.6 +- **TypeScript Support**: Full type safety across federated modules +- **Error Boundaries**: Graceful handling of federation failures + For more information, see the [Modern.js documentation](https://modernjs.dev/en). diff --git a/bi-directional/app1/modern.config.js b/bi-directional/app1/modern.config.js index 0b6f3a4b165..1bab1914fd6 100644 --- a/bi-directional/app1/modern.config.js +++ b/bi-directional/app1/modern.config.js @@ -1,41 +1,32 @@ -import appTools, { defineConfig } from '@modern-js/app-tools'; -import { ModuleFederationPlugin } from '@module-federation/enhanced/webpack'; +import { appTools, defineConfig } from '@modern-js/app-tools'; +import { moduleFederationPlugin } from '@module-federation/modern-js'; + // https://modernjs.dev/en/configure/app/usage export default defineConfig({ + dev: { + port: 3001, + }, server: { port: 3001, + ssr: false, // Disable SSR completely for client-side rendering }, runtime: { router: true, }, source: { - enableAsyncEntry: true, // Enable async entry for module federation + enableAsyncEntry: true, // Ensure async entry for module federation }, tools: { - webpack: (config, { webpack, appendPlugins }) => { - // Remove splitChunks optimization - delete config.optimization.splitChunks; - config.output.publicPath = 'auto'; - - // Add Module Federation Plugin - appendPlugins([ - new ModuleFederationPlugin({ - name: 'app1', - filename: 'static/js/remoteEntry.js', - exposes: { - './Button': './src/components/button.js', - }, - remotes: { - app2: 'app2@http://localhost:3002/static/js/remoteEntry.js', - }, - shared: { - react: { singleton: true }, - 'react-dom': { singleton: true }, - }, - runtimePlugins: ['./single-runtime-plugin.js'], - }), - ]); + devServer: { + headers: { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization', + }, }, }, - plugins: [appTools()], + plugins: [ + appTools(), + moduleFederationPlugin() + ], }); diff --git a/bi-directional/app1/module-federation.config.ts b/bi-directional/app1/module-federation.config.ts new file mode 100644 index 00000000000..903c8a1ce57 --- /dev/null +++ b/bi-directional/app1/module-federation.config.ts @@ -0,0 +1,16 @@ +import { createModuleFederationConfig } from '@module-federation/modern-js'; + +export default createModuleFederationConfig({ + name: 'app1', + remotes: { + app2: 'app2@http://localhost:3002/mf-manifest.json', + }, + exposes: { + './Button': './src/components/button.js', + }, + shared: { + react: { singleton: true }, + 'react-dom': { singleton: true }, + }, + dts: false, +}); \ No newline at end of file diff --git a/bi-directional/app1/package.json b/bi-directional/app1/package.json index 88280f108f2..18d1b12efb3 100644 --- a/bi-directional/app1/package.json +++ b/bi-directional/app1/package.json @@ -27,17 +27,18 @@ "dist/" ], "dependencies": { - "@modern-js/runtime": "2.54.6", + "@modern-js/runtime": "2.68.6", + "@module-federation/modern-js": "0.17.1", "react": "~18.3.0", "react-dom": "~18.3.0" }, "devDependencies": { - "@modern-js-app/eslint-config": "2.54.6", - "@modern-js/app-tools": "2.54.6", + "@modern-js-app/eslint-config": "2.59.0", + "@modern-js/app-tools": "2.68.6", "@modern-js/builder-rspack-provider": "2.46.1", - "@modern-js/eslint-config": "2.54.6", - "@modern-js/tsconfig": "2.54.6", - "@module-federation/enhanced": "0.7.3", + "@modern-js/eslint-config": "2.59.0", + "@modern-js/tsconfig": "2.68.6", + "@module-federation/enhanced": "0.17.1", "husky": "9.0.11", "lint-staged": "15.2.7", "prettier": "3.3.2", diff --git a/bi-directional/app1/src/routes/page.jsx b/bi-directional/app1/src/routes/page.jsx index ee88bd3e704..571d823e46d 100644 --- a/bi-directional/app1/src/routes/page.jsx +++ b/bi-directional/app1/src/routes/page.jsx @@ -1,6 +1,8 @@ import { Helmet } from '@modern-js/runtime/head'; +import { Suspense, lazy } from 'react'; import './index.css'; -import Button from 'app2/Button'; + +const Button = lazy(() => import('app2/Button')); const Index = () => (
@@ -22,7 +24,9 @@ const Index = () => (

Modern.js Bidirectional Host Example

- FEDERATED: