up
This commit is contained in:
@@ -14,6 +14,7 @@
|
|||||||
"react-dom": "^19.2.5"
|
"react-dom": "^19.2.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/bun": "^1.3.12",
|
||||||
"@types/node": "^25.6.0",
|
"@types/node": "^25.6.0",
|
||||||
"@types/react": "^19.2.14",
|
"@types/react": "^19.2.14",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
|
|||||||
17
pnpm-lock.yaml
generated
17
pnpm-lock.yaml
generated
@@ -21,6 +21,9 @@ importers:
|
|||||||
specifier: ^19.2.5
|
specifier: ^19.2.5
|
||||||
version: 19.2.5(react@19.2.5)
|
version: 19.2.5(react@19.2.5)
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
'@types/bun':
|
||||||
|
specifier: ^1.3.12
|
||||||
|
version: 1.3.12
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^25.6.0
|
specifier: ^25.6.0
|
||||||
version: 25.6.0
|
version: 25.6.0
|
||||||
@@ -364,6 +367,9 @@ packages:
|
|||||||
react: '>=16.9.0'
|
react: '>=16.9.0'
|
||||||
react-dom: '>=16.9.0'
|
react-dom: '>=16.9.0'
|
||||||
|
|
||||||
|
'@types/bun@1.3.12':
|
||||||
|
resolution: {integrity: sha512-DBv81elK+/VSwXHDlnH3Qduw+KxkTIWi7TXkAeh24zpi5l0B2kUg9Ga3tb4nJaPcOFswflgi/yAvMVBPrxMB+A==}
|
||||||
|
|
||||||
'@types/node@25.6.0':
|
'@types/node@25.6.0':
|
||||||
resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==}
|
resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==}
|
||||||
|
|
||||||
@@ -381,6 +387,9 @@ packages:
|
|||||||
react: '>=18.0.0'
|
react: '>=18.0.0'
|
||||||
react-dom: '>=18.0.0'
|
react-dom: '>=18.0.0'
|
||||||
|
|
||||||
|
bun-types@1.3.12:
|
||||||
|
resolution: {integrity: sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA==}
|
||||||
|
|
||||||
clsx@2.1.1:
|
clsx@2.1.1:
|
||||||
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
|
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -834,6 +843,10 @@ snapshots:
|
|||||||
react: 19.2.5
|
react: 19.2.5
|
||||||
react-dom: 19.2.5(react@19.2.5)
|
react-dom: 19.2.5(react@19.2.5)
|
||||||
|
|
||||||
|
'@types/bun@1.3.12':
|
||||||
|
dependencies:
|
||||||
|
bun-types: 1.3.12
|
||||||
|
|
||||||
'@types/node@25.6.0':
|
'@types/node@25.6.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 7.19.2
|
undici-types: 7.19.2
|
||||||
@@ -903,6 +916,10 @@ snapshots:
|
|||||||
- luxon
|
- luxon
|
||||||
- moment
|
- moment
|
||||||
|
|
||||||
|
bun-types@1.3.12:
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 25.6.0
|
||||||
|
|
||||||
clsx@2.1.1: {}
|
clsx@2.1.1: {}
|
||||||
|
|
||||||
compute-scroll-into-view@3.1.1: {}
|
compute-scroll-into-view@3.1.1: {}
|
||||||
|
|||||||
@@ -1,14 +1,6 @@
|
|||||||
// entry.tsx - 客户端入口
|
import { hydrateRoot } from 'react-dom/client';
|
||||||
import { hydrateRoot, createRoot } from 'react-dom/client';
|
|
||||||
import A from './pages/a/index';
|
import A from './pages/a/index';
|
||||||
|
|
||||||
const root = document.getElementById('root');
|
// React 19: renderToPipeableStream embeds RSC payload in HTML
|
||||||
createRoot(root!).render(<A />);
|
// hydrateRoot will find and use that payload automatically
|
||||||
|
hydrateRoot(document.getElementById('root')!, <A />);
|
||||||
// hydrateRoot(document.getElementById('root')!, <A />);
|
|
||||||
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
console.log('Hydrating with new content...');
|
|
||||||
hydrateRoot(root!, <A />);
|
|
||||||
}, 30000)
|
|
||||||
@@ -1,15 +1,17 @@
|
|||||||
import { renderToString } from 'react-dom/server';
|
import { renderToReadableStream } from 'react-dom/server';
|
||||||
import A from './pages/a/index';
|
import A from './pages/a/index';
|
||||||
import http from 'http';
|
|
||||||
|
|
||||||
const html = renderToString(<A />, {
|
Bun.serve({
|
||||||
identifierPrefix: 'test-',
|
port: 3000,
|
||||||
});
|
async fetch(req) {
|
||||||
console.log(html);
|
const stream = await renderToReadableStream(<A />, {
|
||||||
|
bootstrapScripts: [],
|
||||||
|
});
|
||||||
|
|
||||||
http.createServer((req, res) => {
|
return new Response(stream, {
|
||||||
res.writeHead(200, { 'Content-Type': 'text/html' });
|
headers: { 'Content-Type': 'text/html' },
|
||||||
res.end(html);
|
});
|
||||||
}).listen(3000, () => {
|
},
|
||||||
console.log('Server is running on http://localhost:3000');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log('Server running on http://localhost:3000');
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
"use client";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
|
|
||||||
export default function List() {
|
export default function List() {
|
||||||
|
|||||||
8
src/pages/a/server-index.tsx
Normal file
8
src/pages/a/server-index.tsx
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// Server component - no 'use client' directive
|
||||||
|
export default function ServerList() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Server List</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
18
src/pages/a/server/index.tsx
Normal file
18
src/pages/a/server/index.tsx
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
'use server';
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
const getVersion = async () => {
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
return '1.0.0';
|
||||||
|
}
|
||||||
|
export default async function List() {
|
||||||
|
const v = await getVersion();
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>List - Version {v}</h1>
|
||||||
|
<div style={{
|
||||||
|
width: 200
|
||||||
|
}}>Primary Button</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
31
src/server-node.tsx
Normal file
31
src/server-node.tsx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
"use server";
|
||||||
|
import { renderToPipeableStream, renderToString } from 'react-dom/server';
|
||||||
|
// import A from './pages/a/index.tsx';
|
||||||
|
import { AEntry } from './browser-entry.tsx';
|
||||||
|
import AServer from './pages/a/server/index.tsx';
|
||||||
|
import http from 'http';
|
||||||
|
|
||||||
|
const PORT = 3000;
|
||||||
|
|
||||||
|
http.createServer((req, res) => {
|
||||||
|
if (req.url === '/ssr') {
|
||||||
|
const { pipe } = renderToPipeableStream(<AServer />, {
|
||||||
|
bootstrapScripts: [],
|
||||||
|
onShellReady() {
|
||||||
|
res.writeHead(200, { 'Content-Type': 'text/html' });
|
||||||
|
pipe(res);
|
||||||
|
},
|
||||||
|
onShellError(err) {
|
||||||
|
console.error('Shell error:', err);
|
||||||
|
res.writeHead(500);
|
||||||
|
res.end('Server Error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const str = renderToString(<A />);
|
||||||
|
res.writeHead(200, { 'Content-Type': 'text/html' });
|
||||||
|
res.end(str);
|
||||||
|
}
|
||||||
|
}).listen(PORT, () => {
|
||||||
|
console.log(`Server running on http://localhost:${PORT}`);
|
||||||
|
});
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
"DOM"
|
"DOM"
|
||||||
],
|
],
|
||||||
"types": [
|
"types": [
|
||||||
|
"bun",
|
||||||
"node",
|
"node",
|
||||||
],
|
],
|
||||||
"jsx": "react-jsx"
|
"jsx": "react-jsx"
|
||||||
|
|||||||
Reference in New Issue
Block a user