diff --git a/README.md b/README.md index a91bf3d..c866093 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ | `hono` | [examples/hono](./examples/hono/) | [stackblitz](https://stackblitz.com/fork/github/nitrojs/nitro-vite-examples/tree/main/examples/hono?startScript=dev&file=vite.config.mjs,server.ts) | `npx giget gh:nitrojs/vite-examples/examples/hono hono-app` | | `node-compat` | [examples/node-compat](./examples/node-compat/) | [stackblitz](https://stackblitz.com/fork/github/nitrojs/nitro-vite-examples/tree/main/examples/node-compat?startScript=dev&file=vite.config.mjs,server.ts) | `npx giget gh:nitrojs/vite-examples/examples/node-compat node-compat-app` | | `react-ssr` | [examples/react-ssr](./examples/react-ssr/) | [stackblitz](https://stackblitz.com/fork/github/nitrojs/nitro-vite-examples/tree/main/examples/react-ssr?startScript=dev&file=vite.config.mjs,server.ts) | `npx giget gh:nitrojs/vite-examples/examples/react-ssr react-ssr-app` | +| `solid-ssr` | [examples/solid-ssr](./examples/solid-ssr/) | [stackblitz](https://stackblitz.com/fork/github/nitrojs/nitro-vite-examples/tree/main/examples/solid-ssr?startScript=dev&file=vite.config.mjs,server.ts) | `npx giget gh:nitrojs/vite-examples/examples/solid-ssr solid-ssr-app` | | `vue-ssr` | [examples/vue-ssr](./examples/vue-ssr/) | [stackblitz](https://stackblitz.com/fork/github/nitrojs/nitro-vite-examples/tree/main/examples/vue-ssr?startScript=dev&file=vite.config.mjs,server.ts) | `npx giget gh:nitrojs/vite-examples/examples/vue-ssr vue-ssr-app` | diff --git a/examples/solid-ssr/package.json b/examples/solid-ssr/package.json new file mode 100644 index 0000000..0aa13f9 --- /dev/null +++ b/examples/solid-ssr/package.json @@ -0,0 +1,15 @@ +{ + "name": "nitro-vite-solid-ssr", + "version": "0.0.0", + "scripts": { + "build": "vite build", + "dev": "vite dev" + }, + "devDependencies": { + "@vitejs/plugin-react": "^4.6.0", + "nitro": "npm:nitro-nightly", + "solid-js": "^1.9.7", + "vite": "^7", + "vite-plugin-solid": "^2.11.7" + } +} diff --git a/examples/solid-ssr/src/App.tsx b/examples/solid-ssr/src/App.tsx new file mode 100644 index 0000000..c224710 --- /dev/null +++ b/examples/solid-ssr/src/App.tsx @@ -0,0 +1,15 @@ +/// +import { createSignal } from "solid-js"; + +export default () => { + const [count, setCount] = createSignal(0); + + return ( +
+

Hello, Solid!

+ +
+ ); +}; diff --git a/examples/solid-ssr/src/client.tsx b/examples/solid-ssr/src/client.tsx new file mode 100644 index 0000000..0b35eaf --- /dev/null +++ b/examples/solid-ssr/src/client.tsx @@ -0,0 +1,7 @@ +/// +import { hydrate } from "solid-js/web"; +import "./styles.css"; + +const App = await import("./App.jsx").then((mod) => mod.default); + +hydrate(() => , document.querySelector("#app")!); diff --git a/examples/solid-ssr/src/server.tsx b/examples/solid-ssr/src/server.tsx new file mode 100644 index 0000000..479c0f8 --- /dev/null +++ b/examples/solid-ssr/src/server.tsx @@ -0,0 +1,50 @@ +import { renderToStringAsync, generateHydrationScript } from "solid-js/web"; +import App from "./App.jsx"; + +export default { + async fetch(req: Request): Promise { + const appHTML = await renderToStringAsync(() => ); + return new Response(indexHTML(appHTML), { + headers: { + "Content-Type": "text/html", + }, + }); + }, +}; + +function indexHTML(appHTML: string) { + return /* html */ ` + + + + + Vite + Nitro + Solid + ${ + import.meta.env?.DEV + ? '' + : "" + } + + +
${appHTML}
+ + ${generateHydrationScript()} + +`; +} + +function resolveEntry(entry: string): string { + if (import.meta.env?.PROD) { + const manifest = globalThis.__VITE_MANIFEST__; + const file = manifest?.[entry]?.file; + if (!file) { + throw new Error( + manifest + ? `Entry "${entry}" not found in Vite manifest.` + : "Vite manifest is not available.", + ); + } + return `/${file}`; + } + return `/${entry}`; +} diff --git a/examples/solid-ssr/src/styles.css b/examples/solid-ssr/src/styles.css new file mode 100644 index 0000000..59990a6 --- /dev/null +++ b/examples/solid-ssr/src/styles.css @@ -0,0 +1,19 @@ +div { + font-family: system-ui, Arial, sans-serif; + font-size: 20px; + margin-bottom: 10px; +} + +button { + background-color: rgb(147 197 253); + color: rgb(15 23 42); + border: none; + padding: 10px 20px; + font-size: 16px; + cursor: pointer; + border-radius: 5px; +} + +button:hover { + background-color: rgb(191 219 254); +} diff --git a/examples/solid-ssr/tsconfig.json b/examples/solid-ssr/tsconfig.json new file mode 100644 index 0000000..249b273 --- /dev/null +++ b/examples/solid-ssr/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "strict": true, + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + "types": ["vite/client"], + "noEmit": true, + "isolatedModules": true + } +} diff --git a/examples/solid-ssr/vite.config.mjs b/examples/solid-ssr/vite.config.mjs new file mode 100644 index 0000000..1abe8a3 --- /dev/null +++ b/examples/solid-ssr/vite.config.mjs @@ -0,0 +1,16 @@ +import solid from "vite-plugin-solid"; +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ + plugins: [solid({ ssr: true }), nitro()], + esbuild: { + jsx: "preserve", + jsxImportSource: "solid-js", + }, + environments: { + client: { + build: { rollupOptions: { input: "./src/client.tsx" } }, + }, + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 926f434..31da2e4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -92,6 +92,24 @@ importers: specifier: ^3.5.17 version: 3.5.17 + examples/solid-ssr: + devDependencies: + '@vitejs/plugin-react': + specifier: ^4.6.0 + version: 4.6.0(vite@7.0.5(@types/node@24.0.14)(jiti@2.4.2)(terser@5.43.1)) + nitro: + specifier: npm:nitro-nightly@3.0.0-20250717-115429.740761af + version: nitro-nightly@3.0.0-20250717-115429.740761af(vite@7.0.5(@types/node@24.0.14)(jiti@2.4.2)(terser@5.43.1)) + solid-js: + specifier: ^1.9.7 + version: 1.9.7 + vite: + specifier: ^7.0.4 + version: 7.0.5(@types/node@24.0.14)(jiti@2.4.2)(terser@5.43.1) + vite-plugin-solid: + specifier: ^2.11.7 + version: 2.11.7(solid-js@1.9.7)(vite@7.0.5(@types/node@24.0.14)(jiti@2.4.2)(terser@5.43.1)) + examples/vue-ssr: devDependencies: '@vitejs/plugin-vue': @@ -137,6 +155,10 @@ packages: resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.18.6': + resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} + engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.27.1': resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} @@ -172,6 +194,12 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/plugin-syntax-jsx@7.27.1': + resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-react-jsx-self@7.27.1': resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} engines: {node: '>=6.9.0'} @@ -803,6 +831,16 @@ packages: resolution: {integrity: sha512-zU63NNzqdaUoFMUgw6srqFem4p+FiKV+wsavIsaT8NDyJK9H7SsElWv/+3kiCvJp71Ukjau9Roz0kF1hCy0cYA==} hasBin: true + babel-plugin-jsx-dom-expressions@0.39.8: + resolution: {integrity: sha512-/MVOIIjonylDXnrWmG23ZX82m9mtKATsVHB7zYlPfDR9Vdd/NBE48if+wv27bSkBtyO7EPMUlcUc4J63QwuACQ==} + peerDependencies: + '@babel/core': ^7.20.12 + + babel-preset-solid@1.9.6: + resolution: {integrity: sha512-HXTK9f93QxoH8dYn1M2mJdOlWgMsR88Lg/ul6QCZGkNTktjTE5HAf93YxQumHoCudLEtZrU1cFCMFOVho6GqFg==} + peerDependencies: + '@babel/core': ^7.0.0 + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -1020,6 +1058,10 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + error-stack-parser-es@1.0.5: resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} @@ -1178,6 +1220,9 @@ packages: hookable@5.5.3: resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + html-entities@2.3.3: + resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==} + http-errors@2.0.0: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} @@ -1256,6 +1301,10 @@ packages: resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + is-what@4.1.16: + resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} + engines: {node: '>=12.13'} + is-wsl@2.2.0: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} @@ -1343,6 +1392,10 @@ packages: mdbox@0.1.1: resolution: {integrity: sha512-jvLISenzbLRPWWamTG3THlhTcMbKWzJQNyTi61AVXhCBOC+gsldNTUfUNH8d3Vay83zGehFw3wZpF3xChzkTIQ==} + merge-anything@5.1.7: + resolution: {integrity: sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==} + engines: {node: '>=12.13'} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -1483,6 +1536,9 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -1655,6 +1711,16 @@ packages: serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + seroval-plugins@1.3.2: + resolution: {integrity: sha512-0QvCV2lM3aj/U3YozDiVwx9zpH0q8A60CTWIv4Jszj/givcudPb48B+rkU5D51NJ0pTpweGMttHjboPa9/zoIQ==} + engines: {node: '>=10'} + peerDependencies: + seroval: ^1.0 + + seroval@1.3.2: + resolution: {integrity: sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==} + engines: {node: '>=10'} + serve-placeholder@2.0.2: resolution: {integrity: sha512-/TMG8SboeiQbZJWRlfTCqMs2DD3SZgWp0kDQePz9yUuCnDfDh/92gf7/PxGhzXTKBIPASIHxFcZndoNbp6QOLQ==} @@ -1684,6 +1750,14 @@ packages: smob@1.5.0: resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} + solid-js@1.9.7: + resolution: {integrity: sha512-/saTKi8iWEM233n5OSi1YHCCuh66ZIQ7aK2hsToPe4tqGm7qAejU1SwNuTPivbWAYq7SjuHVVYxxuZQNRbICiw==} + + solid-refresh@0.6.3: + resolution: {integrity: sha512-F3aPsX6hVw9ttm5LYlth8Q15x6MlI/J3Dn+o3EQyRTtTxidepSTwAYdozt01/YA+7ObcciagGEyXIopGZzQtbA==} + peerDependencies: + solid-js: ^1.3 + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -1908,6 +1982,19 @@ packages: uqr@0.1.2: resolution: {integrity: sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==} + validate-html-nesting@1.2.3: + resolution: {integrity: sha512-kdkWdCl6eCeLlRShJKbjVOU2kFKxMF8Ghu50n+crEoyx+VKm3FxAxF9z4DCy6+bbTOqNW0+jcIYRnjoIRzigRw==} + + vite-plugin-solid@2.11.7: + resolution: {integrity: sha512-5TgK1RnE449g0Ryxb9BXqem89RSy7fE8XGVCo+Gw84IHgPuPVP7nYNP6WBVAaY/0xw+OqfdQee+kusL0y3XYNg==} + peerDependencies: + '@testing-library/jest-dom': ^5.16.6 || ^5.17.0 || ^6.* + solid-js: ^1.7.2 + vite: ^7.0.4 + peerDependenciesMeta: + '@testing-library/jest-dom': + optional: true + vite@7.0.5: resolution: {integrity: sha512-1mncVwJxy2C9ThLwz0+2GKZyEXuC3MyWtAAlNftlZZXZDP3AJt5FmwcMit/IGGaNZ8ZOB2BNO/HFUB+CpN0NQw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1948,6 +2035,14 @@ packages: yaml: optional: true + vitefu@1.1.1: + resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==} + peerDependencies: + vite: ^7.0.4 + peerDependenciesMeta: + vite: + optional: true + vue@3.5.17: resolution: {integrity: sha512-LbHV3xPN9BeljML+Xctq4lbz2lVHCR6DtbpTf5XIO6gugpXUN49j2QQPcMj086r9+AkJ0FfUT8xjulKKBkkr9g==} peerDependencies: @@ -2057,6 +2152,10 @@ snapshots: '@babel/helper-globals@7.28.0': {} + '@babel/helper-module-imports@7.18.6': + dependencies: + '@babel/types': 7.28.1 + '@babel/helper-module-imports@7.27.1': dependencies: '@babel/traverse': 7.28.0 @@ -2090,6 +2189,11 @@ snapshots: dependencies: '@babel/types': 7.28.1 + '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 @@ -2646,6 +2750,21 @@ snapshots: transitivePeerDependencies: - magicast + babel-plugin-jsx-dom-expressions@0.39.8(@babel/core@7.28.0): + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-module-imports': 7.18.6 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.0) + '@babel/types': 7.28.1 + html-entities: 2.3.3 + parse5: 7.3.0 + validate-html-nesting: 1.2.3 + + babel-preset-solid@1.9.6(@babel/core@7.28.0): + dependencies: + '@babel/core': 7.28.0 + babel-plugin-jsx-dom-expressions: 0.39.8(@babel/core@7.28.0) + balanced-match@1.0.2: {} bindings@1.5.0: @@ -2806,6 +2925,8 @@ snapshots: entities@4.5.0: {} + entities@6.0.1: {} + error-stack-parser-es@1.0.5: {} esbuild@0.25.6: @@ -2994,6 +3115,8 @@ snapshots: hookable@5.5.3: {} + html-entities@2.3.3: {} + http-errors@2.0.0: dependencies: depd: 2.0.0 @@ -3065,6 +3188,8 @@ snapshots: is-stream@3.0.0: {} + is-what@4.1.16: {} + is-wsl@2.2.0: dependencies: is-docker: 2.2.1 @@ -3162,6 +3287,10 @@ snapshots: dependencies: md4w: 0.2.7 + merge-anything@5.1.7: + dependencies: + is-what: 4.1.16 + merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -3363,6 +3492,10 @@ snapshots: package-json-from-dist@1.0.1: {} + parse5@7.3.0: + dependencies: + entities: 6.0.1 + parseurl@1.3.3: {} path-key@3.1.1: {} @@ -3529,6 +3662,12 @@ snapshots: dependencies: randombytes: 2.1.0 + seroval-plugins@1.3.2(seroval@1.3.2): + dependencies: + seroval: 1.3.2 + + seroval@1.3.2: {} + serve-placeholder@2.0.2: dependencies: defu: 6.1.4 @@ -3556,6 +3695,21 @@ snapshots: smob@1.5.0: {} + solid-js@1.9.7: + dependencies: + csstype: 3.1.3 + seroval: 1.3.2 + seroval-plugins: 1.3.2(seroval@1.3.2) + + solid-refresh@0.6.3(solid-js@1.9.7): + dependencies: + '@babel/generator': 7.28.0 + '@babel/helper-module-imports': 7.27.1 + '@babel/types': 7.28.1 + solid-js: 1.9.7 + transitivePeerDependencies: + - supports-color + source-map-js@1.2.1: {} source-map-support@0.5.21: @@ -3751,6 +3905,21 @@ snapshots: uqr@0.1.2: {} + validate-html-nesting@1.2.3: {} + + vite-plugin-solid@2.11.7(solid-js@1.9.7)(vite@7.0.5(@types/node@24.0.14)(jiti@2.4.2)(terser@5.43.1)): + dependencies: + '@babel/core': 7.28.0 + '@types/babel__core': 7.20.5 + babel-preset-solid: 1.9.6(@babel/core@7.28.0) + merge-anything: 5.1.7 + solid-js: 1.9.7 + solid-refresh: 0.6.3(solid-js@1.9.7) + vite: 7.0.5(@types/node@24.0.14)(jiti@2.4.2)(terser@5.43.1) + vitefu: 1.1.1(vite@7.0.5(@types/node@24.0.14)(jiti@2.4.2)(terser@5.43.1)) + transitivePeerDependencies: + - supports-color + vite@7.0.5(@types/node@24.0.14)(jiti@2.4.2)(terser@5.43.1): dependencies: esbuild: 0.25.6 @@ -3765,6 +3934,10 @@ snapshots: jiti: 2.4.2 terser: 5.43.1 + vitefu@1.1.1(vite@7.0.5(@types/node@24.0.14)(jiti@2.4.2)(terser@5.43.1)): + optionalDependencies: + vite: 7.0.5(@types/node@24.0.14)(jiti@2.4.2)(terser@5.43.1) + vue@3.5.17: dependencies: '@vue/compiler-dom': 3.5.17