Skip to content

Commit

Permalink
feat(nextjs-mf): update module share for rsc
Browse files Browse the repository at this point in the history
  • Loading branch information
ScriptedAlchemy committed Jan 21, 2025
1 parent 10f2b73 commit 432550a
Show file tree
Hide file tree
Showing 21 changed files with 246 additions and 90 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +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 });

const ContextClickCounter = () => {
const [count, setCount] = useCounter();
Expand All @@ -14,6 +16,7 @@ const ContextClickCounter = () => {
size="small"
animateRerendering={false}
>
<Button>testing</Button>
<button
onClick={() => setCount(count + 1)}
className="rounded-lg bg-gray-700 px-3 py-1 text-sm font-medium tabular-nums text-gray-100 hover:bg-gray-500 hover:text-white"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';

import { Boundary } from '#/ui/boundary';
import Button from '#/ui/button';
import Button from 'remote_4001/Button';
import React from 'react';

export default function Error({ error, reset }: any) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';

import { Boundary } from '#/ui/boundary';
import Button from '#/ui/button';
import Button from 'remote_4001/Button';
import React from 'react';

export default function Error({ error, reset }: any) {
Expand Down
2 changes: 1 addition & 1 deletion apps/next-app-router-4000/app/error-handling/error.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';

import { Boundary } from '#/ui/boundary';
import Button from '#/ui/button';
import Button from 'remote_4001/Button';
import React from 'react';

export default function Error({ error, reset }: any) {
Expand Down
4 changes: 2 additions & 2 deletions apps/next-app-router-4000/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import '#/styles/globals.css';
import { AddressBar } from '#/ui/address-bar';
import Byline from '#/ui/byline';
import { GlobalNav } from '#/ui/global-nav';
// import { GlobalNav } from 'remote_4001/GlobalNav(rsc)';
import { Metadata } from 'next';

export const metadata: Metadata = {
Expand Down Expand Up @@ -31,7 +31,7 @@ export default function RootLayout({
return (
<html lang="en" className="[color-scheme:dark]">
<body className="overflow-y-scroll bg-gray-1100 bg-[url('/grid.svg')] pb-36">
<GlobalNav />
{/*<GlobalNav />*/}

<div className="lg:pl-72">
<div className="mx-auto max-w-4xl space-y-8 px-2 pt-20 lg:px-8 lg:py-8">
Expand Down
2 changes: 1 addition & 1 deletion apps/next-app-router-4000/ui/buggy-button.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';

import Button from '#/ui/button';
import Button from 'remote_4001/Button';
import React from 'react';

export default function BuggyButton() {
Expand Down
47 changes: 30 additions & 17 deletions apps/next-app-router-4001/app/demo/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,45 +6,58 @@ import dynamic from 'next/dynamic';
// Dynamically import remote components
const Button = dynamic(() => import('remote_4001/Button'), { ssr: true });
const Header = dynamic(() => import('remote_4001/Header'), { ssr: true });
const ProductCard = dynamic(() => import('remote_4001/ProductCard'), { ssr: true });
const ProductCard = dynamic(() => import('remote_4001/ProductCard'), {
ssr: true,
});
const TabGroup = dynamic(() => import('remote_4001/TabGroup'), { ssr: true });
const TabNavItem = dynamic(() => import('remote_4001/TabNavItem'), { ssr: true });
const TabNavItem = dynamic(() => import('remote_4001/TabNavItem'), {
ssr: true,
});
const CountUp = dynamic(() => import('remote_4001/CountUp'), { ssr: true });
const RenderingInfo = dynamic(() => import('remote_4001/RenderingInfo'), { ssr: true });
const RenderingInfo = dynamic(() => import('remote_4001/RenderingInfo'), {
ssr: true,
});

export default function DemoPage() {
return (
<div className="p-4">
<Header />

<main className="max-w-4xl mx-auto mt-8">
<h1 className="text-2xl font-bold mb-6">Remote Components Demo</h1>
<main className="mx-auto mt-8 max-w-4xl">
<h1 className="mb-6 text-2xl font-bold">Remote Components Demo</h1>

<section className="mb-8">
<h2 className="text-xl font-semibold mb-4">Basic UI Components</h2>
<h2 className="mb-4 text-xl font-semibold">Basic UI Components</h2>
<div className="space-x-4">
<Button>Primary Button</Button>
<Button>Secondary Button</Button>
</div>
</section>

<section className="mb-8">
<h2 className="text-xl font-semibold mb-4">Navigation Components</h2>
<h2 className="mb-4 text-xl font-semibold">Navigation Components</h2>
<TabGroup>
<TabNavItem href="/demo/tab1" isActive={true}>Tab 1</TabNavItem>
<TabNavItem href="/demo/tab2" isActive={false}>Tab 2</TabNavItem>
<TabNavItem href="/demo/tab3" isActive={false}>Tab 3</TabNavItem>
<TabNavItem href="/demo/tab1" isActive={true}>
Tab 1
</TabNavItem>
<TabNavItem href="/demo/tab2" isActive={false}>
Tab 2
</TabNavItem>
<TabNavItem href="/demo/tab3" isActive={false}>
Tab 3
</TabNavItem>
</TabGroup>
</section>

<section className="mb-8">
<h2 className="text-xl font-semibold mb-4">Product Components</h2>
<h2 className="mb-4 text-xl font-semibold">Product Components</h2>
<div className="grid grid-cols-2 gap-4">
<ProductCard
product={{
name: 'Demo Product',
price: 99.99,
description: 'This is a demo product to showcase the ProductCard component',
description:
'This is a demo product to showcase the ProductCard component',
image: 'https://via.placeholder.com/300',
rating: 4.5,
}}
Expand All @@ -62,14 +75,14 @@ export default function DemoPage() {
</section>

<section className="mb-8">
<h2 className="text-xl font-semibold mb-4">Interactive Components</h2>
<h2 className="mb-4 text-xl font-semibold">Interactive Components</h2>
<div className="space-y-4">
<div className="p-4 border rounded">
<h3 className="font-medium mb-2">Count Up Animation</h3>
<div className="rounded border p-4">
<h3 className="mb-2 font-medium">Count Up Animation</h3>
<CountUp start={0} end={1000} />
</div>
<div className="p-4 border rounded">
<h3 className="font-medium mb-2">Rendering Information</h3>
<div className="rounded border p-4">
<h3 className="mb-2 font-medium">Rendering Information</h3>
<RenderingInfo />
</div>
</div>
Expand Down
8 changes: 5 additions & 3 deletions apps/next-app-router-4001/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ const nextConfig = {
exposes: {
// Core UI Components
'./Button': './ui/button',
// './Header': './ui/header',
// './Footer': './ui/footer',
// './GlobalNav': './ui/global-nav',
// './Header': isServer ? './ui/header?rsc' : './ui/header?shared',
'./Footer': './ui/footer',
// './GlobalNav(rsc)': isServer ? './ui/global-nav?rsc' : './ui/global-nav',
// './GlobalNav(ssr)': isServer ? './ui/global-nav?ssr' : './ui/global-nav',
'./GlobalNav': './ui/global-nav',
//
// // Product Related Components
// './ProductCard': './ui/product-card',
Expand Down
5 changes: 3 additions & 2 deletions packages/enhanced/src/lib/sharing/ConsumeSharedPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,8 +334,9 @@ class ConsumeSharedPlugin {
return createConsumeSharedModule(context, request, match);
}
for (const [prefix, options] of prefixedConsumes) {
if (request.startsWith(prefix)) {
const remainder = request.slice(prefix.length);
const lookup = options.request || prefix;
if (request.startsWith(lookup)) {
const remainder = request.slice(lookup.length);
return createConsumeSharedModule(context, request, {
...options,
import: options.import
Expand Down
6 changes: 4 additions & 2 deletions packages/enhanced/src/lib/sharing/ProvideSharedPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,10 @@ class ProvideSharedPlugin {
}
}
for (const [prefix, config] of prefixMatchProvides) {
if (request.startsWith(prefix) && resource) {
const remainder = request.slice(prefix.length);
const lookup = config.request || prefix;
if (request.startsWith(lookup) && resource) {
const remainder = request.slice(lookup.length);
debugger;
provideSharedModule(
resource,
{
Expand Down
12 changes: 12 additions & 0 deletions packages/enhanced/test/configCases/layers/9-layers-full/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React, { layeredComponentsReact } from 'react';
import other from 'react/other';
import ComponentA from 'containerA/ComponentA';
import RemoteApp from 'containerA/App';
import LocalComponentA from './ComponentA';
console.log(other);
export default function App() {
return `App (no layer) rendered with React version: [${React()}] with non-layered React value: [${layeredComponentsReact()}]
Local Component: ${LocalComponentA()}
Remote Component from container7: ${ComponentA()}
Remote App from container7: ${RemoteApp()}`;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React, { layeredComponentsReact } from 'react';

export default function ComponentA() {
return `LocalComponentA (in react-layer) rendered with React version: [${React()}], layered React value: [${layeredComponentsReact()}]`;
}
12 changes: 12 additions & 0 deletions packages/enhanced/test/configCases/layers/9-layers-full/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
it('should load App with React and both types of remote components', () => {
return import('containerA/noop').then((m) => {
return import('./App').then(({ default: App }) => {
const rendered = App();
expect(rendered)
.toBe(`App (no layer) rendered with React version: [This is react 0.1.2] with non-layered React value: [No Layer]
Local Component: LocalComponentA (in react-layer) rendered with React version: [This is react 0.1.2], layered React value: [react-layer]
Remote Component from container7: ComponentA (in react-layer) rendered with React version: [This is react 0.1.2] with layered React value: [react-layer]
Remote App from container7: App (no layer) rendered with React version: [This is react 0.1.2] with non-layered React value: [No Layer] and imported: ComponentA (in react-layer) rendered with React version: [This is react 0.1.2] with layered React value: [react-layer]`);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import LocalComponentA from './ComponentA';

export default LocalComponentA;

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"private": true,
"engines": {
"node": ">=10.13.0"
},
"scripts": {
"build": "webpack --config=webpack.config.js"
},
"dependencies": {
"react": "*"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
findBundle: function (i, options) {
return './main.js';
return i === 0 ? './main.js' : './module/main.mjs';
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
const { ModuleFederationPlugin } = require('../../../../dist/src');

const common = {
name: 'container_8',
filename: 'container.js',
remotes: {
containerA: {
external: '../7-layers-full/container.js',
},
},
shared: {
react: {
singleton: true,
requiredVersion: false,
},
randomvalue: {
request: 'react/',
shareKey: 'react',
singleton: true,
requiredVersion: false,
layer: 'react-layer',
issuerLayer: 'react-layer',
},
},
};

const commonConfig = {
entry: './index.js',
mode: 'development',
devtool: false,
experiments: {
layers: true,
},
module: {
rules: [
{
layer: 'react-layer',
test: /ComponentA\.js$/,
},
{
test: /react\.js$/,
issuerLayer: 'react-layer',
layer: 'react-layer',
},
],
},
};

module.exports = [
{
...commonConfig,
output: {
filename: '[name].js',
uniqueName: '8-layers-full',
},
plugins: [
new ModuleFederationPlugin({
...common,
library: { type: 'commonjs-module' },
}),
],
},
{
...commonConfig,
experiments: {
...commonConfig.experiments,
outputModule: true,
},
output: {
filename: 'module/[name].mjs',
uniqueName: '8-layers-full-mjs',
},
plugins: [
new ModuleFederationPlugin({
...common,
library: { type: 'module' },
filename: 'module/container.mjs',
remotes: {
containerA: {
external: '../../7-layers-full/module/container.mjs',
},
},
}),
],
target: 'node14',
},
];
Loading

0 comments on commit 432550a

Please sign in to comment.