Compare commits
	
		
			4 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 65622e08e5 | ||
|  | a0dbe4f7fc | ||
|  | dbaee0c81a | ||
|  | d6aa2782bf | 
							
								
								
									
										11
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -68,7 +68,8 @@ $RECYCLE.BIN/ | ||||
| .LSOverride | ||||
|  | ||||
| # Icon must end with two \r | ||||
| Icon | ||||
| Icon | ||||
|  | ||||
|  | ||||
| # Thumbnails | ||||
| ._* | ||||
| @@ -200,7 +201,8 @@ fabric.properties | ||||
| .LSOverride | ||||
|  | ||||
| # Icon must end with two \r | ||||
| # Icon must end with two \r | ||||
| Icon | ||||
|  | ||||
|  | ||||
| # Thumbnails | ||||
| ._* | ||||
| @@ -1022,8 +1024,11 @@ _site/ | ||||
| /vendor | ||||
|  | ||||
| # Specific ignore for GitHub Pages | ||||
|  | ||||
| # GitHub Pages will always use its own deployed version of pages-gem | ||||
| # This means GitHub Pages will NOT use your Gemfile.lock and therefore it is | ||||
| # counterproductive to check this file into the repository. | ||||
| # Details at https://github.com/github/pages-gem/issues/768 | ||||
| Gemfile.lock | ||||
|  | ||||
| # Fix extra-ignoring for kernel module file pattern on CSS Module files. | ||||
| !*.module.css | ||||
|   | ||||
							
								
								
									
										24
									
								
								index.html
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								index.html
									
									
									
									
									
								
							| @@ -1,13 +1,15 @@ | ||||
| <!doctype html> | ||||
| <html lang="en"> | ||||
|   <head> | ||||
|     <meta charset="UTF-8" /> | ||||
|     <link rel="icon" type="image/svg+xml" href="/vite.svg" /> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||||
|     <title>Vite + React + TS</title> | ||||
|   </head> | ||||
|   <body> | ||||
|     <div id="root"></div> | ||||
|     <script type="module" src="/src/main.tsx"></script> | ||||
|   </body> | ||||
| <html lang="zh-CN"> | ||||
|  | ||||
| <head> | ||||
|   <meta charset="UTF-8" /> | ||||
|   <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||||
|   <title>Vite + React + TS</title> | ||||
| </head> | ||||
|  | ||||
| <body> | ||||
|   <div id="root"><!--ssr-outlet--></div> | ||||
|   <script type="module" src="/src/main.tsx"></script> | ||||
| </body> | ||||
|  | ||||
| </html> | ||||
|   | ||||
| @@ -11,6 +11,7 @@ | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@elysiajs/static": "^1.1.1", | ||||
|     "clsx": "^2.1.1", | ||||
|     "elysia": "^1.1.26", | ||||
|     "elysia-connect-middleware": "^0.0.3", | ||||
|     "react": "^19.0.0", | ||||
|   | ||||
							
								
								
									
										26
									
								
								server.ts
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								server.ts
									
									
									
									
									
								
							| @@ -5,22 +5,40 @@ import { renderToReadableStream } from 'react-dom/server'; | ||||
| import { createServer } from 'vite'; | ||||
| import { App } from './src/App'; | ||||
|  | ||||
| const isProduction = process.env.NODE_ENV === 'production'; | ||||
| const base = process.env.BASE || '/'; | ||||
|  | ||||
| let template = ''; | ||||
| if (!isProduction) { | ||||
|   const templateFile = Bun.file('index.html'); | ||||
|   template = await templateFile.text(); | ||||
| } | ||||
|  | ||||
| const app = new Elysia(); | ||||
| const vite = await createServer({ | ||||
|   server: { middlewareMode: true }, | ||||
|   appType: 'custom', | ||||
| }); | ||||
| app.use(connect(vite.middlewares)); | ||||
| app.get('/', async () => { | ||||
| app.get('/', async ({ request }) => { | ||||
|   const url = request.url.replace(base, ''); | ||||
|   const app = createElement(App); | ||||
|   const stream = await renderToReadableStream(app, { bootstrapScripts: ['/src/main.tsx'] }); | ||||
|   return new Response(stream, { | ||||
|   const rootComponent = await renderToReadableStream(app); | ||||
|   const rootComponentString = await Bun.readableStreamToText(rootComponent); | ||||
|  | ||||
|   if (!isProduction) { | ||||
|     template = await vite.transformIndexHtml(url, template); | ||||
|   } | ||||
|  | ||||
|   const html = template.replace(`<!--ssr-outlet-->`, () => rootComponentString); | ||||
|  | ||||
|   return new Response(html, { | ||||
|     headers: { | ||||
|       'Content-Type': 'text/html', | ||||
|     }, | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| app.listen(3000); | ||||
| app.listen(8000); | ||||
|  | ||||
| console.log(`Server running at http://${app.server?.hostname}:${app.server?.port}`); | ||||
|   | ||||
							
								
								
									
										20
									
								
								src/App.tsx
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								src/App.tsx
									
									
									
									
									
								
							| @@ -6,21 +6,11 @@ import { MainLayout } from './pages/MainLayout'; | ||||
| export const App = () => { | ||||
|   return ( | ||||
|     <StrictMode> | ||||
|       <html lang="zh-CN"> | ||||
|         <head> | ||||
|           <meta charSet="utf-8" /> | ||||
|           <meta name="viewport" content="width=device-width, initial-scale=1" /> | ||||
|           <title>React SSR App</title> | ||||
|           <link rel="stylesheet" href="/src/index.css" /> | ||||
|         </head> | ||||
|         <body> | ||||
|           <StaticRouter> | ||||
|             <Routes> | ||||
|               <Route path="/" element={<MainLayout />} /> | ||||
|             </Routes> | ||||
|           </StaticRouter> | ||||
|         </body> | ||||
|       </html> | ||||
|       <StaticRouter> | ||||
|         <Routes> | ||||
|           <Route path="/" element={<MainLayout />} /> | ||||
|         </Routes> | ||||
|       </StaticRouter> | ||||
|     </StrictMode> | ||||
|   ); | ||||
| }; | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| // Boot styles | ||||
| // import './index.css'; | ||||
| import './index.css'; | ||||
|  | ||||
| // Boot scripts | ||||
| import { hydrateRoot } from 'react-dom/client'; | ||||
| import { App } from './App'; | ||||
|  | ||||
| hydrateRoot(document, <App />); | ||||
| hydrateRoot(document.getElementById('root'), <App />); | ||||
|   | ||||
							
								
								
									
										23
									
								
								src/pages/MainLayout.module.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/pages/MainLayout.module.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| @layer page { | ||||
|   .main_layout { | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     overflow: hidden; | ||||
|     display: flex; | ||||
|     flex-direction: row; | ||||
|     justify-content: flex-start; | ||||
|     align-items: stretch; | ||||
|   } | ||||
|   .navigation_column { | ||||
|     min-width: 230px; | ||||
|     flex: 0 0 auto; | ||||
|     display: flex; | ||||
|     flex-direction: column; | ||||
|     justify-content: flex-start; | ||||
|     align-items: stretch; | ||||
|     gap: 4px; | ||||
|   } | ||||
|   .content { | ||||
|     flex: 1 0 auto; | ||||
|   } | ||||
| } | ||||
| @@ -1,3 +1,5 @@ | ||||
| 'use client'; | ||||
|  | ||||
| import { Outlet } from 'react-router-dom'; | ||||
| import styles from './MainLayout.module.css'; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user