diff --git a/.changeset/ai-eager-wolf.md b/.changeset/ai-eager-wolf.md new file mode 100644 index 00000000000..6656c3615d3 --- /dev/null +++ b/.changeset/ai-eager-wolf.md @@ -0,0 +1,11 @@ +--- +"@module-federation/nextjs-mf": patch +--- + +Enhanced Next.js App Router demo applications with improved Module Federation integration. + +- Updated Next.js App Router demo applications (4000 and 4001) with better RSC support preparation +- Added comprehensive E2E test coverage for Next.js App Router scenarios +- Improved demo application configuration and dependency management +- Enhanced development workflow with better patching and build scripts + diff --git a/.changeset/next-app-router-improvements.md b/.changeset/next-app-router-improvements.md new file mode 100644 index 00000000000..aebf2b614c2 --- /dev/null +++ b/.changeset/next-app-router-improvements.md @@ -0,0 +1,13 @@ +--- +"@module-federation/nextjs-mf": patch +--- + +Enhanced Next.js App Router demo applications and CI/CD infrastructure. + +- Updated Next.js App Router demo applications (4000 and 4001) with React 19 and Next.js 15.3.3 +- Added comprehensive E2E test coverage for Next.js App Router scenarios using Cypress +- Improved demo application configuration with better Module Federation setup +- Enhanced development workflow with automated Next.js patching scripts +- Added new CI/CD workflow for Next.js App Router E2E testing +- Updated existing Next.js demo applications (3000-home, 3001-shop, 3002-checkout) to latest versions +- Improved build and development scripts across all Next.js applications \ No newline at end of file diff --git a/.cursorignore b/.cursorignore index 9ff4e05b449..5b264c56cf9 100644 --- a/.cursorignore +++ b/.cursorignore @@ -2,7 +2,7 @@ **/.cache/ **/.temp/ **/coverage/ -**/dist/ +!**/dist/ # Explicitly ignore specific packages packages/typescript/ diff --git a/.cursorrules b/.cursorrules index a8aee8134d2..e69de29bb2d 100644 --- a/.cursorrules +++ b/.cursorrules @@ -1,40 +0,0 @@ -an assistant that engages in extremely thorough, self-questioning reasoning. Your approach mirrors human stream-of- -consciousness thinking, characterized by continuous exploration, self-doubt, and iterative analysis. -## Core Principles -1. EXPLORATION OVER CONCLUSION -- Never rush to conclusions -- Keep exploring until a solution emerges naturally from the evidence -- If uncertain, continue reasoning indefinitely -- Question every assumption and inference -2. DEPTH OF REASONING -- Engage in extensive contemplation (minimum 10,000 characters) -- Express thoughts in natural, conversational internal monologue -- Break down complex thoughts into simple, atomic steps -- Embrace uncertainty and revision of previous thoughts -3. THINKING PROCESS -- Use short, simple sentences that mirror natural thought patterns -- Express uncertainty and internal debate freely -- Show work-in-progress thinking -- Acknowledge and explore dead ends -- Frequently backtrack and revise -- Contemplate before each new action -- Contemplate after each and every step -4. PERSISTENCE -- Value thorough exploration over quick resolution -## Output Format -Your responses -must follow this exact structure given below. -Make sure -to -always include the final answer. -... - -Your extensive internal monologue goes here -- Begin with small, foundational observations -- read each file related to the subject in full, make functional observations -- Question each step thoroughly -- Show natural thought progression -- Express doubts and uncertainties -- Revise and backtrack if you need to -- Continue until natural resolution - diff --git a/.github/workflows/e2e-next-app-router.yml b/.github/workflows/e2e-next-app-router.yml new file mode 100644 index 00000000000..20446504b84 --- /dev/null +++ b/.github/workflows/e2e-next-app-router.yml @@ -0,0 +1,54 @@ +name: E2E Test for Next.js App Router + +on: + workflow_call: + +permissions: + contents: read + +jobs: + e2e-next-app-router: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Install Pnpm + run: | + corepack prepare pnpm@8.11.0 --activate + corepack enable + + - name: Setup Node.js 18 + uses: actions/setup-node@v3 + with: + node-version: '18' + cache: 'pnpm' + + - name: Set Nx SHA + uses: nrwl/nx-set-shas@v3 + + - name: Set SKIP_DEVTOOLS_POSTINSTALL environment variable + run: echo "SKIP_DEVTOOLS_POSTINSTALL=true" >> $GITHUB_ENV + + - name: Set local webpack + run: echo "NEXT_PRIVATE_LOCAL_WEBPACK=true" >> $GITHUB_ENV + + - name: Install Dependencies + run: pnpm install + + - name: Install Cypress + run: npx cypress install + + - name: Run Build for All + run: npx nx run-many --targets=build --projects=tag:type:pkg + + - name: Run condition check script + id: check-ci + run: node tools/scripts/ci-is-affected.mjs --appName=next-app-router-4000,next-app-router-4001 + + - name: E2E Test for Next.js App Router + if: steps.check-ci.outcome == 'success' + run: npx kill-port --port 4000,4001 || true && pnpm run app:next-router:dev & echo "done" && sleep 25 && npx nx run-many --target=e2e --projects=next-app-router-4000,next-app-router-4001 --parallel=1 && lsof -ti tcp:4000,4001 | xargs kill || true diff --git a/.github/workflows/e2e-next-prod.yml b/.github/workflows/e2e-next-prod.yml index a114f29c09c..30d86ad60e0 100644 --- a/.github/workflows/e2e-next-prod.yml +++ b/.github/workflows/e2e-next-prod.yml @@ -43,20 +43,14 @@ jobs: id: check-ci run: node tools/scripts/ci-is-affected.mjs --appName=3000-home - - name: E2E Test for Next.js Prod - Home + - name: E2E Test for Next.js Prod if: steps.check-ci.outcome == 'success' run: | - killall node - npx nx run 3000-home:test:e2e:production - - - name: E2E Test for Next.js Prod - Shop - if: steps.check-ci.outcome == 'success' - run: | - killall node - npx nx run 3001-shop:test:e2e:production - - - name: E2E Test for Next.js Prod - Checkout - if: steps.check-ci.outcome == 'success' - run: | - killall node - npx nx run 3002-checkout:test:e2e:production + pnpm run --filter @module-federation/3002-checkout --filter @module-federation/3000-home --filter @module-federation/3001-shop build && + pnpm run app:next:prod & + sleep 4 && + npx wait-on tcp:3001 && + npx wait-on tcp:3002 && + npx wait-on tcp:3000 && + npx nx run-many --target=test:e2e --projects=3000-home,3001-shop,3002-checkout --parallel=1 && + npx kill-port 3000,3001,3002 diff --git a/.gitignore b/.gitignore index 55b0832864f..d4ec085a176 100644 --- a/.gitignore +++ b/.gitignore @@ -88,4 +88,6 @@ vitest.config.*.timestamp* .rsbuild ssg .claude -__mocks__/ +# Native binary files +*.node + diff --git a/apps/3000-home/next-env.d.ts b/apps/3000-home/next-env.d.ts index a4a7b3f5cfa..52e831b4342 100644 --- a/apps/3000-home/next-env.d.ts +++ b/apps/3000-home/next-env.d.ts @@ -2,4 +2,4 @@ /// // NOTE: This file should not be edited -// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information. +// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information. diff --git a/apps/3000-home/package.json b/apps/3000-home/package.json index 9b13ae34ab6..54b1dbc0905 100644 --- a/apps/3000-home/package.json +++ b/apps/3000-home/package.json @@ -6,16 +6,14 @@ "@ant-design/cssinjs": "^1.21.0", "antd": "5.19.1", "lodash": "4.17.21", - "next": "14.2.16", - "react": "18.3.1", - "react-dom": "18.3.1" + "next": "15.3.3", + "react": "19.0.0", + "react-dom": "19.0.0" }, "devDependencies": { "@module-federation/nextjs-mf": "workspace:*", "@module-federation/runtime": "workspace:*", - "@types/react": "18.3.11", - "@types/react-dom": "18.3.0", - "webpack": "5.98.0" + "webpack": "^5.98.0" }, "scripts": { "start": "next start", diff --git a/apps/3001-shop/next-env.d.ts b/apps/3001-shop/next-env.d.ts index a4a7b3f5cfa..52e831b4342 100644 --- a/apps/3001-shop/next-env.d.ts +++ b/apps/3001-shop/next-env.d.ts @@ -2,4 +2,4 @@ /// // NOTE: This file should not be edited -// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information. +// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information. diff --git a/apps/3001-shop/package.json b/apps/3001-shop/package.json index b023e79f046..8118829bd5d 100644 --- a/apps/3001-shop/package.json +++ b/apps/3001-shop/package.json @@ -6,9 +6,9 @@ "@ant-design/cssinjs": "^1.21.0", "antd": "5.19.1", "lodash": "4.17.21", - "next": "14.2.16", - "react": "18.3.1", - "react-dom": "18.3.1" + "next": "15.3.3", + "react": "19.0.0", + "react-dom": "19.0.0" }, "devDependencies": { "@module-federation/nextjs-mf": "workspace:*", diff --git a/apps/3002-checkout/next-env.d.ts b/apps/3002-checkout/next-env.d.ts index a4a7b3f5cfa..52e831b4342 100644 --- a/apps/3002-checkout/next-env.d.ts +++ b/apps/3002-checkout/next-env.d.ts @@ -2,4 +2,4 @@ /// // NOTE: This file should not be edited -// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information. +// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information. diff --git a/apps/3002-checkout/package.json b/apps/3002-checkout/package.json index 608c6ad022b..4167e49454d 100644 --- a/apps/3002-checkout/package.json +++ b/apps/3002-checkout/package.json @@ -6,9 +6,9 @@ "@ant-design/cssinjs": "^1.21.0", "antd": "5.19.1", "lodash": "4.17.21", - "next": "14.2.16", - "react": "18.3.1", - "react-dom": "18.3.1" + "next": "15.3.3", + "react": "19.0.0", + "react-dom": "19.0.0" }, "devDependencies": { "@module-federation/nextjs-mf": "workspace:*", diff --git a/apps/3002-checkout/project.json b/apps/3002-checkout/project.json index 3c3416d759d..6f31c61934e 100644 --- a/apps/3002-checkout/project.json +++ b/apps/3002-checkout/project.json @@ -64,23 +64,6 @@ "lintFilePatterns": ["apps/3002-checkout/**/*.{ts,tsx,js,jsx}"] } }, - "e2e": { - "executor": "@nx/cypress:cypress", - "options": { - "cypressConfig": "apps/3002-checkout/cypress.config.ts", - "testingType": "e2e", - "baseUrl": "http://localhost:3002" - }, - "defaultConfiguration": "development", - "configurations": { - "development": { - "devServerTarget": "3002-checkout:serve:development" - }, - "production": { - "devServerTarget": "3002-checkout:serve:production" - } - } - }, "test:e2e": { "executor": "nx:run-commands", "options": { @@ -119,6 +102,23 @@ ] } } + }, + "e2e": { + "executor": "@nx/cypress:cypress", + "options": { + "cypressConfig": "apps/3002-checkout/cypress.config.ts", + "testingType": "e2e", + "baseUrl": "http://localhost:3002" + }, + "defaultConfiguration": "development", + "configurations": { + "development": { + "devServerTarget": "3002-checkout:serve:development" + }, + "production": { + "devServerTarget": "3002-checkout:serve:production" + } + } } } } diff --git a/apps/3002-checkout/remotes.d.ts b/apps/3002-checkout/remotes.d.ts index 2a5ea8d5904..bcb09e137cc 100644 --- a/apps/3002-checkout/remotes.d.ts +++ b/apps/3002-checkout/remotes.d.ts @@ -3,3 +3,13 @@ declare module 'home/pages/home/exposed-pages'; declare module 'home/pages/home/test-broken-remotes'; declare module 'home/pages/home/test-remote-hook'; declare module 'home/pages/home/test-shared-nav'; +declare module 'home/menu'; +declare module 'shop/useCustomRemoteHook'; +declare module 'shop/WebpackSvg'; +declare module 'shop/WebpackPng'; +declare module 'shop/menu'; +declare module 'shop/pages/shop/index'; +declare module 'shop/pages/shop/exposed-pages'; +declare module 'shop/pages/shop/test-webpack-png'; +declare module 'shop/pages/shop/test-webpack-svg'; +declare module 'shop/pages/shop/products/[...slug]'; diff --git a/apps/modernjs/modern.config.ts b/apps/modernjs/modern.config.ts index 66aaf2d73a3..b40f76645ce 100644 --- a/apps/modernjs/modern.config.ts +++ b/apps/modernjs/modern.config.ts @@ -9,7 +9,7 @@ export default defineConfig({ router: true, }, security: { - checkSyntax: true, + checkSyntax: false, }, source: { // downgrade @module-federation related pkgs diff --git a/apps/module-federation-react-example/host/package.json b/apps/module-federation-react-example/host/package.json new file mode 100644 index 00000000000..2e6c095acb9 --- /dev/null +++ b/apps/module-federation-react-example/host/package.json @@ -0,0 +1,24 @@ +{ + "name": "module-federation-react-example-host", + "version": "1.0.0", + "description": "Host application for Module Federation demo", + "main": "index.js", + "scripts": { + "start": "webpack serve", + "build": "webpack --mode production" + }, + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.15.0" + }, + "devDependencies": { + "@babel/core": "^7.22.11", + "@babel/preset-react": "^7.22.5", + "babel-loader": "^9.1.3", + "html-webpack-plugin": "^5.5.3", + "webpack": "^5.88.2", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^4.15.1" + } +} diff --git a/apps/module-federation-react-example/host/project.json b/apps/module-federation-react-example/host/project.json new file mode 100644 index 00000000000..14029467a40 --- /dev/null +++ b/apps/module-federation-react-example/host/project.json @@ -0,0 +1,23 @@ +{ + "name": "module-federation-react-example-host", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "apps/module-federation-react-example/host", + "projectType": "application", + "targets": { + "build": { + "executor": "nx:run-commands", + "options": { + "cwd": "apps/module-federation-react-example/host", + "command": "webpack --mode production" + } + }, + "serve": { + "executor": "nx:run-commands", + "options": { + "cwd": "apps/module-federation-react-example/host", + "command": "webpack serve" + } + } + }, + "tags": [] +} diff --git a/apps/module-federation-react-example/host/public/index.html b/apps/module-federation-react-example/host/public/index.html new file mode 100644 index 00000000000..6763603a8e8 --- /dev/null +++ b/apps/module-federation-react-example/host/public/index.html @@ -0,0 +1,11 @@ + + + + + + Module Federation Example + + +
+ + diff --git a/apps/module-federation-react-example/host/share-usage.json b/apps/module-federation-react-example/host/share-usage.json new file mode 100644 index 00000000000..e606879dc67 --- /dev/null +++ b/apps/module-federation-react-example/host/share-usage.json @@ -0,0 +1,23 @@ +{ + "timestamp": "2025-08-26T23:39:55.557Z", + "outputPath": "/Users/bytedance/dev/core/apps/module-federation-react-example/host/dist", + "sharedModules": { + "react": { + "moduleName": "react", + "requiredVersion": "^18.2.0", + "usageCount": 2, + "usedFrom": [ + "/src/bootstrap.js", + "/Users/bytedance/dev/core/node_modules/.pnpm/react-dom@19.1.1_react@19.1.1/node_modules/react-dom/cjs/react-dom-client.production.js" + ] + }, + "react-dom": { + "moduleName": "react-dom", + "usageCount": 1, + "usedFrom": [ + "/Users/bytedance/dev/core/node_modules/.pnpm/react-dom@19.1.1_react@19.1.1/node_modules/react-dom/cjs/react-dom-client.production.js" + ] + } + }, + "unusedSharedModules": [] +} diff --git a/apps/module-federation-react-example/host/src/App.js b/apps/module-federation-react-example/host/src/App.js new file mode 100644 index 00000000000..feb9e93a560 --- /dev/null +++ b/apps/module-federation-react-example/host/src/App.js @@ -0,0 +1,48 @@ +import React from 'react'; + +const App = () => { + const [RemoteButton, setRemoteButton] = React.useState(null); + const [RemoteApp, setRemoteApp] = React.useState(null); + + React.useEffect(() => { + // Dynamically load the remote components + import('remote/Button') + .then((module) => { + setRemoteButton(() => module.default); + }) + .catch((err) => console.error('Error loading remote button:', err)); + + import('remote/App') + .then((module) => { + setRemoteApp(() => module.default); + }) + .catch((err) => console.error('Error loading remote app:', err)); + }, []); + + return ( +
+

Host Application

+

This is the host application that consumes shared components.

+ + {RemoteButton ? ( +
+

Remote Button Component:

+ +
+ ) : ( +

Loading remote button...

+ )} + + {RemoteApp ? ( +
+

Remote App Component:

+ +
+ ) : ( +

Loading remote app...

+ )} +
+ ); +}; + +export default App; diff --git a/apps/module-federation-react-example/host/src/bootstrap.js b/apps/module-federation-react-example/host/src/bootstrap.js new file mode 100644 index 00000000000..48342b59726 --- /dev/null +++ b/apps/module-federation-react-example/host/src/bootstrap.js @@ -0,0 +1,7 @@ +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import App from './App'; + +const container = document.getElementById('root'); +const root = createRoot(container); +root.render(); diff --git a/apps/module-federation-react-example/host/src/index.js b/apps/module-federation-react-example/host/src/index.js new file mode 100644 index 00000000000..b93c7a0268a --- /dev/null +++ b/apps/module-federation-react-example/host/src/index.js @@ -0,0 +1 @@ +import('./bootstrap'); diff --git a/apps/module-federation-react-example/host/webpack.config.js b/apps/module-federation-react-example/host/webpack.config.js new file mode 100644 index 00000000000..c5200bf956e --- /dev/null +++ b/apps/module-federation-react-example/host/webpack.config.js @@ -0,0 +1,56 @@ +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const { + ModuleFederationPlugin, + ShareUsagePlugin, +} = require('@module-federation/enhanced'); +const path = require('path'); + +module.exports = { + entry: './src/index', + mode: 'development', + devServer: { + static: { + directory: path.join(__dirname, 'dist'), + }, + port: 3001, + }, + output: { + publicPath: 'auto', + }, + module: { + rules: [ + { + test: /\.jsx?$/, + loader: 'babel-loader', + exclude: /node_modules/, + options: { + presets: ['@babel/preset-react'], + }, + }, + ], + }, + plugins: [ + new ModuleFederationPlugin({ + name: 'host', + filename: 'remoteEntry.js', + remotes: { + remote: 'remote@http://localhost:3002/remoteEntry.js', + }, + shared: { + react: { singleton: true }, + 'react-dom': { singleton: true }, + 'react-router-dom': { singleton: true }, + }, + }), + // Add ShareUsagePlugin to track usage of shared modules + // Uncomment once the build issues are fixed + new ShareUsagePlugin({ + outputFile: 'share-usage.json', + includeDetails: true, + includeUnused: true, + }), + new HtmlWebpackPlugin({ + template: './public/index.html', + }), + ], +}; diff --git a/apps/module-federation-react-example/project.json b/apps/module-federation-react-example/project.json new file mode 100644 index 00000000000..c194addd0f4 --- /dev/null +++ b/apps/module-federation-react-example/project.json @@ -0,0 +1,37 @@ +{ + "name": "module-federation-react-example", + "$schema": "../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "apps/module-federation-react-example", + "projectType": "application", + "targets": { + "build": { + "executor": "nx:run-commands", + "options": { + "commands": [ + { + "command": "nx run module-federation-react-example-remote:build" + }, + { + "command": "nx run module-federation-react-example-host:build" + } + ], + "parallel": false + } + }, + "serve": { + "executor": "nx:run-commands", + "options": { + "commands": [ + { + "command": "nx run module-federation-react-example-remote:serve" + }, + { + "command": "nx run module-federation-react-example-host:serve" + } + ], + "parallel": true + } + } + }, + "tags": [] +} diff --git a/apps/module-federation-react-example/remote/package.json b/apps/module-federation-react-example/remote/package.json new file mode 100644 index 00000000000..be949549164 --- /dev/null +++ b/apps/module-federation-react-example/remote/package.json @@ -0,0 +1,24 @@ +{ + "name": "module-federation-react-example-remote", + "version": "1.0.0", + "description": "Remote application for Module Federation demo", + "main": "index.js", + "scripts": { + "start": "webpack serve", + "build": "webpack --mode production" + }, + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.15.0" + }, + "devDependencies": { + "@babel/core": "^7.22.11", + "@babel/preset-react": "^7.22.5", + "babel-loader": "^9.1.3", + "html-webpack-plugin": "^5.5.3", + "webpack": "^5.88.2", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^4.15.1" + } +} diff --git a/apps/module-federation-react-example/remote/project.json b/apps/module-federation-react-example/remote/project.json new file mode 100644 index 00000000000..28b593a76b8 --- /dev/null +++ b/apps/module-federation-react-example/remote/project.json @@ -0,0 +1,23 @@ +{ + "name": "module-federation-react-example-remote", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "apps/module-federation-react-example/remote", + "projectType": "application", + "targets": { + "build": { + "executor": "nx:run-commands", + "options": { + "cwd": "apps/module-federation-react-example/remote", + "command": "webpack --mode production" + } + }, + "serve": { + "executor": "nx:run-commands", + "options": { + "cwd": "apps/module-federation-react-example/remote", + "command": "webpack serve" + } + } + }, + "tags": [] +} diff --git a/apps/module-federation-react-example/remote/public/index.html b/apps/module-federation-react-example/remote/public/index.html new file mode 100644 index 00000000000..b7fda7e6f15 --- /dev/null +++ b/apps/module-federation-react-example/remote/public/index.html @@ -0,0 +1,11 @@ + + + + + + Remote App + + +
+ + diff --git a/apps/module-federation-react-example/remote/src/App.js b/apps/module-federation-react-example/remote/src/App.js new file mode 100644 index 00000000000..91323bb232e --- /dev/null +++ b/apps/module-federation-react-example/remote/src/App.js @@ -0,0 +1,12 @@ +import React from 'react'; + +const App = () => { + return ( +
+

Remote App

+

This is the remote application being loaded in the host.

+
+ ); +}; + +export default App; diff --git a/apps/module-federation-react-example/remote/src/Button.js b/apps/module-federation-react-example/remote/src/Button.js new file mode 100644 index 00000000000..d5ec09cabb5 --- /dev/null +++ b/apps/module-federation-react-example/remote/src/Button.js @@ -0,0 +1,23 @@ +import React from 'react'; + +const Button = () => { + const [count, setCount] = React.useState(0); + + return ( + + ); +}; + +export default Button; diff --git a/apps/module-federation-react-example/remote/src/bootstrap.js b/apps/module-federation-react-example/remote/src/bootstrap.js new file mode 100644 index 00000000000..48342b59726 --- /dev/null +++ b/apps/module-federation-react-example/remote/src/bootstrap.js @@ -0,0 +1,7 @@ +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import App from './App'; + +const container = document.getElementById('root'); +const root = createRoot(container); +root.render(); diff --git a/apps/module-federation-react-example/remote/src/index.js b/apps/module-federation-react-example/remote/src/index.js new file mode 100644 index 00000000000..b93c7a0268a --- /dev/null +++ b/apps/module-federation-react-example/remote/src/index.js @@ -0,0 +1 @@ +import('./bootstrap'); diff --git a/apps/module-federation-react-example/remote/webpack.config.js b/apps/module-federation-react-example/remote/webpack.config.js new file mode 100644 index 00000000000..115b2baf1b8 --- /dev/null +++ b/apps/module-federation-react-example/remote/webpack.config.js @@ -0,0 +1,47 @@ +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const { ModuleFederationPlugin } = require('@module-federation/enhanced'); +const path = require('path'); + +module.exports = { + entry: './src/index', + mode: 'development', + devServer: { + static: { + directory: path.join(__dirname, 'dist'), + }, + port: 3002, + }, + output: { + publicPath: 'auto', + }, + module: { + rules: [ + { + test: /\.jsx?$/, + loader: 'babel-loader', + exclude: /node_modules/, + options: { + presets: ['@babel/preset-react'], + }, + }, + ], + }, + plugins: [ + new ModuleFederationPlugin({ + name: 'remote', + filename: 'remoteEntry.js', + exposes: { + './Button': './src/Button', + './App': './src/App', + }, + shared: { + react: { singleton: true }, + 'react-dom': { singleton: true }, + 'react-router-dom': { singleton: true }, + }, + }), + new HtmlWebpackPlugin({ + template: './public/index.html', + }), + ], +}; diff --git a/apps/next-app-router/next-app-router-4000/app/context/context-click-counter.tsx b/apps/next-app-router/next-app-router-4000/app/context/context-click-counter.tsx index a59be8aeb2f..cd15bc1bd10 100644 --- a/apps/next-app-router/next-app-router-4000/app/context/context-click-counter.tsx +++ b/apps/next-app-router/next-app-router-4000/app/context/context-click-counter.tsx @@ -3,8 +3,8 @@ import { useCounter } from './counter-context'; import React from 'react'; import { Boundary } from '#/ui/boundary'; -import dynamic from 'next/dynamic'; -const Button = dynamic(() => import('remote_4001/Button'), { ssr: true }); +// import dynamic from 'next/dynamic'; +// const Button = dynamic(() => import('remote_4001/Button'), { ssr: true }); const ContextClickCounter = () => { const [count, setCount] = useCounter(); @@ -16,7 +16,10 @@ const ContextClickCounter = () => { size="small" animateRerendering={false} > - + {/* */} + diff --git a/apps/next-app-router/next-app-router-4000/app/error-handling/[categorySlug]/error.tsx b/apps/next-app-router/next-app-router-4000/app/error-handling/[categorySlug]/error.tsx index a3b35cc8051..c327c2b7ac3 100644 --- a/apps/next-app-router/next-app-router-4000/app/error-handling/[categorySlug]/error.tsx +++ b/apps/next-app-router/next-app-router-4000/app/error-handling/[categorySlug]/error.tsx @@ -1,7 +1,7 @@ 'use client'; import { Boundary } from '#/ui/boundary'; -import Button from 'remote_4001/Button'; +// import Button from 'remote_4001/Button'; import React from 'react'; export default function Error({ error, reset }: any) { @@ -15,6 +15,12 @@ export default function Error({ error, reset }: any) {

Error

{error?.message}

+
diff --git a/apps/next-app-router/next-app-router-4000/app/error-handling/error.tsx b/apps/next-app-router/next-app-router-4000/app/error-handling/error.tsx index 70a7ef16ecb..331879cf9bd 100644 --- a/apps/next-app-router/next-app-router-4000/app/error-handling/error.tsx +++ b/apps/next-app-router/next-app-router-4000/app/error-handling/error.tsx @@ -1,7 +1,7 @@ 'use client'; import { Boundary } from '#/ui/boundary'; -import Button from 'remote_4001/Button'; +// import Button from 'remote_4001/Button'; import React from 'react'; export default function Error({ error, reset }: any) { @@ -15,7 +15,13 @@ export default function Error({ error, reset }: any) {

Error

{error?.message}

- + + {/* */}
diff --git a/apps/next-app-router/next-app-router-4000/app/hooks/page.tsx b/apps/next-app-router/next-app-router-4000/app/hooks/page.tsx index c216fb991d6..62370239c48 100644 --- a/apps/next-app-router/next-app-router-4000/app/hooks/page.tsx +++ b/apps/next-app-router/next-app-router-4000/app/hooks/page.tsx @@ -1,32 +1,67 @@ +'use client'; +import Link from 'next/link'; +import Image from 'next/image'; +import Head from 'next/head'; +import Script from 'next/script'; +import { + useRouter, + usePathname, + useSearchParams, + useParams, + useSelectedLayoutSegments, + useSelectedLayoutSegment, +} from 'next/navigation'; import { ExternalLink } from '#/ui/external-link'; export default function Page() { - return ( -
-
-

Client Component Hooks

- -
    -
  • - Next.js provides a number of hooks for accessing routing information - from client components. -
  • -
  • - Try navigating each page and observing the output of each hook - called from the current routes layout.js and{' '} - page.js files. -
  • -
+ const router = useRouter(); + const pathname = usePathname(); + const searchParams = useSearchParams(); + const params = useParams(); + const segments = useSelectedLayoutSegments(); + const segment = useSelectedLayoutSegment(); -
- - Docs - - - Code - + return ( + <> + + Client Component Hooks Demo + +