From 0042fd1951a9adb029dc0925f1a81a3189c4accd Mon Sep 17 00:00:00 2001 From: "Mr.Dat" Date: Mon, 5 Jan 2026 19:13:03 +0700 Subject: [PATCH] init --- bun.lock | 42 ++++++++++ components.d.ts | 12 --- package.json | 2 + ssrPlugin.ts => plugins/ssrPlugin.ts | 14 ++-- plugins/vite-plugin-ssr-middleware.ts | 116 ++++++++++++++++++++++++++ src/index.tsx | 2 + vite.config.ts | 27 +++++- 7 files changed, 194 insertions(+), 21 deletions(-) rename ssrPlugin.ts => plugins/ssrPlugin.ts (90%) create mode 100644 plugins/vite-plugin-ssr-middleware.ts diff --git a/bun.lock b/bun.lock index a4df97c..cc88dfd 100644 --- a/bun.lock +++ b/bun.lock @@ -25,6 +25,8 @@ }, "devDependencies": { "@cloudflare/vite-plugin": "^1.17.1", + "@hattip/adapter-node": "^0.0.49", + "@hono/vite-dev-server": "^0.24.0", "@primevue/auto-import-resolver": "^4.5.4", "@types/node": "^25.0.3", "@vitejs/plugin-vue": "^6.0.3", @@ -253,10 +255,24 @@ "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.0", "", { "os": "win32", "cpu": "x64" }, "sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg=="], + "@hattip/adapter-node": ["@hattip/adapter-node@0.0.49", "", { "dependencies": { "@hattip/core": "0.0.49", "@hattip/polyfills": "0.0.49", "@hattip/walk": "0.0.49" } }, "sha512-BE+Y8Q4U0YcH34FZUYU4DssGKOaZLbNL0zK57Z41UZp0m9kS79ZIolBmjjpPhTVpIlRY3Rs+uhXbVXKk7mUcJA=="], + + "@hattip/core": ["@hattip/core@0.0.49", "", {}, "sha512-3/ZJtC17cv8m6Sph8+nw4exUp9yhEf2Shi7HK6AHSUSBtaaQXZ9rJBVxTfZj3PGNOR/P49UBXOym/52WYKFTJQ=="], + + "@hattip/headers": ["@hattip/headers@0.0.49", "", { "dependencies": { "@hattip/core": "0.0.49" } }, "sha512-rrB2lEhTf0+MNVt5WdW184Ky706F1Ze9Aazn/R8c+/FMUYF9yjem2CgXp49csPt3dALsecrnAUOHFiV0LrrHXA=="], + + "@hattip/polyfills": ["@hattip/polyfills@0.0.49", "", { "dependencies": { "@hattip/core": "0.0.49", "@whatwg-node/fetch": "^0.9.22", "node-fetch-native": "^1.6.4" } }, "sha512-5g7W5s6Gq+HDxwULGFQ861yAnEx3yd9V8GDwS96HBZ1nM1u93vN+KTuwXvNsV7Z3FJmCrD/pgU8WakvchclYuA=="], + + "@hattip/walk": ["@hattip/walk@0.0.49", "", { "dependencies": { "@hattip/headers": "0.0.49", "cac": "^6.7.14", "mime-types": "^2.1.35" }, "bin": { "hattip-walk": "cli.js" } }, "sha512-AgJgKLooZyQnzMfoFg5Mo/aHM+HGBC9ExpXIjNqGimYTRgNbL/K7X5EM1kR2JY90BNKk9lo6Usq1T/nWFdT7TQ=="], + "@hiogawa/tiny-rpc": ["@hiogawa/tiny-rpc@0.2.3-pre.18", "", {}, "sha512-BiNHrutG9G9yV622QvkxZxF+PhkaH2Aspp4/X1KYTfnaQTcg4fFUTBWf5Kf533swon2SuVJwi6U6H1LQbhVOQQ=="], "@hiogawa/utils": ["@hiogawa/utils@1.7.0", "", {}, "sha512-ghiEFWBR1NENoHn+lSuW7liicTIzVPN+8Srm5UedCTw43gus0mlse6Wp2lz6GmbOXJ/CalMPp/0Tz2X8tajkAg=="], + "@hono/node-server": ["@hono/node-server@1.19.7", "", { "peerDependencies": { "hono": "^4" } }, "sha512-vUcD0uauS7EU2caukW8z5lJKtoGMokxNbJtBiwHgpqxEXokaHCBkQUmCHhjFB1VUTWdqj25QoMkMKzgjq+uhrw=="], + + "@hono/vite-dev-server": ["@hono/vite-dev-server@0.24.0", "", { "dependencies": { "@hono/node-server": "^1.14.2", "minimatch": "^9.0.3" }, "peerDependencies": { "hono": "*", "miniflare": "*", "wrangler": "*" }, "optionalPeers": ["miniflare", "wrangler"] }, "sha512-yV+DHE9suDPPvZW/o4VhY2KFl0vrIPvt0zDlj22V6wkTsEKy7TGpAd4tw0swOhN3Zfb7mXch7QAGEtO9c6qrMQ=="], + "@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="], "@iconify/utils": ["@iconify/utils@3.1.0", "", { "dependencies": { "@antfu/install-pkg": "^1.1.0", "@iconify/types": "^2.0.0", "mlly": "^1.8.0" } }, "sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw=="], @@ -309,6 +325,8 @@ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], + "@kamilkisiela/fast-url-parser": ["@kamilkisiela/fast-url-parser@1.1.4", "", {}, "sha512-gbkePEBupNydxCelHCESvFSFM8XPh1Zs/OAVRW/rKpEqPAl5PbOM90Si8mv9bvnR53uPD2s/FiRxdvSejpRJew=="], + "@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="], "@poppinss/colors": ["@poppinss/colors@4.1.6", "", { "dependencies": { "kleur": "^4.1.5" } }, "sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg=="], @@ -589,10 +607,16 @@ "@vueuse/shared": ["@vueuse/shared@14.1.0", "", { "peerDependencies": { "vue": "^3.5.0" } }, "sha512-EcKxtYvn6gx1F8z9J5/rsg3+lTQnvOruQd8fUecW99DCK04BkWD7z5KQ/wTAx+DazyoEE9dJt/zV8OIEQbM6kw=="], + "@whatwg-node/fetch": ["@whatwg-node/fetch@0.9.23", "", { "dependencies": { "@whatwg-node/node-fetch": "^0.6.0", "urlpattern-polyfill": "^10.0.0" } }, "sha512-7xlqWel9JsmxahJnYVUj/LLxWcnA93DR4c9xlw3U814jWTiYalryiH1qToik1hOxweKKRLi4haXHM5ycRksPBA=="], + + "@whatwg-node/node-fetch": ["@whatwg-node/node-fetch@0.6.0", "", { "dependencies": { "@kamilkisiela/fast-url-parser": "^1.1.4", "busboy": "^1.6.0", "fast-querystring": "^1.1.1", "tslib": "^2.6.3" } }, "sha512-tcZAhrpx6oVlkEsRngeTEEE7I5/QdLjeEz4IlekabGaESP7+Dkm/6a9KcF1KdCBB7mO9PXtBkwCuTCt8+UPg8Q=="], + "acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="], "acorn-walk": ["acorn-walk@8.3.2", "", {}, "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A=="], + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "baseline-browser-mapping": ["baseline-browser-mapping@2.9.11", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ=="], "birpc": ["birpc@2.9.0", "", {}, "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw=="], @@ -601,8 +625,12 @@ "bowser": ["bowser@2.13.1", "", {}, "sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw=="], + "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="], + "busboy": ["busboy@1.6.0", "", { "dependencies": { "streamsearch": "^1.1.0" } }, "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA=="], + "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], "caniuse-lite": ["caniuse-lite@1.0.30001762", "", {}, "sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw=="], @@ -663,6 +691,10 @@ "exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="], + "fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="], + + "fast-querystring": ["fast-querystring@1.1.2", "", { "dependencies": { "fast-decode-uri-component": "^1.0.1" } }, "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg=="], + "fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="], "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], @@ -709,8 +741,14 @@ "mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="], + "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + + "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + "miniflare": ["miniflare@4.20251210.0", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "7.14.0", "workerd": "1.20251210.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-k6kIoXwGVqlPZb0hcn+X7BmnK+8BjIIkusQPY22kCo2RaQJ/LzAjtxHQdGXerlHSnJyQivDQsL6BJHMpQfUFyw=="], + "minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "mitt": ["mitt@3.0.1", "", {}, "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="], "mlly": ["mlly@1.8.0", "", { "dependencies": { "acorn": "^8.15.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.1" } }, "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g=="], @@ -771,6 +809,8 @@ "stoppable": ["stoppable@1.1.0", "", {}, "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw=="], + "streamsearch": ["streamsearch@1.1.0", "", {}, "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="], + "strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="], "strnum": ["strnum@2.1.2", "", {}, "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ=="], @@ -817,6 +857,8 @@ "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], + "urlpattern-polyfill": ["urlpattern-polyfill@10.1.0", "", {}, "sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw=="], + "vite": ["vite@7.3.0", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg=="], "vite-ssr-components": ["vite-ssr-components@0.5.2", "", { "dependencies": { "@babel/parser": "^7.27.2", "@babel/traverse": "^7.27.1", "picomatch": "^4.0.2" } }, "sha512-1a8YThRwyyu1gGjc1Ral9Q4uS+n0D4GydhbkVd9c1SA1YNgXyrOizttped87C1ItEznQzhiCyQjaOcYnXa0zMA=="], diff --git a/components.d.ts b/components.d.ts index ef49267..50cbcb9 100644 --- a/components.d.ts +++ b/components.d.ts @@ -13,19 +13,15 @@ export {} declare module 'vue' { export interface GlobalComponents { Add: typeof import('./src/components/icons/Add.vue')['default'] - AddFilled: typeof import('./src/components/icons/AddFilled.vue')['default'] Bell: typeof import('./src/components/icons/Bell.vue')['default'] - BellFilled: typeof import('./src/components/icons/BellFilled.vue')['default'] Button: typeof import('primevue/button')['default'] Checkbox: typeof import('primevue/checkbox')['default'] CheckIcon: typeof import('./src/components/icons/CheckIcon.vue')['default'] Credit: typeof import('./src/components/icons/Credit.vue')['default'] DashboardLayout: typeof import('./src/components/DashboardLayout.vue')['default'] Home: typeof import('./src/components/icons/Home.vue')['default'] - HomeFilled: typeof import('./src/components/icons/HomeFilled.vue')['default'] InputText: typeof import('primevue/inputtext')['default'] Layout: typeof import('./src/components/icons/Layout.vue')['default'] - LayoutFilled: typeof import('./src/components/icons/LayoutFilled.vue')['default'] Message: typeof import('primevue/message')['default'] Password: typeof import('primevue/password')['default'] RootLayout: typeof import('./src/components/RootLayout.vue')['default'] @@ -33,9 +29,7 @@ declare module 'vue' { RouterView: typeof import('vue-router')['RouterView'] TestIcon: typeof import('./src/components/icons/TestIcon.vue')['default'] Upload: typeof import('./src/components/icons/Upload.vue')['default'] - UploadFilled: typeof import('./src/components/icons/UploadFilled.vue')['default'] Video: typeof import('./src/components/icons/Video.vue')['default'] - VideoFilled: typeof import('./src/components/icons/VideoFilled.vue')['default'] VueHead: typeof import('./src/components/VueHead.tsx')['default'] } } @@ -43,19 +37,15 @@ declare module 'vue' { // For TSX support declare global { const Add: typeof import('./src/components/icons/Add.vue')['default'] - const AddFilled: typeof import('./src/components/icons/AddFilled.vue')['default'] const Bell: typeof import('./src/components/icons/Bell.vue')['default'] - const BellFilled: typeof import('./src/components/icons/BellFilled.vue')['default'] const Button: typeof import('primevue/button')['default'] const Checkbox: typeof import('primevue/checkbox')['default'] const CheckIcon: typeof import('./src/components/icons/CheckIcon.vue')['default'] const Credit: typeof import('./src/components/icons/Credit.vue')['default'] const DashboardLayout: typeof import('./src/components/DashboardLayout.vue')['default'] const Home: typeof import('./src/components/icons/Home.vue')['default'] - const HomeFilled: typeof import('./src/components/icons/HomeFilled.vue')['default'] const InputText: typeof import('primevue/inputtext')['default'] const Layout: typeof import('./src/components/icons/Layout.vue')['default'] - const LayoutFilled: typeof import('./src/components/icons/LayoutFilled.vue')['default'] const Message: typeof import('primevue/message')['default'] const Password: typeof import('primevue/password')['default'] const RootLayout: typeof import('./src/components/RootLayout.vue')['default'] @@ -63,8 +53,6 @@ declare global { const RouterView: typeof import('vue-router')['RouterView'] const TestIcon: typeof import('./src/components/icons/TestIcon.vue')['default'] const Upload: typeof import('./src/components/icons/Upload.vue')['default'] - const UploadFilled: typeof import('./src/components/icons/UploadFilled.vue')['default'] const Video: typeof import('./src/components/icons/Video.vue')['default'] - const VideoFilled: typeof import('./src/components/icons/VideoFilled.vue')['default'] const VueHead: typeof import('./src/components/VueHead.tsx')['default'] } \ No newline at end of file diff --git a/package.json b/package.json index f6177e4..9e49699 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,8 @@ }, "devDependencies": { "@cloudflare/vite-plugin": "^1.17.1", + "@hattip/adapter-node": "^0.0.49", + "@hono/vite-dev-server": "^0.24.0", "@primevue/auto-import-resolver": "^4.5.4", "@types/node": "^25.0.3", "@vitejs/plugin-vue": "^6.0.3", diff --git a/ssrPlugin.ts b/plugins/ssrPlugin.ts similarity index 90% rename from ssrPlugin.ts rename to plugins/ssrPlugin.ts index 21dce38..01906e7 100644 --- a/ssrPlugin.ts +++ b/plugins/ssrPlugin.ts @@ -26,16 +26,17 @@ export function clientFirstBuild(): Plugin { config.builder.buildApp = async (builder) => { const clientEnvironment = builder.environments.client; const workerEnvironments = Object.keys(builder.environments) - .filter((name) => name !== "client" && name !== "ssr") + .filter((name) => name !== "client") .map((name) => builder.environments[name]); // console.log('Client First Build Plugin: Starting builds...', workerEnvironments) // Client build first // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (clientEnvironment) { - // console.log("Client First Build Plugin: Building client...", clientEnvironment.resolve); + // clientEnvironment.config.build.outDir = "dist/client"; + // console.log("Client First Build Plugin: Building client...", Object.keys()); await builder.build(clientEnvironment); } - + // console.log("Client First Build Plugin: Client build complete.", workerEnvironments); // Then worker builds for (const workerEnv of workerEnvironments) { await builder.build(workerEnv); @@ -110,12 +111,13 @@ export default function ssrPlugin(): Plugin[] { }, resolveId(id, importer, options) { if (!id.startsWith('@httpClientAdapter')) return - + const pwd = process.cwd() + console.log('Resolving httpClientAdapter in', pwd, 'for', {id, importer, options}) return path.resolve( __dirname, options?.ssr - ? "./src/api/httpClientAdapter.server.ts" - : "./src/api/httpClientAdapter.client.ts" + ? pwd+"/src/api/httpClientAdapter.server.ts" + : pwd+"/src/api/httpClientAdapter.client.ts" ); }, async configResolved(config) { diff --git a/plugins/vite-plugin-ssr-middleware.ts b/plugins/vite-plugin-ssr-middleware.ts new file mode 100644 index 0000000..b4a7452 --- /dev/null +++ b/plugins/vite-plugin-ssr-middleware.ts @@ -0,0 +1,116 @@ +import type { Connect, Plugin } from "vite"; +import { name as packageName } from "../package.json"; +import { createMiddleware } from "@hattip/adapter-node"; +import { pathToFileURL } from "url"; + + +export function vitePluginSsrMiddleware({ + entry, + preview, + mode = "ssrLoadModule", +}: { + entry: string; + preview?: string; + mode?: "ssrLoadModule" | "ModuleRunner" | "ModuleRunner-HMR"; +}): Plugin { + return { + name: packageName, + + apply(config, env) { + // skip client build + return Boolean(env.command === "serve" || config.build?.ssr); + }, + + config(config, env) { + if (env.command === "serve") { + return { + // disable builtin HTML middleware, which would rewrite `req.url` to "/index.html" + appType: "custom", + }; + } + if (env.command === "build" && config.build?.ssr) { + return { + build: { + rollupOptions: { + input: { + index: entry, + }, + }, + }, + }; + } + return; + }, + + async configureServer(server) { + let loadModule = server.ssrLoadModule; + if (mode === "ModuleRunner" || mode === "ModuleRunner-HMR") { + const { createServerModuleRunner } = await import("vite"); + const runner = createServerModuleRunner(server.environments.ssr, { + hmr: mode === "ModuleRunner-HMR" ? undefined : false, + }); + loadModule = (id: string) => runner.import(id); + } + + const handler: Connect.NextHandleFunction = async (req, res, next) => { + // expose ViteDevServer via request + Object.defineProperty(req, "viteDevServer", { value: server }); + + try { + const mod = await loadModule(entry); + await createMiddleware((ctx) => mod["default"].fetch(ctx.request))(req, res, next); + // await mod["default"](req, res, next); + } catch (e) { + next(e); + } + }; + return () => server.middlewares.use(handler); + }, + + async configurePreviewServer(server) { + if (preview) { + const mod = await import( pathToFileURL(preview).href); + return () => server.middlewares.use(createMiddleware((ctx) => mod["default"].fetch(ctx.request))); + } + return; + }, + }; +} + +// minimal logger inspired by +// https://github.com/koajs/logger +// https://github.com/honojs/hono/blob/25beca878f2662fedd84ed3fbf80c6a515609cea/src/middleware/logger/index.ts + +export function vitePluginLogger(): Plugin { + return { + name: vitePluginLogger.name, + configureServer(server) { + return () => server.middlewares.use(loggerMiddleware()); + }, + configurePreviewServer(server) { + return () => server.middlewares.use(loggerMiddleware()); + }, + }; +} + +function loggerMiddleware(): Connect.NextHandleFunction { + return (req, res, next) => { + const url = new URL(req.originalUrl!, "https://test.local"); + console.log(" -->", req.method, url.pathname); + const startTime = Date.now(); + res.once("close", () => { + console.log( + " <--", + req.method, + url.pathname, + res.statusCode, + formatDuration(Date.now() - startTime), + ); + }); + next(); + }; +} + +function formatDuration(ms: number) { + return ms < 1000 ? `${Math.floor(ms)}ms` : `${(ms / 1000).toFixed(1)}s`; +} \ No newline at end of file diff --git a/src/index.tsx b/src/index.tsx index ca7d69a..bb93da0 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -9,6 +9,7 @@ import { cors } from "hono/cors"; import { jwtRpc, rpcServer } from './api/rpc'; import isMobile from 'is-mobile'; import { useAuthStore } from './stores/auth'; +import { serveStatic } from "hono/bun"; import { cssContent } from './lib/primeCssContent'; import { styleTags } from './lib/primePassthrough'; // @ts-ignore @@ -26,6 +27,7 @@ app.use(cors(), async (c, next) => { c.set("isMobile", isMobile({ ua })); await next(); }, rpcServer); +app.use(serveStatic({ root: "./public" })) app.get("/.well-known/*", (c) => { return c.json({ ok: true }); }); diff --git a/vite.config.ts b/vite.config.ts index 5566f1f..132904a 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -7,7 +7,9 @@ import unocss from "unocss/vite"; import Components from "unplugin-vue-components/vite"; import AutoImport from "unplugin-auto-import/vite"; import { defineConfig } from "vite"; -import ssrPlugin from "./ssrPlugin"; +import ssrPlugin from "./plugins/ssrPlugin"; +import devServer from '@hono/vite-dev-server' +import { vitePluginSsrMiddleware } from "./plugins/vite-plugin-ssr-middleware"; export default defineConfig((env) => { // console.log("env:", env, import.meta.env); return { @@ -28,8 +30,26 @@ export default defineConfig((env) => { resolvers: [PrimeVueResolver()], }), ssrPlugin(), - cloudflare(), + vitePluginSsrMiddleware({ + entry: "src/index.tsx", + preview: path.resolve("dist/server/index.js"), + }) + // devServer({ + // entry: 'src/index.tsx', + // }), + // cloudflare(), ], + environments: { + ssr: { + build: { + outDir: "dist/server", + copyPublicDir: false, + rollupOptions: { + input: { index: "/src/index.tsx" }, + }, + }, + }, + }, resolve: { alias: { "@": path.resolve(__dirname, "./src"), @@ -41,7 +61,8 @@ export default defineConfig((env) => { }, ssr: { - noExternal: ["vue"], + // external: ["vue"] + // noExternal: ["vue"], }, }; });