diff --git a/package.json b/package.json index 8b02a02..8e2b444 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "react-dom": "^19.2.5" }, "devDependencies": { + "@types/bun": "^1.3.12", "@types/node": "^25.6.0", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8cda8b7..02c96bc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,6 +21,9 @@ importers: specifier: ^19.2.5 version: 19.2.5(react@19.2.5) devDependencies: + '@types/bun': + specifier: ^1.3.12 + version: 1.3.12 '@types/node': specifier: ^25.6.0 version: 25.6.0 @@ -364,6 +367,9 @@ packages: react: '>=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': resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==} @@ -381,6 +387,9 @@ packages: react: '>=18.0.0' react-dom: '>=18.0.0' + bun-types@1.3.12: + resolution: {integrity: sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA==} + clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -834,6 +843,10 @@ snapshots: 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': dependencies: undici-types: 7.19.2 @@ -903,6 +916,10 @@ snapshots: - luxon - moment + bun-types@1.3.12: + dependencies: + '@types/node': 25.6.0 + clsx@2.1.1: {} compute-scroll-into-view@3.1.1: {} diff --git a/src/browser-entry.tsx b/src/browser-entry.tsx index 1f5c874..984a386 100644 --- a/src/browser-entry.tsx +++ b/src/browser-entry.tsx @@ -1,14 +1,6 @@ -// entry.tsx - 客户端入口 -import { hydrateRoot, createRoot } from 'react-dom/client'; +import { hydrateRoot } from 'react-dom/client'; import A from './pages/a/index'; -const root = document.getElementById('root'); -createRoot(root!).render(); - -// hydrateRoot(document.getElementById('root')!, ); - - -setTimeout(() => { - console.log('Hydrating with new content...'); - hydrateRoot(root!, ); -}, 30000) \ No newline at end of file +// React 19: renderToPipeableStream embeds RSC payload in HTML +// hydrateRoot will find and use that payload automatically +hydrateRoot(document.getElementById('root')!, ); \ No newline at end of file diff --git a/src/entry.tsx b/src/entry.tsx index 8e8fda7..e894884 100644 --- a/src/entry.tsx +++ b/src/entry.tsx @@ -1,15 +1,17 @@ -import { renderToString } from 'react-dom/server'; +import { renderToReadableStream } from 'react-dom/server'; import A from './pages/a/index'; -import http from 'http'; -const html = renderToString(, { - identifierPrefix: 'test-', +Bun.serve({ + port: 3000, + async fetch(req) { + const stream = await renderToReadableStream(, { + bootstrapScripts: [], + }); + + return new Response(stream, { + headers: { 'Content-Type': 'text/html' }, + }); + }, }); -console.log(html); -http.createServer((req, res) => { - res.writeHead(200, { 'Content-Type': 'text/html' }); - res.end(html); -}).listen(3000, () => { - console.log('Server is running on http://localhost:3000'); -}); \ No newline at end of file +console.log('Server running on http://localhost:3000'); \ No newline at end of file diff --git a/src/pages/a/index.tsx b/src/pages/a/index.tsx index 699c4e6..e24e787 100644 --- a/src/pages/a/index.tsx +++ b/src/pages/a/index.tsx @@ -1,3 +1,4 @@ +"use client"; import { useEffect } from "react"; export default function List() { diff --git a/src/pages/a/server-index.tsx b/src/pages/a/server-index.tsx new file mode 100644 index 0000000..0f67558 --- /dev/null +++ b/src/pages/a/server-index.tsx @@ -0,0 +1,8 @@ +// Server component - no 'use client' directive +export default function ServerList() { + return ( +