Merge pull request #14 from Mechse/client-router
8f8415c0
Select client router: none, reactrouter, tanstack-router
39 file(s) · +2554 −204
Select client router: none, reactrouter, tanstack-router
| 2 | 2 | ||
| 3 | 3 | on: |
|
| 4 | 4 | push: |
|
| 5 | - | branches: [ main ] |
|
| 5 | + | branches: [main] |
|
| 6 | 6 | pull_request: |
|
| 7 | - | branches: [ main ] |
|
| 7 | + | branches: [main] |
|
| 8 | 8 | ||
| 9 | 9 | jobs: |
|
| 10 | 10 | test-cli-options: |
|
| 11 | 11 | runs-on: ubuntu-latest |
|
| 12 | - | ||
| 12 | + | ||
| 13 | 13 | strategy: |
|
| 14 | 14 | fail-fast: false |
|
| 15 | 15 | matrix: |
|
| 18 | 18 | - template: "default" |
|
| 19 | 19 | rpc: true |
|
| 20 | 20 | tanstackQuery: false |
|
| 21 | + | router: "none" |
|
| 21 | 22 | linter: "eslint" |
|
| 22 | - | test_name: "Default + RPC + No TanStack Query + ESLint" |
|
| 23 | + | test_name: "Default + RPC + No TanStack Query + No Router + ESLint" |
|
| 24 | + | - template: "default" |
|
| 25 | + | rpc: true |
|
| 26 | + | tanstackQuery: false |
|
| 27 | + | router: "none" |
|
| 28 | + | linter: "biome" |
|
| 29 | + | test_name: "Default + RPC + No TanStack Query + No Router + Biome" |
|
| 30 | + | - template: "default" |
|
| 31 | + | rpc: false |
|
| 32 | + | tanstackQuery: false |
|
| 33 | + | router: "none" |
|
| 34 | + | linter: "eslint" |
|
| 35 | + | test_name: "Default + No RPC + No TanStack Query + No Router + ESLint" |
|
| 36 | + | - template: "default" |
|
| 37 | + | rpc: false |
|
| 38 | + | tanstackQuery: false |
|
| 39 | + | router: "none" |
|
| 40 | + | linter: "biome" |
|
| 41 | + | test_name: "Default + No RPC + No TanStack Query + No Router + Biome" |
|
| 42 | + | - template: "default" |
|
| 43 | + | rpc: true |
|
| 44 | + | tanstackQuery: true |
|
| 45 | + | router: "none" |
|
| 46 | + | linter: "eslint" |
|
| 47 | + | test_name: "Default + RPC + TanStack Query + No Router + ESLint" |
|
| 48 | + | - template: "default" |
|
| 49 | + | rpc: true |
|
| 50 | + | tanstackQuery: true |
|
| 51 | + | router: "none" |
|
| 52 | + | linter: "biome" |
|
| 53 | + | test_name: "Default + RPC + TanStack Query + No Router + Biome" |
|
| 54 | + | - template: "default" |
|
| 55 | + | rpc: false |
|
| 56 | + | tanstackQuery: true |
|
| 57 | + | router: "none" |
|
| 58 | + | linter: "eslint" |
|
| 59 | + | test_name: "Default + No RPC + TanStack Query + No Router + ESLint" |
|
| 60 | + | - template: "default" |
|
| 61 | + | rpc: false |
|
| 62 | + | tanstackQuery: true |
|
| 63 | + | router: "none" |
|
| 64 | + | linter: "biome" |
|
| 65 | + | test_name: "Default + No RPC + TanStack Query + No Router + Biome" |
|
| 66 | + | ||
| 67 | + | # Tailwind template combinations |
|
| 68 | + | - template: "tailwind" |
|
| 69 | + | rpc: true |
|
| 70 | + | tanstackQuery: false |
|
| 71 | + | router: "none" |
|
| 72 | + | linter: "eslint" |
|
| 73 | + | test_name: "Tailwind + RPC + No TanStack Query + No Router + ESLint" |
|
| 74 | + | - template: "tailwind" |
|
| 75 | + | rpc: true |
|
| 76 | + | tanstackQuery: false |
|
| 77 | + | router: "none" |
|
| 78 | + | linter: "biome" |
|
| 79 | + | test_name: "Tailwind + RPC + No TanStack Query + No Router + Biome" |
|
| 80 | + | - template: "tailwind" |
|
| 81 | + | rpc: false |
|
| 82 | + | tanstackQuery: false |
|
| 83 | + | router: "none" |
|
| 84 | + | linter: "eslint" |
|
| 85 | + | test_name: "Tailwind + No RPC + No TanStack Query + No Router + ESLint" |
|
| 86 | + | - template: "tailwind" |
|
| 87 | + | rpc: false |
|
| 88 | + | tanstackQuery: false |
|
| 89 | + | router: "none" |
|
| 90 | + | linter: "biome" |
|
| 91 | + | test_name: "Tailwind + No RPC + No TanStack Query + No Router + Biome" |
|
| 92 | + | - template: "tailwind" |
|
| 93 | + | rpc: true |
|
| 94 | + | tanstackQuery: true |
|
| 95 | + | router: "none" |
|
| 96 | + | linter: "eslint" |
|
| 97 | + | test_name: "Tailwind + RPC + TanStack Query + No Router + ESLint" |
|
| 98 | + | - template: "tailwind" |
|
| 99 | + | rpc: true |
|
| 100 | + | tanstackQuery: true |
|
| 101 | + | router: "none" |
|
| 102 | + | linter: "biome" |
|
| 103 | + | test_name: "Tailwind + RPC + TanStack Query + No Router + Biome" |
|
| 104 | + | - template: "tailwind" |
|
| 105 | + | rpc: false |
|
| 106 | + | tanstackQuery: true |
|
| 107 | + | router: "none" |
|
| 108 | + | linter: "eslint" |
|
| 109 | + | test_name: "Tailwind + No RPC + TanStack Query + No Router + ESLint" |
|
| 110 | + | - template: "tailwind" |
|
| 111 | + | rpc: false |
|
| 112 | + | tanstackQuery: true |
|
| 113 | + | router: "none" |
|
| 114 | + | linter: "biome" |
|
| 115 | + | test_name: "Tailwind + No RPC + TanStack Query + No Router + Biome" |
|
| 116 | + | ||
| 117 | + | # Shadcn template combinations |
|
| 118 | + | - template: "shadcn" |
|
| 119 | + | rpc: true |
|
| 120 | + | tanstackQuery: false |
|
| 121 | + | router: "none" |
|
| 122 | + | linter: "eslint" |
|
| 123 | + | test_name: "Shadcn + RPC + No TanStack Query + No Router + ESLint" |
|
| 124 | + | - template: "shadcn" |
|
| 125 | + | rpc: true |
|
| 126 | + | tanstackQuery: false |
|
| 127 | + | router: "none" |
|
| 128 | + | linter: "biome" |
|
| 129 | + | test_name: "Shadcn + RPC + No TanStack Query + No Router + Biome" |
|
| 130 | + | - template: "shadcn" |
|
| 131 | + | rpc: false |
|
| 132 | + | tanstackQuery: false |
|
| 133 | + | router: "none" |
|
| 134 | + | linter: "eslint" |
|
| 135 | + | test_name: "Shadcn + No RPC + No TanStack Query + No Router + ESLint" |
|
| 136 | + | - template: "shadcn" |
|
| 137 | + | rpc: false |
|
| 138 | + | tanstackQuery: false |
|
| 139 | + | router: "none" |
|
| 140 | + | linter: "biome" |
|
| 141 | + | test_name: "Shadcn + No RPC + No TanStack Query + No Router + Biome" |
|
| 142 | + | - template: "shadcn" |
|
| 143 | + | rpc: true |
|
| 144 | + | tanstackQuery: true |
|
| 145 | + | router: "none" |
|
| 146 | + | linter: "eslint" |
|
| 147 | + | test_name: "Shadcn + RPC + TanStack Query + No Router + ESLint" |
|
| 148 | + | - template: "shadcn" |
|
| 149 | + | rpc: true |
|
| 150 | + | tanstackQuery: true |
|
| 151 | + | router: "none" |
|
| 152 | + | linter: "biome" |
|
| 153 | + | test_name: "Shadcn + RPC + TanStack Query + No Router + Biome" |
|
| 154 | + | - template: "shadcn" |
|
| 155 | + | rpc: false |
|
| 156 | + | tanstackQuery: true |
|
| 157 | + | router: "none" |
|
| 158 | + | linter: "eslint" |
|
| 159 | + | test_name: "Shadcn + No RPC + TanStack Query + No Router + ESLint" |
|
| 160 | + | - template: "shadcn" |
|
| 161 | + | rpc: false |
|
| 162 | + | tanstackQuery: true |
|
| 163 | + | router: "none" |
|
| 164 | + | linter: "biome" |
|
| 165 | + | test_name: "Shadcn + No RPC + TanStack Query + No Router + Biome" |
|
| 166 | + | ||
| 167 | + | # React Router |
|
| 168 | + | # Default template combinations |
|
| 169 | + | - template: "default" |
|
| 170 | + | rpc: true |
|
| 171 | + | tanstackQuery: false |
|
| 172 | + | router: "reactrouter" |
|
| 173 | + | linter: "eslint" |
|
| 174 | + | test_name: "Default + RPC + No TanStack Query + React Router + ESLint" |
|
| 175 | + | - template: "default" |
|
| 176 | + | rpc: true |
|
| 177 | + | tanstackQuery: false |
|
| 178 | + | router: "reactrouter" |
|
| 179 | + | linter: "biome" |
|
| 180 | + | test_name: "Default + RPC + No TanStack Query + React Router + Biome" |
|
| 181 | + | - template: "default" |
|
| 182 | + | rpc: false |
|
| 183 | + | tanstackQuery: false |
|
| 184 | + | router: "reactrouter" |
|
| 185 | + | linter: "eslint" |
|
| 186 | + | test_name: "Default + No RPC + No TanStack Query + React Router + ESLint" |
|
| 187 | + | - template: "default" |
|
| 188 | + | rpc: false |
|
| 189 | + | tanstackQuery: false |
|
| 190 | + | router: "reactrouter" |
|
| 191 | + | linter: "biome" |
|
| 192 | + | test_name: "Default + No RPC + No TanStack Query + React Router + Biome" |
|
| 193 | + | - template: "default" |
|
| 194 | + | rpc: true |
|
| 195 | + | tanstackQuery: true |
|
| 196 | + | router: "reactrouter" |
|
| 197 | + | linter: "eslint" |
|
| 198 | + | test_name: "Default + RPC + TanStack Query + React Router + ESLint" |
|
| 199 | + | - template: "default" |
|
| 200 | + | rpc: true |
|
| 201 | + | tanstackQuery: true |
|
| 202 | + | router: "reactrouter" |
|
| 203 | + | linter: "biome" |
|
| 204 | + | test_name: "Default + RPC + TanStack Query + React Router + Biome" |
|
| 205 | + | - template: "default" |
|
| 206 | + | rpc: false |
|
| 207 | + | tanstackQuery: true |
|
| 208 | + | router: "reactrouter" |
|
| 209 | + | linter: "eslint" |
|
| 210 | + | test_name: "Default + No RPC + TanStack Query + React Router + ESLint" |
|
| 211 | + | - template: "default" |
|
| 212 | + | rpc: false |
|
| 213 | + | tanstackQuery: true |
|
| 214 | + | router: "reactrouter" |
|
| 215 | + | linter: "biome" |
|
| 216 | + | test_name: "Default + No RPC + TanStack Query + React Router + Biome" |
|
| 217 | + | ||
| 218 | + | # Tailwind template combinations |
|
| 219 | + | - template: "tailwind" |
|
| 220 | + | rpc: true |
|
| 221 | + | tanstackQuery: false |
|
| 222 | + | router: "reactrouter" |
|
| 223 | + | linter: "eslint" |
|
| 224 | + | test_name: "Tailwind + RPC + No TanStack Query + React Router + ESLint" |
|
| 225 | + | - template: "tailwind" |
|
| 226 | + | rpc: true |
|
| 227 | + | tanstackQuery: false |
|
| 228 | + | router: "reactrouter" |
|
| 229 | + | linter: "biome" |
|
| 230 | + | test_name: "Tailwind + RPC + No TanStack Query + React Router + Biome" |
|
| 231 | + | - template: "tailwind" |
|
| 232 | + | rpc: false |
|
| 233 | + | tanstackQuery: false |
|
| 234 | + | router: "reactrouter" |
|
| 235 | + | linter: "eslint" |
|
| 236 | + | test_name: "Tailwind + No RPC + No TanStack Query + React Router + ESLint" |
|
| 237 | + | - template: "tailwind" |
|
| 238 | + | rpc: false |
|
| 239 | + | tanstackQuery: false |
|
| 240 | + | router: "reactrouter" |
|
| 241 | + | linter: "biome" |
|
| 242 | + | test_name: "Tailwind + No RPC + No TanStack Query + React Router + Biome" |
|
| 243 | + | - template: "tailwind" |
|
| 244 | + | rpc: true |
|
| 245 | + | tanstackQuery: true |
|
| 246 | + | router: "reactrouter" |
|
| 247 | + | linter: "eslint" |
|
| 248 | + | test_name: "Tailwind + RPC + TanStack Query + React Router + ESLint" |
|
| 249 | + | - template: "tailwind" |
|
| 250 | + | rpc: true |
|
| 251 | + | tanstackQuery: true |
|
| 252 | + | router: "reactrouter" |
|
| 253 | + | linter: "biome" |
|
| 254 | + | test_name: "Tailwind + RPC + TanStack Query + React Router + Biome" |
|
| 255 | + | - template: "tailwind" |
|
| 256 | + | rpc: false |
|
| 257 | + | tanstackQuery: true |
|
| 258 | + | router: "reactrouter" |
|
| 259 | + | linter: "eslint" |
|
| 260 | + | test_name: "Tailwind + No RPC + TanStack Query + React Router + ESLint" |
|
| 261 | + | - template: "tailwind" |
|
| 262 | + | rpc: false |
|
| 263 | + | tanstackQuery: true |
|
| 264 | + | router: "reactrouter" |
|
| 265 | + | linter: "biome" |
|
| 266 | + | test_name: "Tailwind + No RPC + TanStack Query + React Router + Biome" |
|
| 267 | + | ||
| 268 | + | # Shadcn template combinations |
|
| 269 | + | - template: "shadcn" |
|
| 270 | + | rpc: true |
|
| 271 | + | tanstackQuery: false |
|
| 272 | + | router: "reactrouter" |
|
| 273 | + | linter: "eslint" |
|
| 274 | + | test_name: "Shadcn + RPC + No TanStack Query + React Router + ESLint" |
|
| 275 | + | - template: "shadcn" |
|
| 276 | + | rpc: true |
|
| 277 | + | tanstackQuery: false |
|
| 278 | + | router: "reactrouter" |
|
| 279 | + | linter: "biome" |
|
| 280 | + | test_name: "Shadcn + RPC + No TanStack Query + React Router + Biome" |
|
| 281 | + | - template: "shadcn" |
|
| 282 | + | rpc: false |
|
| 283 | + | tanstackQuery: false |
|
| 284 | + | router: "reactrouter" |
|
| 285 | + | linter: "eslint" |
|
| 286 | + | test_name: "Shadcn + No RPC + No TanStack Query + React Router + ESLint" |
|
| 287 | + | - template: "shadcn" |
|
| 288 | + | rpc: false |
|
| 289 | + | tanstackQuery: false |
|
| 290 | + | router: "reactrouter" |
|
| 291 | + | linter: "biome" |
|
| 292 | + | test_name: "Shadcn + No RPC + No TanStack Query + React Router + Biome" |
|
| 293 | + | - template: "shadcn" |
|
| 294 | + | rpc: true |
|
| 295 | + | tanstackQuery: true |
|
| 296 | + | router: "reactrouter" |
|
| 297 | + | linter: "eslint" |
|
| 298 | + | test_name: "Shadcn + RPC + TanStack Query + React Router + ESLint" |
|
| 299 | + | - template: "shadcn" |
|
| 300 | + | rpc: true |
|
| 301 | + | tanstackQuery: true |
|
| 302 | + | router: "reactrouter" |
|
| 303 | + | linter: "biome" |
|
| 304 | + | test_name: "Shadcn + RPC + TanStack Query + React Router + Biome" |
|
| 305 | + | - template: "shadcn" |
|
| 306 | + | rpc: false |
|
| 307 | + | tanstackQuery: true |
|
| 308 | + | router: "reactrouter" |
|
| 309 | + | linter: "eslint" |
|
| 310 | + | test_name: "Shadcn + No RPC + TanStack Query + React Router + ESLint" |
|
| 311 | + | - template: "shadcn" |
|
| 312 | + | rpc: false |
|
| 313 | + | tanstackQuery: true |
|
| 314 | + | router: "reactrouter" |
|
| 315 | + | linter: "biome" |
|
| 316 | + | test_name: "Shadcn + No RPC + TanStack Query + React Router + Biome" |
|
| 317 | + | ||
| 318 | + | # TanStack Router |
|
| 319 | + | # Default template combinations |
|
| 23 | 320 | - template: "default" |
|
| 24 | 321 | rpc: true |
|
| 25 | 322 | tanstackQuery: false |
|
| 323 | + | router: "tanstackrouter" |
|
| 324 | + | linter: "eslint" |
|
| 325 | + | test_name: "Default + RPC + No TanStack Query + TanStack Router + ESLint" |
|
| 326 | + | - template: "default" |
|
| 327 | + | rpc: true |
|
| 328 | + | tanstackQuery: false |
|
| 329 | + | router: "tanstackrouter" |
|
| 26 | 330 | linter: "biome" |
|
| 27 | - | test_name: "Default + RPC + No TanStack Query + Biome" |
|
| 331 | + | test_name: "Default + RPC + No TanStack Query + TanStack Router + Biome" |
|
| 28 | 332 | - template: "default" |
|
| 29 | 333 | rpc: false |
|
| 30 | 334 | tanstackQuery: false |
|
| 335 | + | router: "tanstackrouter" |
|
| 31 | 336 | linter: "eslint" |
|
| 32 | - | test_name: "Default + No RPC + No TanStack Query + ESLint" |
|
| 337 | + | test_name: "Default + No RPC + No TanStack Query + TanStack Router + ESLint" |
|
| 33 | 338 | - template: "default" |
|
| 34 | 339 | rpc: false |
|
| 35 | 340 | tanstackQuery: false |
|
| 341 | + | router: "tanstackrouter" |
|
| 36 | 342 | linter: "biome" |
|
| 37 | - | test_name: "Default + No RPC + No TanStack Query + Biome" |
|
| 343 | + | test_name: "Default + No RPC + No TanStack Query + TanStack Router + Biome" |
|
| 38 | 344 | - template: "default" |
|
| 39 | 345 | rpc: true |
|
| 40 | 346 | tanstackQuery: true |
|
| 347 | + | router: "tanstackrouter" |
|
| 41 | 348 | linter: "eslint" |
|
| 42 | - | test_name: "Default + RPC + TanStack Query + ESLint" |
|
| 349 | + | test_name: "Default + RPC + TanStack Query + TanStack Router + ESLint" |
|
| 43 | 350 | - template: "default" |
|
| 44 | 351 | rpc: true |
|
| 45 | 352 | tanstackQuery: true |
|
| 353 | + | router: "tanstackrouter" |
|
| 46 | 354 | linter: "biome" |
|
| 47 | - | test_name: "Default + RPC + TanStack Query + Biome" |
|
| 355 | + | test_name: "Default + RPC + TanStack Query + TanStack Router + Biome" |
|
| 48 | 356 | - template: "default" |
|
| 49 | 357 | rpc: false |
|
| 50 | 358 | tanstackQuery: true |
|
| 359 | + | router: "tanstackrouter" |
|
| 51 | 360 | linter: "eslint" |
|
| 52 | - | test_name: "Default + No RPC + TanStack Query + ESLint" |
|
| 361 | + | test_name: "Default + No RPC + TanStack Query + TanStack Router + ESLint" |
|
| 53 | 362 | - template: "default" |
|
| 54 | 363 | rpc: false |
|
| 55 | 364 | tanstackQuery: true |
|
| 365 | + | router: "tanstackrouter" |
|
| 56 | 366 | linter: "biome" |
|
| 57 | - | test_name: "Default + No RPC + TanStack Query + Biome" |
|
| 58 | - | ||
| 367 | + | test_name: "Default + No RPC + TanStack Query + TanStack Router + Biome" |
|
| 368 | + | ||
| 59 | 369 | # Tailwind template combinations |
|
| 60 | 370 | - template: "tailwind" |
|
| 61 | 371 | rpc: true |
|
| 62 | 372 | tanstackQuery: false |
|
| 373 | + | router: "tanstackrouter" |
|
| 63 | 374 | linter: "eslint" |
|
| 64 | - | test_name: "Tailwind + RPC + No TanStack Query + ESLint" |
|
| 375 | + | test_name: "Tailwind + RPC + No TanStack Query + TanStack Router + ESLint" |
|
| 65 | 376 | - template: "tailwind" |
|
| 66 | 377 | rpc: true |
|
| 67 | 378 | tanstackQuery: false |
|
| 379 | + | router: "tanstackrouter" |
|
| 68 | 380 | linter: "biome" |
|
| 69 | - | test_name: "Tailwind + RPC + No TanStack Query + Biome" |
|
| 381 | + | test_name: "Tailwind + RPC + No TanStack Query + TanStack Router + Biome" |
|
| 70 | 382 | - template: "tailwind" |
|
| 71 | 383 | rpc: false |
|
| 72 | 384 | tanstackQuery: false |
|
| 385 | + | router: "tanstackrouter" |
|
| 73 | 386 | linter: "eslint" |
|
| 74 | - | test_name: "Tailwind + No RPC + No TanStack Query + ESLint" |
|
| 387 | + | test_name: "Tailwind + No RPC + No TanStack Query + TanStack Router + ESLint" |
|
| 75 | 388 | - template: "tailwind" |
|
| 76 | 389 | rpc: false |
|
| 77 | 390 | tanstackQuery: false |
|
| 391 | + | router: "tanstackrouter" |
|
| 78 | 392 | linter: "biome" |
|
| 79 | - | test_name: "Tailwind + No RPC + No TanStack Query + Biome" |
|
| 393 | + | test_name: "Tailwind + No RPC + No TanStack Query + TanStack Router + Biome" |
|
| 80 | 394 | - template: "tailwind" |
|
| 81 | 395 | rpc: true |
|
| 82 | 396 | tanstackQuery: true |
|
| 397 | + | router: "tanstackrouter" |
|
| 83 | 398 | linter: "eslint" |
|
| 84 | - | test_name: "Tailwind + RPC + TanStack Query + ESLint" |
|
| 399 | + | test_name: "Tailwind + RPC + TanStack Query + TanStack Router + ESLint" |
|
| 85 | 400 | - template: "tailwind" |
|
| 86 | 401 | rpc: true |
|
| 87 | 402 | tanstackQuery: true |
|
| 403 | + | router: "tanstackrouter" |
|
| 88 | 404 | linter: "biome" |
|
| 89 | - | test_name: "Tailwind + RPC + TanStack Query + Biome" |
|
| 405 | + | test_name: "Tailwind + RPC + TanStack Query + TanStack Router + Biome" |
|
| 90 | 406 | - template: "tailwind" |
|
| 91 | 407 | rpc: false |
|
| 92 | 408 | tanstackQuery: true |
|
| 409 | + | router: "tanstackrouter" |
|
| 93 | 410 | linter: "eslint" |
|
| 94 | - | test_name: "Tailwind + No RPC + TanStack Query + ESLint" |
|
| 411 | + | test_name: "Tailwind + No RPC + TanStack Query + TanStack Router + ESLint" |
|
| 95 | 412 | - template: "tailwind" |
|
| 96 | 413 | rpc: false |
|
| 97 | 414 | tanstackQuery: true |
|
| 415 | + | router: "tanstackrouter" |
|
| 98 | 416 | linter: "biome" |
|
| 99 | - | test_name: "Tailwind + No RPC + TanStack Query + Biome" |
|
| 417 | + | test_name: "Tailwind + No RPC + TanStack Query + TanStack Router + Biome" |
|
| 100 | 418 | ||
| 101 | 419 | # Shadcn template combinations |
|
| 102 | 420 | - template: "shadcn" |
|
| 103 | 421 | rpc: true |
|
| 104 | 422 | tanstackQuery: false |
|
| 423 | + | router: "tanstackrouter" |
|
| 105 | 424 | linter: "eslint" |
|
| 106 | - | test_name: "Shadcn + RPC + No TanStack Query + ESLint" |
|
| 425 | + | test_name: "Shadcn + RPC + No TanStack Query + TanStack Router + ESLint" |
|
| 107 | 426 | - template: "shadcn" |
|
| 108 | 427 | rpc: true |
|
| 109 | 428 | tanstackQuery: false |
|
| 429 | + | router: "tanstackrouter" |
|
| 110 | 430 | linter: "biome" |
|
| 111 | - | test_name: "Shadcn + RPC + No TanStack Query + Biome" |
|
| 431 | + | test_name: "Shadcn + RPC + No TanStack Query + TanStack Router + Biome" |
|
| 112 | 432 | - template: "shadcn" |
|
| 113 | 433 | rpc: false |
|
| 114 | 434 | tanstackQuery: false |
|
| 435 | + | router: "tanstackrouter" |
|
| 115 | 436 | linter: "eslint" |
|
| 116 | - | test_name: "Shadcn + No RPC + No TanStack Query + ESLint" |
|
| 437 | + | test_name: "Shadcn + No RPC + No TanStack Query + TanStack Router + ESLint" |
|
| 117 | 438 | - template: "shadcn" |
|
| 118 | 439 | rpc: false |
|
| 119 | 440 | tanstackQuery: false |
|
| 441 | + | router: "tanstackrouter" |
|
| 120 | 442 | linter: "biome" |
|
| 121 | - | test_name: "Shadcn + No RPC + No TanStack Query + Biome" |
|
| 443 | + | test_name: "Shadcn + No RPC + No TanStack Query + TanStack Router + Biome" |
|
| 122 | 444 | - template: "shadcn" |
|
| 123 | 445 | rpc: true |
|
| 124 | 446 | tanstackQuery: true |
|
| 447 | + | router: "tanstackrouter" |
|
| 125 | 448 | linter: "eslint" |
|
| 126 | - | test_name: "Shadcn + RPC + TanStack Query + ESLint" |
|
| 449 | + | test_name: "Shadcn + RPC + TanStack Query + TanStack Router + ESLint" |
|
| 127 | 450 | - template: "shadcn" |
|
| 128 | 451 | rpc: true |
|
| 129 | 452 | tanstackQuery: true |
|
| 453 | + | router: "tanstackrouter" |
|
| 130 | 454 | linter: "biome" |
|
| 131 | - | test_name: "Shadcn + RPC + TanStack Query + Biome" |
|
| 455 | + | test_name: "Shadcn + RPC + TanStack Query + TanStack Router + Biome" |
|
| 132 | 456 | - template: "shadcn" |
|
| 133 | 457 | rpc: false |
|
| 134 | 458 | tanstackQuery: true |
|
| 459 | + | router: "tanstackrouter" |
|
| 135 | 460 | linter: "eslint" |
|
| 136 | - | test_name: "Shadcn + No RPC + TanStack Query + ESLint" |
|
| 461 | + | test_name: "Shadcn + No RPC + TanStack Query + TanStack Router + ESLint" |
|
| 137 | 462 | - template: "shadcn" |
|
| 138 | 463 | rpc: false |
|
| 139 | 464 | tanstackQuery: true |
|
| 465 | + | router: "tanstackrouter" |
|
| 140 | 466 | linter: "biome" |
|
| 141 | - | test_name: "Shadcn + No RPC + TanStack Query + Biome" |
|
| 467 | + | test_name: "Shadcn + No RPC + TanStack Query + TanStack Router + Biome" |
|
| 142 | 468 | ||
| 143 | 469 | steps: |
|
| 144 | 470 | - name: Checkout repository |
|
| 161 | 487 | echo "Creating project with options:" |
|
| 162 | 488 | echo "Template: ${{ matrix.template }}" |
|
| 163 | 489 | echo "RPC: ${{ matrix.rpc }}" |
|
| 490 | + | echo "TanStack Query: ${{ matrix.tanstackQuery }}" |
|
| 491 | + | echo "Router: ${{ matrix.router }}" |
|
| 164 | 492 | echo "Linter: ${{ matrix.linter }}" |
|
| 493 | + | ||
| 494 | + | # Build the command with conditional flags |
|
| 495 | + | cmd="./dist/index.js test-project-${{ matrix.template }}-${{ matrix.rpc }}-${{ matrix.tanstackQuery }}-${{ matrix.router }}-${{ matrix.linter }} --yes --template ${{ matrix.template }}" |
|
| 165 | 496 | ||
| 166 | 497 | if [ "${{ matrix.rpc }}" = "true" ]; then |
|
| 167 | - | ./dist/index.js test-project-${{ matrix.template }}-${{ matrix.rpc }}-${{ matrix.linter }} \ |
|
| 168 | - | --yes \ |
|
| 169 | - | --template ${{ matrix.template }} \ |
|
| 170 | - | --rpc \ |
|
| 171 | - | --linter ${{ matrix.linter }} |
|
| 172 | - | else |
|
| 173 | - | ./dist/index.js test-project-${{ matrix.template }}-${{ matrix.rpc }}-${{ matrix.linter }} \ |
|
| 174 | - | --yes \ |
|
| 175 | - | --template ${{ matrix.template }} \ |
|
| 176 | - | --linter ${{ matrix.linter }} |
|
| 498 | + | cmd="$cmd --rpc" |
|
| 499 | + | fi |
|
| 500 | + | ||
| 501 | + | if [ "${{ matrix.tanstackQuery }}" = "true" ]; then |
|
| 502 | + | cmd="$cmd --tsquery" |
|
| 503 | + | fi |
|
| 504 | + | ||
| 505 | + | if [ "${{ matrix.router }}" != "none" ]; then |
|
| 506 | + | cmd="$cmd --router ${{ matrix.router }}" |
|
| 177 | 507 | fi |
|
| 508 | + | ||
| 509 | + | cmd="$cmd --linter ${{ matrix.linter }}" |
|
| 510 | + | ||
| 511 | + | echo "Running: $cmd" |
|
| 512 | + | eval $cmd |
|
| 178 | 513 | ||
| 179 | 514 | - name: Install project dependencies |
|
| 180 | 515 | run: | |
|
| 181 | - | cd test-project-${{ matrix.template }}-${{ matrix.rpc }}-${{ matrix.linter }} |
|
| 516 | + | cd test-project-${{ matrix.template }}-${{ matrix.rpc }}-${{ matrix.tanstackQuery }}-${{ matrix.router }}-${{ matrix.linter }} |
|
| 182 | 517 | bun install |
|
| 183 | 518 | ||
| 184 | 519 | - name: Build test project |
|
| 185 | 520 | run: | |
|
| 186 | - | cd test-project-${{ matrix.template }}-${{ matrix.rpc }}-${{ matrix.linter }} |
|
| 521 | + | cd test-project-${{ matrix.template }}-${{ matrix.rpc }}-${{ matrix.tanstackQuery }}-${{ matrix.router }}-${{ matrix.linter }} |
|
| 187 | 522 | bun run build |
|
| 188 | 523 | ||
| 189 | 524 | - name: Verify build outputs |
|
| 190 | 525 | run: | |
|
| 191 | - | cd test-project-${{ matrix.template }}-${{ matrix.rpc }}-${{ matrix.linter }} |
|
| 192 | - | ||
| 526 | + | cd test-project-${{ matrix.template }}-${{ matrix.rpc }}-${{ matrix.tanstackQuery }}-${{ matrix.router }}-${{ matrix.linter }} |
|
| 527 | + | ||
| 193 | 528 | # Check that dist directories exist |
|
| 194 | 529 | if [ ! -d "client/dist" ]; then |
|
| 195 | 530 | echo "❌ Client build failed - dist directory not found" |
|
| 196 | 531 | exit 1 |
|
| 197 | 532 | fi |
|
| 198 | - | ||
| 533 | + | ||
| 199 | 534 | if [ ! -d "server/dist" ]; then |
|
| 200 | 535 | echo "❌ Server build failed - dist directory not found" |
|
| 201 | 536 | exit 1 |
|
| 202 | 537 | fi |
|
| 203 | - | ||
| 538 | + | ||
| 204 | 539 | # Check for expected files |
|
| 205 | 540 | if [ ! -f "client/dist/index.html" ]; then |
|
| 206 | 541 | echo "❌ Client build incomplete - index.html not found" |
|
| 207 | 542 | exit 1 |
|
| 208 | 543 | fi |
|
| 209 | - | ||
| 544 | + | ||
| 210 | 545 | if [ ! -f "server/dist/index.js" ]; then |
|
| 211 | 546 | echo "❌ Server build incomplete - index.js not found" |
|
| 212 | 547 | exit 1 |
|
| 213 | 548 | fi |
|
| 214 | - | ||
| 549 | + | ||
| 215 | 550 | echo "✅ Build verification passed for ${{ matrix.test_name }}" |
|
| 216 | 551 | ||
| 217 | 552 | - name: Run linter on generated project |
|
| 218 | 553 | run: | |
|
| 219 | - | cd test-project-${{ matrix.template }}-${{ matrix.rpc }}-${{ matrix.linter }} |
|
| 220 | - | ||
| 554 | + | cd test-project-${{ matrix.template }}-${{ matrix.rpc }}-${{ matrix.tanstackQuery }}-${{ matrix.router }}-${{ matrix.linter }} |
|
| 555 | + | ||
| 221 | 556 | if [ "${{ matrix.linter }}" = "eslint" ]; then |
|
| 222 | 557 | # Check if ESLint config exists and run it |
|
| 223 | 558 | if [ -f ".eslintrc.json" ] || [ -f ".eslintrc.js" ] || [ -f "eslint.config.js" ]; then |
|
| 235 | 570 | - name: Cleanup test project |
|
| 236 | 571 | if: always() |
|
| 237 | 572 | run: | |
|
| 238 | - | rm -rf test-project-${{ matrix.template }}-${{ matrix.rpc }}-${{ matrix.linter }} |
|
| 573 | + | rm -rf test-project-${{ matrix.template }}-${{ matrix.rpc }}-${{ matrix.tanstackQuery }}-${{ matrix.router }}-${{ matrix.linter }} |
|
| 6 | 6 | import path from "node:path"; |
|
| 7 | 7 | ||
| 8 | 8 | // Define the possible boolean options from ProjectOptions type |
|
| 9 | - | const BOOLEAN_OPTIONS = ["tailwind", "shadcn", "rpc", "tanstackQuery"] as const; |
|
| 9 | + | const BOOLEAN_OPTIONS = [ |
|
| 10 | + | "tailwind", |
|
| 11 | + | "shadcn", |
|
| 12 | + | "rpc", |
|
| 13 | + | "tanstackQuery", |
|
| 14 | + | "reactRouter", |
|
| 15 | + | "tanstackRouter", |
|
| 16 | + | ] as const; |
|
| 17 | + | ||
| 18 | + | // Package dependency rules |
|
| 19 | + | const PACKAGE_DEPENDENCIES: Record<string, string[]> = { |
|
| 20 | + | shadcn: ["tailwind"], // shadcn requires tailwind |
|
| 21 | + | // Add more dependencies here as needed |
|
| 22 | + | // example: somePackage: ["requiredPackage1", "requiredPackage2"] |
|
| 23 | + | }; |
|
| 24 | + | ||
| 25 | + | // Mutually exclusive groups (only one option from each group can be selected) |
|
| 26 | + | const MUTUALLY_EXCLUSIVE_GROUPS: string[][] = [ |
|
| 27 | + | // Add mutually exclusive groups here as needed |
|
| 28 | + | // example: ["option1", "option2", "option3"] |
|
| 29 | + | ["reactRouter", "tanstackRouter"], |
|
| 30 | + | ]; |
|
| 31 | + | ||
| 32 | + | // Check if a combination is valid based on dependencies and mutual exclusivity |
|
| 33 | + | function isValidCombination(combination: Record<string, boolean>): boolean { |
|
| 34 | + | // Skip combinations with no packages selected |
|
| 35 | + | const hasAnyPackage = Object.values(combination).some((value) => value); |
|
| 36 | + | if (!hasAnyPackage) { |
|
| 37 | + | return false; |
|
| 38 | + | } |
|
| 39 | + | ||
| 40 | + | // Skip combinations that only contain shadcn and/or tailwind (they're cloned from repo) |
|
| 41 | + | const enabledPackages = Object.keys(combination).filter( |
|
| 42 | + | (key) => combination[key], |
|
| 43 | + | ); |
|
| 44 | + | const onlyShadcnTailwind = enabledPackages.every( |
|
| 45 | + | (pkg) => pkg === "shadcn" || pkg === "tailwind", |
|
| 46 | + | ); |
|
| 47 | + | if (onlyShadcnTailwind) { |
|
| 48 | + | return false; |
|
| 49 | + | } |
|
| 50 | + | ||
| 51 | + | // Check package dependencies |
|
| 52 | + | for (const [packageName, dependencies] of Object.entries( |
|
| 53 | + | PACKAGE_DEPENDENCIES, |
|
| 54 | + | )) { |
|
| 55 | + | if (combination[packageName]) { |
|
| 56 | + | // If this package is enabled, all its dependencies must also be enabled |
|
| 57 | + | for (const dependency of dependencies) { |
|
| 58 | + | if (!combination[dependency]) { |
|
| 59 | + | return false; |
|
| 60 | + | } |
|
| 61 | + | } |
|
| 62 | + | } |
|
| 63 | + | } |
|
| 64 | + | ||
| 65 | + | // Check mutual exclusivity |
|
| 66 | + | for (const group of MUTUALLY_EXCLUSIVE_GROUPS) { |
|
| 67 | + | const selectedInGroup = group.filter((option) => combination[option]); |
|
| 68 | + | if (selectedInGroup.length > 1) { |
|
| 69 | + | return false; // More than one option selected in mutually exclusive group |
|
| 70 | + | } |
|
| 71 | + | } |
|
| 72 | + | ||
| 73 | + | return true; |
|
| 74 | + | } |
|
| 75 | + | ||
| 76 | + | // Generate all possible combinations of boolean options with filtering |
|
| 77 | + | function generateAllCombinations( |
|
| 78 | + | options: readonly string[], |
|
| 79 | + | ): Array<Record<string, boolean>> { |
|
| 80 | + | const combinations: Array<Record<string, boolean>> = []; |
|
| 81 | + | const totalCombinations = Math.pow(2, options.length); |
|
| 82 | + | ||
| 83 | + | for (let i = 0; i < totalCombinations; i++) { |
|
| 84 | + | const combination: Record<string, boolean> = {}; |
|
| 85 | + | for (let j = 0; j < options.length; j++) { |
|
| 86 | + | combination[options[j]] = Boolean(i & (1 << j)); |
|
| 87 | + | } |
|
| 88 | + | ||
| 89 | + | // Only include valid combinations |
|
| 90 | + | if (isValidCombination(combination)) { |
|
| 91 | + | combinations.push(combination); |
|
| 92 | + | } |
|
| 93 | + | } |
|
| 94 | + | ||
| 95 | + | return combinations; |
|
| 96 | + | } |
|
| 10 | 97 | ||
| 11 | 98 | // Simulate nameGenerator function locally |
|
| 12 | 99 | const nameGenerator = ( |
|
| 30 | 117 | } |
|
| 31 | 118 | return basename; |
|
| 32 | 119 | }; |
|
| 33 | - | ||
| 34 | - | // Generate all possible combinations of boolean options |
|
| 35 | - | function generateAllCombinations( |
|
| 36 | - | options: readonly string[], |
|
| 37 | - | ): Array<Record<string, boolean>> { |
|
| 38 | - | const combinations: Array<Record<string, boolean>> = []; |
|
| 39 | - | const totalCombinations = Math.pow(2, options.length); |
|
| 40 | - | ||
| 41 | - | for (let i = 0; i < totalCombinations; i++) { |
|
| 42 | - | const combination: Record<string, boolean> = {}; |
|
| 43 | - | for (let j = 0; j < options.length; j++) { |
|
| 44 | - | combination[options[j]] = Boolean(i & (1 << j)); |
|
| 45 | - | } |
|
| 46 | - | combinations.push(combination); |
|
| 47 | - | } |
|
| 48 | - | ||
| 49 | - | return combinations; |
|
| 50 | - | } |
|
| 51 | 120 | ||
| 52 | 121 | // Parse installer files to find nameGenerator calls and hardcoded template patterns |
|
| 53 | 122 | // Recursively find all .ts files in installers directory |
|
| 270 | 339 | ||
| 271 | 340 | let result = filename + "-with"; |
|
| 272 | 341 | ||
| 273 | - | // Hardcoded follows specific order: tailwind, shadcn, rpc |
|
| 342 | + | // Hardcoded follows specific order: tailwind, shadcn, rpc, tanstackQuery, then routers |
|
| 274 | 343 | if (possibleOptions.tailwind) result += "-tailwind"; |
|
| 275 | 344 | if (possibleOptions.shadcn) result += "-shadcn"; |
|
| 276 | 345 | if (possibleOptions.rpc) result += "-rpc"; |
|
| 346 | + | if (possibleOptions.tanstackQuery) result += "-tanstackquery"; |
|
| 347 | + | if (possibleOptions.reactRouter) result += "-reactrouter"; |
|
| 277 | 348 | ||
| 278 | 349 | return extension ? `${result}.${extension}` : result; |
|
| 279 | 350 | }; |
|
| 280 | 351 | ||
| 281 | 352 | // Check if template files exist for all combinations |
|
| 282 | 353 | async function checkTemplateFiles() { |
|
| 283 | - | console.log("🔍 Analyzing template patterns in installers...\n"); |
|
| 284 | - | ||
| 285 | 354 | const templateCalls = await parseInstallerFiles(); |
|
| 286 | 355 | ||
| 287 | 356 | if (templateCalls.length === 0) { |
|
| 288 | - | console.log("❌ No template patterns found in installer files!"); |
|
| 289 | 357 | return; |
|
| 290 | 358 | } |
|
| 291 | - | ||
| 292 | - | const extrasDir = path.resolve("src/templates/extras"); |
|
| 293 | - | ||
| 294 | - | for (const call of templateCalls) { |
|
| 295 | - | console.log(`📁 Analyzing: ${call.file} (${call.type})`); |
|
| 296 | - | console.log(` Basename: ${call.basename}`); |
|
| 297 | - | console.log(` Used Options: [${call.usedOptions.join(", ")}]`); |
|
| 298 | - | console.log(` Template Path: ${call.templatePath}`); |
|
| 299 | - | console.log(""); |
|
| 300 | - | ||
| 301 | - | // Generate all possible combinations for the used options |
|
| 302 | - | const allCombinations = generateAllCombinations(call.usedOptions); |
|
| 303 | - | const templateDir = path.join( |
|
| 304 | - | extrasDir, |
|
| 305 | - | call.templatePath.replace(/["']/g, ""), |
|
| 306 | - | call.basename, |
|
| 307 | - | ); |
|
| 308 | - | ||
| 309 | - | console.log( |
|
| 310 | - | ` 📋 All possible template files for ${call.basename} (${call.type}):`, |
|
| 311 | - | ); |
|
| 312 | - | ||
| 313 | - | let foundCount = 0; |
|
| 314 | - | let missingCount = 0; |
|
| 315 | - | ||
| 316 | - | for (const combination of allCombinations) { |
|
| 317 | - | const templateName = |
|
| 318 | - | call.type === "nameGenerator" |
|
| 319 | - | ? nameGenerator(call.basename, combination) |
|
| 320 | - | : hardcodedGenerator(call.basename, combination); |
|
| 321 | - | const fullTemplatePath = path.join(templateDir, templateName); |
|
| 322 | - | ||
| 323 | - | const exists = await fs.pathExists(fullTemplatePath); |
|
| 324 | - | const status = exists ? "✅" : "❌"; |
|
| 325 | - | ||
| 326 | - | if (exists) { |
|
| 327 | - | foundCount++; |
|
| 328 | - | } else { |
|
| 329 | - | missingCount++; |
|
| 330 | - | } |
|
| 331 | - | ||
| 332 | - | // Show combination details |
|
| 333 | - | const enabledOptions = Object.keys(combination) |
|
| 334 | - | .filter((key) => combination[key]) |
|
| 335 | - | .join(", "); |
|
| 336 | - | ||
| 337 | - | console.log( |
|
| 338 | - | ` ${status} ${templateName} ${enabledOptions ? `(${enabledOptions})` : "(no options)"}`, |
|
| 339 | - | ); |
|
| 340 | - | ||
| 341 | - | if (!exists) { |
|
| 342 | - | console.log(` Missing: ${fullTemplatePath}`); |
|
| 343 | - | } |
|
| 344 | - | } |
|
| 345 | - | ||
| 346 | - | console.log(""); |
|
| 347 | - | console.log(` 📊 Summary: ${foundCount} found, ${missingCount} missing`); |
|
| 348 | - | console.log(" " + "=".repeat(50)); |
|
| 349 | - | console.log(""); |
|
| 350 | - | } |
|
| 351 | - | ||
| 352 | - | // Overall statistics |
|
| 353 | - | console.log("🎯 Overall Analysis Complete!"); |
|
| 354 | - | console.log( |
|
| 355 | - | ` Found ${templateCalls.length} template patterns in installers`, |
|
| 356 | - | ); |
|
| 357 | - | console.log( |
|
| 358 | - | ` - ${templateCalls.filter((c) => c.type === "nameGenerator").length} nameGenerator calls`, |
|
| 359 | - | ); |
|
| 360 | - | console.log( |
|
| 361 | - | ` - ${templateCalls.filter((c) => c.type === "hardcoded").length} hardcoded template patterns`, |
|
| 362 | - | ); |
|
| 363 | - | ||
| 364 | - | // Consistency analysis |
|
| 365 | - | console.log(""); |
|
| 366 | - | console.log("! CONSISTENCY ISSUES DETECTED:"); |
|
| 367 | - | console.log( |
|
| 368 | - | " The RPC installer uses hardcoded template names with order: tailwind-shadcn-rpc", |
|
| 369 | - | ); |
|
| 370 | - | console.log( |
|
| 371 | - | " The TanStack Query installer uses nameGenerator with alphabetical order: rpc-shadcn-tailwind-tanstackquery", |
|
| 372 | - | ); |
|
| 373 | - | console.log(" But the actual template files follow the hardcoded pattern!"); |
|
| 374 | - | console.log(""); |
|
| 375 | - | console.log("💡 RECOMMENDATIONS:"); |
|
| 376 | - | console.log( |
|
| 377 | - | " 1. Standardize on nameGenerator for consistency across all installers", |
|
| 378 | - | ); |
|
| 379 | - | console.log( |
|
| 380 | - | " 2. OR rename template files to match nameGenerator's alphabetical sorting", |
|
| 381 | - | ); |
|
| 382 | - | console.log( |
|
| 383 | - | " 3. OR update nameGenerator to use the same order as hardcoded pattern", |
|
| 384 | - | ); |
|
| 385 | - | console.log(""); |
|
| 386 | - | console.log("🔍 MISSING TEMPLATE FILES:"); |
|
| 387 | - | const totalMissing = templateCalls.reduce((acc, call) => { |
|
| 388 | - | const allCombinations = generateAllCombinations(call.usedOptions); |
|
| 389 | - | return ( |
|
| 390 | - | acc + |
|
| 391 | - | allCombinations.filter((combo) => { |
|
| 392 | - | const templateName = |
|
| 393 | - | call.type === "nameGenerator" |
|
| 394 | - | ? nameGenerator(call.basename, combo) |
|
| 395 | - | : hardcodedGenerator(call.basename, combo); |
|
| 396 | - | const templateDir = path.join( |
|
| 397 | - | path.resolve("src/templates/extras"), |
|
| 398 | - | call.templatePath.replace(/["']/g, ""), |
|
| 399 | - | call.basename, |
|
| 400 | - | ); |
|
| 401 | - | const fullTemplatePath = path.join(templateDir, templateName); |
|
| 402 | - | return !require("fs-extra").pathExistsSync(fullTemplatePath); |
|
| 403 | - | }).length |
|
| 404 | - | ); |
|
| 405 | - | }, 0); |
|
| 406 | - | console.log(` Total missing template files: ${totalMissing}`); |
|
| 407 | - | ||
| 408 | - | console.log(""); |
|
| 409 | - | console.log("🛠 COMMANDS TO CREATE MISSING FILES:"); |
|
| 410 | 359 | ||
| 411 | 360 | for (const call of templateCalls) { |
|
| 412 | 361 | const allCombinations = generateAllCombinations(call.usedOptions); |
|
| 415 | 364 | call.templatePath.replace(/["']/g, ""), |
|
| 416 | 365 | call.basename, |
|
| 417 | 366 | ); |
|
| 418 | - | ||
| 419 | - | const missingFiles: string[] = []; |
|
| 420 | 367 | ||
| 421 | 368 | for (const combination of allCombinations) { |
|
| 422 | 369 | const templateName = |
|
| 425 | 372 | : hardcodedGenerator(call.basename, combination); |
|
| 426 | 373 | const fullTemplatePath = path.join(templateDir, templateName); |
|
| 427 | 374 | ||
| 428 | - | const exists = require("fs-extra").pathExistsSync(fullTemplatePath); |
|
| 375 | + | const exists = await fs.pathExists(fullTemplatePath); |
|
| 429 | 376 | if (!exists) { |
|
| 430 | - | missingFiles.push(`touch "${fullTemplatePath}"`); |
|
| 377 | + | console.log(`touch "${fullTemplatePath}"`); |
|
| 431 | 378 | } |
|
| 432 | - | } |
|
| 433 | - | ||
| 434 | - | if (missingFiles.length > 0) { |
|
| 435 | - | console.log(` # Missing files for ${call.basename} (${call.type}):`); |
|
| 436 | - | for (const cmd of missingFiles) { |
|
| 437 | - | console.log(` ${cmd}`); |
|
| 438 | - | } |
|
| 439 | - | console.log(""); |
|
| 440 | 379 | } |
|
| 441 | 380 | } |
|
| 442 | 381 | } |
|
| 28 | 28 | "--tsquery", |
|
| 29 | 29 | "use TanStack Query for data fetching and state management", |
|
| 30 | 30 | ) |
|
| 31 | + | .option( |
|
| 32 | + | "--router <router>", |
|
| 33 | + | "specify a client router (none, reactrouter, tanstackrouter)", |
|
| 34 | + | ) |
|
| 31 | 35 | .option("--linter <linter>", "specify the linter to use (eslint or biome)") |
|
| 32 | 36 | .action(create); |
|
| 33 | 37 |
| 1 | + | import path from "node:path"; |
|
| 2 | + | import fs from "fs-extra"; |
|
| 3 | + | import type { ProjectOptions } from "@/types"; |
|
| 4 | + | import yoctoSpinner from "yocto-spinner"; |
|
| 5 | + | import pc from "picocolors"; |
|
| 6 | + | import { consola } from "consola"; |
|
| 7 | + | import { addPackageDependency } from "@/utils/add-package-dependency"; |
|
| 8 | + | import { EXTRAS_DIR } from "@/utils"; |
|
| 9 | + | import { nameGenerator } from "@/utils/name-generator"; |
|
| 10 | + | ||
| 11 | + | export const reactRouterInstaller = async ( |
|
| 12 | + | options: Required<ProjectOptions>, |
|
| 13 | + | ): Promise<boolean> => { |
|
| 14 | + | const spinner = yoctoSpinner({ |
|
| 15 | + | text: "Setting up React Router...", |
|
| 16 | + | }).start(); |
|
| 17 | + | ||
| 18 | + | try { |
|
| 19 | + | const { projectName, rpc, shadcn, tailwind, tanstackQuery } = options; |
|
| 20 | + | ||
| 21 | + | const projectPath = path.resolve(process.cwd(), projectName); |
|
| 22 | + | spinner.text = "Installing React Router..."; |
|
| 23 | + | await addPackageDependency({ |
|
| 24 | + | dependencies: ["react-router"], |
|
| 25 | + | target: "client", |
|
| 26 | + | projectName, |
|
| 27 | + | }); |
|
| 28 | + | ||
| 29 | + | const appTsxTemplate = nameGenerator("App.tsx", { |
|
| 30 | + | reactRouter: true, |
|
| 31 | + | }); |
|
| 32 | + | ||
| 33 | + | const appTsxSrc = path.join( |
|
| 34 | + | EXTRAS_DIR, |
|
| 35 | + | "client", |
|
| 36 | + | "src", |
|
| 37 | + | "App.tsx", |
|
| 38 | + | appTsxTemplate, |
|
| 39 | + | ); |
|
| 40 | + | const appTsxTarget = path.join(projectPath, "client", "src", "App.tsx"); |
|
| 41 | + | fs.copySync(appTsxSrc, appTsxTarget); |
|
| 42 | + | ||
| 43 | + | const homeTsxTemplate = nameGenerator("Home.tsx", { |
|
| 44 | + | rpc, |
|
| 45 | + | shadcn, |
|
| 46 | + | tailwind, |
|
| 47 | + | tanstackQuery, |
|
| 48 | + | }); |
|
| 49 | + | ||
| 50 | + | const homeTsxSrc = path.join( |
|
| 51 | + | EXTRAS_DIR, |
|
| 52 | + | "client", |
|
| 53 | + | "src", |
|
| 54 | + | "components", |
|
| 55 | + | "Home.tsx", |
|
| 56 | + | homeTsxTemplate, |
|
| 57 | + | ); |
|
| 58 | + | const homeTsxTarget = path.join( |
|
| 59 | + | projectPath, |
|
| 60 | + | "client", |
|
| 61 | + | "src", |
|
| 62 | + | "components", |
|
| 63 | + | "Home.tsx", |
|
| 64 | + | ); |
|
| 65 | + | fs.copySync(homeTsxSrc, homeTsxTarget); |
|
| 66 | + | ||
| 67 | + | spinner.success("React Router setup completed"); |
|
| 68 | + | return true; |
|
| 69 | + | } catch (err: unknown) { |
|
| 70 | + | spinner.error("Failed to set up React Router"); |
|
| 71 | + | if (err instanceof Error) { |
|
| 72 | + | consola.error(pc.red("Error:"), err.message); |
|
| 73 | + | } else { |
|
| 74 | + | consola.error(pc.red("Error: Unknown error")); |
|
| 75 | + | } |
|
| 76 | + | return false; |
|
| 77 | + | } |
|
| 78 | + | }; |
| 1 | + | import path from "node:path"; |
|
| 2 | + | import fs from "fs-extra"; |
|
| 3 | + | import type { ProjectOptions } from "@/types"; |
|
| 4 | + | import yoctoSpinner from "yocto-spinner"; |
|
| 5 | + | import pc from "picocolors"; |
|
| 6 | + | import { consola } from "consola"; |
|
| 7 | + | import { addPackageDependency } from "@/utils/add-package-dependency"; |
|
| 8 | + | import { EXTRAS_DIR } from "@/utils"; |
|
| 9 | + | import { nameGenerator } from "@/utils/name-generator"; |
|
| 10 | + | import { execa } from "execa"; |
|
| 11 | + | ||
| 12 | + | export const tanstackRouterInstaller = async ( |
|
| 13 | + | options: Required<ProjectOptions>, |
|
| 14 | + | ): Promise<boolean> => { |
|
| 15 | + | const spinner = yoctoSpinner({ |
|
| 16 | + | text: "Setting up TanStack Router...", |
|
| 17 | + | }).start(); |
|
| 18 | + | ||
| 19 | + | try { |
|
| 20 | + | const { projectName, rpc, shadcn, tailwind, tanstackQuery } = options; |
|
| 21 | + | ||
| 22 | + | const projectPath = path.resolve(process.cwd(), projectName); |
|
| 23 | + | spinner.text = "Installing TanStack Router..."; |
|
| 24 | + | await addPackageDependency({ |
|
| 25 | + | dependencies: [ |
|
| 26 | + | "@tanstack/react-router", |
|
| 27 | + | "@tanstack/react-router-devtools", |
|
| 28 | + | ], |
|
| 29 | + | target: "client", |
|
| 30 | + | projectName, |
|
| 31 | + | }); |
|
| 32 | + | ||
| 33 | + | await addPackageDependency({ |
|
| 34 | + | dependencies: ["@tanstack/router-plugin"], |
|
| 35 | + | devMode: true, |
|
| 36 | + | target: "client", |
|
| 37 | + | projectName, |
|
| 38 | + | }); |
|
| 39 | + | ||
| 40 | + | const viteConfigTemplate = nameGenerator("vite.config.ts", { |
|
| 41 | + | tailwind, |
|
| 42 | + | shadcn, |
|
| 43 | + | tanstackRouter: true, |
|
| 44 | + | }); |
|
| 45 | + | const viteConfigSrc = path.join( |
|
| 46 | + | EXTRAS_DIR, |
|
| 47 | + | "client", |
|
| 48 | + | "vite.config.ts", |
|
| 49 | + | viteConfigTemplate, |
|
| 50 | + | ); |
|
| 51 | + | const viteConfigTarget = path.join(projectPath, "client", "vite.config.ts"); |
|
| 52 | + | fs.copySync(viteConfigSrc, viteConfigTarget); |
|
| 53 | + | ||
| 54 | + | const rootTsxSrc = path.join( |
|
| 55 | + | EXTRAS_DIR, |
|
| 56 | + | "client", |
|
| 57 | + | "src", |
|
| 58 | + | "routes", |
|
| 59 | + | "__root.tsx", |
|
| 60 | + | ); |
|
| 61 | + | const rootTsxTarget = path.join( |
|
| 62 | + | projectPath, |
|
| 63 | + | "client", |
|
| 64 | + | "src", |
|
| 65 | + | "routes", |
|
| 66 | + | "__root.tsx", |
|
| 67 | + | ); |
|
| 68 | + | fs.copySync(rootTsxSrc, rootTsxTarget); |
|
| 69 | + | ||
| 70 | + | const indexTsxSrc = path.join( |
|
| 71 | + | EXTRAS_DIR, |
|
| 72 | + | "client", |
|
| 73 | + | "src", |
|
| 74 | + | "routes", |
|
| 75 | + | "index.tsx", |
|
| 76 | + | nameGenerator("index.tsx", { tanstackQuery, tailwind, shadcn, rpc }), |
|
| 77 | + | ); |
|
| 78 | + | const indexTsxTarget = path.join( |
|
| 79 | + | projectPath, |
|
| 80 | + | "client", |
|
| 81 | + | "src", |
|
| 82 | + | "routes", |
|
| 83 | + | "index.tsx", |
|
| 84 | + | ); |
|
| 85 | + | fs.copySync(indexTsxSrc, indexTsxTarget); |
|
| 86 | + | ||
| 87 | + | const mainTsxSrc = path.join( |
|
| 88 | + | EXTRAS_DIR, |
|
| 89 | + | "client", |
|
| 90 | + | "src", |
|
| 91 | + | "main.tsx", |
|
| 92 | + | nameGenerator("main.tsx", { tanstackQuery, tanstackRouter: true }), |
|
| 93 | + | ); |
|
| 94 | + | const mainTsxTarget = path.join(projectPath, "client", "src", "main.tsx"); |
|
| 95 | + | fs.copySync(mainTsxSrc, mainTsxTarget); |
|
| 96 | + | ||
| 97 | + | const appTsxTarget = path.join(projectPath, "client", "src", "App.tsx"); |
|
| 98 | + | fs.remove(appTsxTarget); |
|
| 99 | + | ||
| 100 | + | spinner.text = "Generating TanStack Route Tree..."; |
|
| 101 | + | ||
| 102 | + | // await execa("vite", ["--config", "vite.config.ts", "--force"], { |
|
| 103 | + | // cwd: path.join(projectPath, "client"), |
|
| 104 | + | // }); |
|
| 105 | + | // |
|
| 106 | + | await execa("bunx", ["vite", "build"], { |
|
| 107 | + | cwd: path.join(projectPath, "client"), |
|
| 108 | + | }); |
|
| 109 | + | ||
| 110 | + | await execa("tsc", ["-b"], { |
|
| 111 | + | cwd: path.join(projectPath, "client"), |
|
| 112 | + | }); |
|
| 113 | + | ||
| 114 | + | spinner.success("TanStack Router setup completed"); |
|
| 115 | + | return true; |
|
| 116 | + | } catch (err: unknown) { |
|
| 117 | + | spinner.error("Failed to set up TanStack Router"); |
|
| 118 | + | if (err instanceof Error) { |
|
| 119 | + | consola.error(pc.red("Error:"), err.message); |
|
| 120 | + | } else { |
|
| 121 | + | consola.error(pc.red("Error: Unknown error")); |
|
| 122 | + | } |
|
| 123 | + | return false; |
|
| 124 | + | } |
|
| 125 | + | }; |
| 3 | 3 | import path from "node:path"; |
|
| 4 | 4 | import { tanstackQueryInstaller } from "@/installers/tanstack-query"; |
|
| 5 | 5 | import { rpcInstaller } from "@/installers/rpc"; |
|
| 6 | + | import { reactRouterInstaller } from "@/installers/react-router"; |
|
| 7 | + | import { tanstackRouterInstaller } from "@/installers/tanstack-router"; |
|
| 6 | 8 | ||
| 7 | 9 | export async function installPackages( |
|
| 8 | 10 | options: Required<ProjectOptions>, |
|
| 9 | 11 | ): Promise<boolean> { |
|
| 10 | - | const { projectName, rpc, linter, tanstackQuery } = options; |
|
| 12 | + | const { projectName, rpc, router, linter, tanstackQuery } = options; |
|
| 11 | 13 | ||
| 12 | 14 | const projectPath = path.resolve(process.cwd(), projectName); |
|
| 13 | 15 | ||
| 21 | 23 | ||
| 22 | 24 | if (tanstackQuery) { |
|
| 23 | 25 | await tanstackQueryInstaller(options); |
|
| 26 | + | } |
|
| 27 | + | ||
| 28 | + | if (router !== "none") { |
|
| 29 | + | switch (router) { |
|
| 30 | + | case "reactrouter": { |
|
| 31 | + | await reactRouterInstaller(options); |
|
| 32 | + | break; |
|
| 33 | + | } |
|
| 34 | + | case "tanstackrouter": { |
|
| 35 | + | await tanstackRouterInstaller(options); |
|
| 36 | + | break; |
|
| 37 | + | } |
|
| 38 | + | } |
|
| 24 | 39 | } |
|
| 25 | 40 | ||
| 26 | 41 | return false; |
|
| 93 | 93 | linter = linterResponse as "eslint" | "biome"; |
|
| 94 | 94 | } |
|
| 95 | 95 | ||
| 96 | + | let router = options.router; |
|
| 97 | + | ||
| 98 | + | if (!options.yes && !options.router) { |
|
| 99 | + | const { data: routerResponse, error } = await tryCatch( |
|
| 100 | + | consola.prompt("Select a client router:", { |
|
| 101 | + | type: "select", |
|
| 102 | + | options: [ |
|
| 103 | + | { label: "None (default)", value: "none" }, |
|
| 104 | + | { label: "React Router", value: "reactrouter" }, |
|
| 105 | + | { label: "TanStack Router", value: "tanstackrouter" }, |
|
| 106 | + | ], |
|
| 107 | + | initial: "none", |
|
| 108 | + | cancel: "reject", |
|
| 109 | + | }), |
|
| 110 | + | ); |
|
| 111 | + | ||
| 112 | + | if (error) { |
|
| 113 | + | console.log(pc.yellow("Project creation cancelled.")); |
|
| 114 | + | process.exit(1); |
|
| 115 | + | } |
|
| 116 | + | ||
| 117 | + | router = routerResponse as "none" | "reactrouter" | "tanstackrouter"; |
|
| 118 | + | } |
|
| 119 | + | ||
| 96 | 120 | let useTanstackQuery = options.tanstackQuery; |
|
| 97 | 121 | ||
| 98 | 122 | if (!options.yes && !options.tanstackQuery) { |
|
| 122 | 146 | shadcn: templateChoice === "shadcn", |
|
| 123 | 147 | rpc: useRpc, |
|
| 124 | 148 | linter, |
|
| 149 | + | router, |
|
| 125 | 150 | tanstackQuery: useTanstackQuery, |
|
| 126 | 151 | }; |
|
| 127 | 152 | } |
|
| 1 | + | import { BrowserRouter, Routes, Route } from "react-router"; |
|
| 2 | + | import Home from "./components/Home"; |
|
| 3 | + | ||
| 4 | + | function App() { |
|
| 5 | + | return ( |
|
| 6 | + | <BrowserRouter> |
|
| 7 | + | <Routes> |
|
| 8 | + | <Route path="/" element={<Home />} /> |
|
| 9 | + | </Routes> |
|
| 10 | + | </BrowserRouter> |
|
| 11 | + | ); |
|
| 12 | + | } |
|
| 13 | + | ||
| 14 | + | export default App; |
| 1 | + | import { useState } from "react"; |
|
| 2 | + | import beaver from "@/assets/beaver.svg"; |
|
| 3 | + | import { Button } from "@/components/ui/button"; |
|
| 4 | + | import { hcWithType } from "server/dist/client"; |
|
| 5 | + | import { useMutation } from "@tanstack/react-query"; |
|
| 6 | + | ||
| 7 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 8 | + | ||
| 9 | + | const client = hcWithType(SERVER_URL); |
|
| 10 | + | ||
| 11 | + | type ResponseType = Awaited<ReturnType<typeof client.hello.$get>>; |
|
| 12 | + | ||
| 13 | + | function Home() { |
|
| 14 | + | const [data, setData] = useState< |
|
| 15 | + | Awaited<ReturnType<ResponseType["json"]>> | undefined |
|
| 16 | + | >(); |
|
| 17 | + | ||
| 18 | + | const { mutate: sendRequest } = useMutation({ |
|
| 19 | + | mutationFn: async () => { |
|
| 20 | + | try { |
|
| 21 | + | const res = await client.hello.$get(); |
|
| 22 | + | if (!res.ok) { |
|
| 23 | + | console.log("Error fetching data"); |
|
| 24 | + | return; |
|
| 25 | + | } |
|
| 26 | + | const data = await res.json(); |
|
| 27 | + | setData(data); |
|
| 28 | + | } catch (error) { |
|
| 29 | + | console.log(error); |
|
| 30 | + | } |
|
| 31 | + | }, |
|
| 32 | + | }); |
|
| 33 | + | ||
| 34 | + | return ( |
|
| 35 | + | <div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen"> |
|
| 36 | + | <a |
|
| 37 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 38 | + | target="_blank" |
|
| 39 | + | rel="noopener" |
|
| 40 | + | > |
|
| 41 | + | <img |
|
| 42 | + | src={beaver} |
|
| 43 | + | className="w-16 h-16 cursor-pointer" |
|
| 44 | + | alt="beaver logo" |
|
| 45 | + | /> |
|
| 46 | + | </a> |
|
| 47 | + | <h1 className="text-5xl font-black">bhvr</h1> |
|
| 48 | + | <h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2> |
|
| 49 | + | <p>A typesafe fullstack monorepo</p> |
|
| 50 | + | <div className="flex items-center gap-4"> |
|
| 51 | + | <Button onClick={() => sendRequest()}>Call API</Button> |
|
| 52 | + | <Button variant="secondary" asChild> |
|
| 53 | + | <a target="_blank" href="https://bhvr.dev" rel="noopener"> |
|
| 54 | + | Docs |
|
| 55 | + | </a> |
|
| 56 | + | </Button> |
|
| 57 | + | </div> |
|
| 58 | + | {data && ( |
|
| 59 | + | <pre className="bg-gray-100 p-4 rounded-md"> |
|
| 60 | + | <code> |
|
| 61 | + | Message: {data.message} <br /> |
|
| 62 | + | Success: {data.success.toString()} |
|
| 63 | + | </code> |
|
| 64 | + | </pre> |
|
| 65 | + | )} |
|
| 66 | + | </div> |
|
| 67 | + | ); |
|
| 68 | + | } |
|
| 69 | + | ||
| 70 | + | export default Home; |
| 1 | + | import { useState } from "react"; |
|
| 2 | + | import beaver from "@/assets/beaver.svg"; |
|
| 3 | + | import { Button } from "@/components/ui/button"; |
|
| 4 | + | import { hcWithType } from "server/dist/client"; |
|
| 5 | + | ||
| 6 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 7 | + | ||
| 8 | + | const client = hcWithType(SERVER_URL); |
|
| 9 | + | ||
| 10 | + | type ResponseType = Awaited<ReturnType<typeof client.hello.$get>>; |
|
| 11 | + | ||
| 12 | + | function Home() { |
|
| 13 | + | const [data, setData] = useState< |
|
| 14 | + | Awaited<ReturnType<ResponseType["json"]>> | undefined |
|
| 15 | + | >(); |
|
| 16 | + | ||
| 17 | + | async function sendRequest() { |
|
| 18 | + | try { |
|
| 19 | + | const res = await client.hello.$get(); |
|
| 20 | + | if (!res.ok) { |
|
| 21 | + | console.log("Error fetching data"); |
|
| 22 | + | return; |
|
| 23 | + | } |
|
| 24 | + | const data = await res.json(); |
|
| 25 | + | setData(data); |
|
| 26 | + | } catch (error) { |
|
| 27 | + | console.log(error); |
|
| 28 | + | } |
|
| 29 | + | } |
|
| 30 | + | ||
| 31 | + | return ( |
|
| 32 | + | <div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen"> |
|
| 33 | + | <a |
|
| 34 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 35 | + | target="_blank" |
|
| 36 | + | rel="noopener" |
|
| 37 | + | > |
|
| 38 | + | <img |
|
| 39 | + | src={beaver} |
|
| 40 | + | className="w-16 h-16 cursor-pointer" |
|
| 41 | + | alt="beaver logo" |
|
| 42 | + | /> |
|
| 43 | + | </a> |
|
| 44 | + | <h1 className="text-5xl font-black">bhvr</h1> |
|
| 45 | + | <h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2> |
|
| 46 | + | <p>A typesafe fullstack monorepo</p> |
|
| 47 | + | <div className="flex items-center gap-4"> |
|
| 48 | + | <Button onClick={sendRequest}>Call API</Button> |
|
| 49 | + | <Button variant="secondary" asChild> |
|
| 50 | + | <a target="_blank" href="https://bhvr.dev" rel="noopener"> |
|
| 51 | + | Docs |
|
| 52 | + | </a> |
|
| 53 | + | </Button> |
|
| 54 | + | </div> |
|
| 55 | + | {data && ( |
|
| 56 | + | <pre className="bg-gray-100 p-4 rounded-md"> |
|
| 57 | + | <code> |
|
| 58 | + | Message: {data.message} <br /> |
|
| 59 | + | Success: {data.success.toString()} |
|
| 60 | + | </code> |
|
| 61 | + | </pre> |
|
| 62 | + | )} |
|
| 63 | + | </div> |
|
| 64 | + | ); |
|
| 65 | + | } |
|
| 66 | + | ||
| 67 | + | export default Home; |
| 1 | + | import { useState } from "react"; |
|
| 2 | + | import beaver from "../assets/beaver.svg"; |
|
| 3 | + | import { hcWithType } from "server/dist/client"; |
|
| 4 | + | import { useMutation } from "@tanstack/react-query"; |
|
| 5 | + | ||
| 6 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 7 | + | ||
| 8 | + | type ResponseType = Awaited<ReturnType<typeof client.hello.$get>>; |
|
| 9 | + | ||
| 10 | + | const client = hcWithType(SERVER_URL); |
|
| 11 | + | ||
| 12 | + | function Home() { |
|
| 13 | + | const [data, setData] = useState< |
|
| 14 | + | Awaited<ReturnType<ResponseType["json"]>> | undefined |
|
| 15 | + | >(); |
|
| 16 | + | ||
| 17 | + | const { mutate: sendRequest } = useMutation({ |
|
| 18 | + | mutationFn: async () => { |
|
| 19 | + | try { |
|
| 20 | + | const res = await client.hello.$get(); |
|
| 21 | + | if (!res.ok) { |
|
| 22 | + | console.log("Error fetching data"); |
|
| 23 | + | return; |
|
| 24 | + | } |
|
| 25 | + | const data = await res.json(); |
|
| 26 | + | setData(data); |
|
| 27 | + | } catch (error) { |
|
| 28 | + | console.log(error); |
|
| 29 | + | } |
|
| 30 | + | }, |
|
| 31 | + | }); |
|
| 32 | + | ||
| 33 | + | return ( |
|
| 34 | + | <div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen"> |
|
| 35 | + | <a |
|
| 36 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 37 | + | target="_blank" |
|
| 38 | + | rel="noopener" |
|
| 39 | + | > |
|
| 40 | + | <img |
|
| 41 | + | src={beaver} |
|
| 42 | + | className="w-16 h-16 cursor-pointer" |
|
| 43 | + | alt="beaver logo" |
|
| 44 | + | /> |
|
| 45 | + | </a> |
|
| 46 | + | <h1 className="text-5xl font-black">bhvr</h1> |
|
| 47 | + | <h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2> |
|
| 48 | + | <p>A typesafe fullstack monorepo</p> |
|
| 49 | + | <div className="flex items-center gap-4"> |
|
| 50 | + | <button |
|
| 51 | + | type="button" |
|
| 52 | + | onClick={() => sendRequest()} |
|
| 53 | + | className="bg-black text-white px-2.5 py-1.5 rounded-md" |
|
| 54 | + | > |
|
| 55 | + | Call API |
|
| 56 | + | </button> |
|
| 57 | + | <a |
|
| 58 | + | target="_blank" |
|
| 59 | + | href="https://bhvr.dev" |
|
| 60 | + | className="border-1 border-black text-black px-2.5 py-1.5 rounded-md" |
|
| 61 | + | rel="noopener" |
|
| 62 | + | > |
|
| 63 | + | Docs |
|
| 64 | + | </a> |
|
| 65 | + | </div> |
|
| 66 | + | {data && ( |
|
| 67 | + | <pre className="bg-gray-100 p-4 rounded-md"> |
|
| 68 | + | <code> |
|
| 69 | + | Message: {data.message} <br /> |
|
| 70 | + | Success: {data.success.toString()} |
|
| 71 | + | </code> |
|
| 72 | + | </pre> |
|
| 73 | + | )} |
|
| 74 | + | </div> |
|
| 75 | + | ); |
|
| 76 | + | } |
|
| 77 | + | ||
| 78 | + | export default Home; |
| 1 | + | import { useState } from "react"; |
|
| 2 | + | import beaver from "../assets/beaver.svg"; |
|
| 3 | + | import { hcWithType } from "server/dist/client"; |
|
| 4 | + | ||
| 5 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 6 | + | ||
| 7 | + | type ResponseType = Awaited<ReturnType<typeof client.hello.$get>>; |
|
| 8 | + | ||
| 9 | + | const client = hcWithType(SERVER_URL); |
|
| 10 | + | ||
| 11 | + | function Home() { |
|
| 12 | + | const [data, setData] = useState< |
|
| 13 | + | Awaited<ReturnType<ResponseType["json"]>> | undefined |
|
| 14 | + | >(); |
|
| 15 | + | ||
| 16 | + | async function sendRequest() { |
|
| 17 | + | try { |
|
| 18 | + | const res = await client.hello.$get(); |
|
| 19 | + | if (!res.ok) { |
|
| 20 | + | console.log("Error fetching data"); |
|
| 21 | + | return; |
|
| 22 | + | } |
|
| 23 | + | const data = await res.json(); |
|
| 24 | + | setData(data); |
|
| 25 | + | } catch (error) { |
|
| 26 | + | console.log(error); |
|
| 27 | + | } |
|
| 28 | + | } |
|
| 29 | + | ||
| 30 | + | return ( |
|
| 31 | + | <div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen"> |
|
| 32 | + | <a |
|
| 33 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 34 | + | target="_blank" |
|
| 35 | + | rel="noopener" |
|
| 36 | + | > |
|
| 37 | + | <img |
|
| 38 | + | src={beaver} |
|
| 39 | + | className="w-16 h-16 cursor-pointer" |
|
| 40 | + | alt="beaver logo" |
|
| 41 | + | /> |
|
| 42 | + | </a> |
|
| 43 | + | <h1 className="text-5xl font-black">bhvr</h1> |
|
| 44 | + | <h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2> |
|
| 45 | + | <p>A typesafe fullstack monorepo</p> |
|
| 46 | + | <div className="flex items-center gap-4"> |
|
| 47 | + | <button |
|
| 48 | + | type="button" |
|
| 49 | + | onClick={sendRequest} |
|
| 50 | + | className="bg-black text-white px-2.5 py-1.5 rounded-md" |
|
| 51 | + | > |
|
| 52 | + | Call API |
|
| 53 | + | </button> |
|
| 54 | + | <a |
|
| 55 | + | target="_blank" |
|
| 56 | + | href="https://bhvr.dev" |
|
| 57 | + | className="border-1 border-black text-black px-2.5 py-1.5 rounded-md" |
|
| 58 | + | rel="noopener" |
|
| 59 | + | > |
|
| 60 | + | Docs |
|
| 61 | + | </a> |
|
| 62 | + | </div> |
|
| 63 | + | {data && ( |
|
| 64 | + | <pre className="bg-gray-100 p-4 rounded-md"> |
|
| 65 | + | <code> |
|
| 66 | + | Message: {data.message} <br /> |
|
| 67 | + | Success: {data.success.toString()} |
|
| 68 | + | </code> |
|
| 69 | + | </pre> |
|
| 70 | + | )} |
|
| 71 | + | </div> |
|
| 72 | + | ); |
|
| 73 | + | } |
|
| 74 | + | ||
| 75 | + | export default Home; |
| 1 | + | import { useState } from "react"; |
|
| 2 | + | import beaver from "../assets/beaver.svg"; |
|
| 3 | + | import { hcWithType } from "server/dist/client"; |
|
| 4 | + | import { useMutation } from "@tanstack/react-query"; |
|
| 5 | + | import "../App.css"; |
|
| 6 | + | ||
| 7 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 8 | + | ||
| 9 | + | const client = hcWithType(SERVER_URL); |
|
| 10 | + | ||
| 11 | + | type ResponseType = Awaited<ReturnType<typeof client.hello.$get>>; |
|
| 12 | + | ||
| 13 | + | function Home() { |
|
| 14 | + | const [data, setData] = useState< |
|
| 15 | + | Awaited<ReturnType<ResponseType["json"]>> | undefined |
|
| 16 | + | >(); |
|
| 17 | + | ||
| 18 | + | const { mutate: sendRequest } = useMutation({ |
|
| 19 | + | mutationFn: async () => { |
|
| 20 | + | try { |
|
| 21 | + | const res = await client.hello.$get(); |
|
| 22 | + | if (!res.ok) { |
|
| 23 | + | console.log("Error fetching data"); |
|
| 24 | + | return; |
|
| 25 | + | } |
|
| 26 | + | const data = await res.json(); |
|
| 27 | + | setData(data); |
|
| 28 | + | } catch (error) { |
|
| 29 | + | console.log(error); |
|
| 30 | + | } |
|
| 31 | + | }, |
|
| 32 | + | }); |
|
| 33 | + | ||
| 34 | + | return ( |
|
| 35 | + | <> |
|
| 36 | + | <div> |
|
| 37 | + | <a |
|
| 38 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 39 | + | target="_blank" |
|
| 40 | + | rel="noopener" |
|
| 41 | + | > |
|
| 42 | + | <img src={beaver} className="logo" alt="beaver logo" /> |
|
| 43 | + | </a> |
|
| 44 | + | </div> |
|
| 45 | + | <h1>bhvr</h1> |
|
| 46 | + | <h2>Bun + Hono + Vite + React</h2> |
|
| 47 | + | <p>A typesafe fullstack monorepo</p> |
|
| 48 | + | <div className="card"> |
|
| 49 | + | <div className="button-container"> |
|
| 50 | + | <button type="button" onClick={() => sendRequest()}> |
|
| 51 | + | Call API |
|
| 52 | + | </button> |
|
| 53 | + | <a |
|
| 54 | + | className="docs-link" |
|
| 55 | + | target="_blank" |
|
| 56 | + | href="https://bhvr.dev" |
|
| 57 | + | rel="noopener" |
|
| 58 | + | > |
|
| 59 | + | Docs |
|
| 60 | + | </a> |
|
| 61 | + | </div> |
|
| 62 | + | {data && ( |
|
| 63 | + | <pre className="response"> |
|
| 64 | + | <code> |
|
| 65 | + | Message: {data.message} <br /> |
|
| 66 | + | Success: {data.success.toString()} |
|
| 67 | + | </code> |
|
| 68 | + | </pre> |
|
| 69 | + | )} |
|
| 70 | + | </div> |
|
| 71 | + | </> |
|
| 72 | + | ); |
|
| 73 | + | } |
|
| 74 | + | ||
| 75 | + | export default Home; |
| 1 | + | import { useState } from "react"; |
|
| 2 | + | import beaver from "../assets/beaver.svg"; |
|
| 3 | + | import { hcWithType } from "server/dist/client"; |
|
| 4 | + | import "../App.css"; |
|
| 5 | + | ||
| 6 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 7 | + | ||
| 8 | + | const client = hcWithType(SERVER_URL); |
|
| 9 | + | ||
| 10 | + | type ResponseType = Awaited<ReturnType<typeof client.hello.$get>>; |
|
| 11 | + | ||
| 12 | + | function Home() { |
|
| 13 | + | const [data, setData] = useState< |
|
| 14 | + | Awaited<ReturnType<ResponseType["json"]>> | undefined |
|
| 15 | + | >(); |
|
| 16 | + | ||
| 17 | + | async function sendRequest() { |
|
| 18 | + | try { |
|
| 19 | + | const res = await client.hello.$get(); |
|
| 20 | + | if (!res.ok) { |
|
| 21 | + | console.log("Error fetching data"); |
|
| 22 | + | return; |
|
| 23 | + | } |
|
| 24 | + | const data = await res.json(); |
|
| 25 | + | setData(data); |
|
| 26 | + | } catch (error) { |
|
| 27 | + | console.log(error); |
|
| 28 | + | } |
|
| 29 | + | } |
|
| 30 | + | ||
| 31 | + | return ( |
|
| 32 | + | <> |
|
| 33 | + | <div> |
|
| 34 | + | <a |
|
| 35 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 36 | + | target="_blank" |
|
| 37 | + | rel="noopener" |
|
| 38 | + | > |
|
| 39 | + | <img src={beaver} className="logo" alt="beaver logo" /> |
|
| 40 | + | </a> |
|
| 41 | + | </div> |
|
| 42 | + | <h1>bhvr</h1> |
|
| 43 | + | <h2>Bun + Hono + Vite + React</h2> |
|
| 44 | + | <p>A typesafe fullstack monorepo</p> |
|
| 45 | + | <div className="card"> |
|
| 46 | + | <div className="button-container"> |
|
| 47 | + | <button type="button" onClick={sendRequest}> |
|
| 48 | + | Call API |
|
| 49 | + | </button> |
|
| 50 | + | <a |
|
| 51 | + | className="docs-link" |
|
| 52 | + | target="_blank" |
|
| 53 | + | href="https://bhvr.dev" |
|
| 54 | + | rel="noopener" |
|
| 55 | + | > |
|
| 56 | + | Docs |
|
| 57 | + | </a> |
|
| 58 | + | </div> |
|
| 59 | + | {data && ( |
|
| 60 | + | <pre className="response"> |
|
| 61 | + | <code> |
|
| 62 | + | Message: {data.message} <br /> |
|
| 63 | + | Success: {data.success.toString()} |
|
| 64 | + | </code> |
|
| 65 | + | </pre> |
|
| 66 | + | )} |
|
| 67 | + | </div> |
|
| 68 | + | </> |
|
| 69 | + | ); |
|
| 70 | + | } |
|
| 71 | + | ||
| 72 | + | export default Home; |
| 1 | + | import { useState } from "react"; |
|
| 2 | + | import beaver from "@/assets/beaver.svg"; |
|
| 3 | + | import type { ApiResponse } from "shared"; |
|
| 4 | + | import { Button } from "@/components/ui/button"; |
|
| 5 | + | import { useMutation } from "@tanstack/react-query"; |
|
| 6 | + | ||
| 7 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 8 | + | ||
| 9 | + | function Home() { |
|
| 10 | + | const [data, setData] = useState<ApiResponse | undefined>(); |
|
| 11 | + | ||
| 12 | + | const { mutate: sendRequest } = useMutation({ |
|
| 13 | + | mutationFn: async () => { |
|
| 14 | + | try { |
|
| 15 | + | const req = await fetch(`${SERVER_URL}/hello`); |
|
| 16 | + | const res: ApiResponse = await req.json(); |
|
| 17 | + | setData(res); |
|
| 18 | + | } catch (error) { |
|
| 19 | + | console.log(error); |
|
| 20 | + | } |
|
| 21 | + | }, |
|
| 22 | + | }); |
|
| 23 | + | ||
| 24 | + | return ( |
|
| 25 | + | <div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen"> |
|
| 26 | + | <a |
|
| 27 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 28 | + | target="_blank" |
|
| 29 | + | rel="noopener" |
|
| 30 | + | > |
|
| 31 | + | <img |
|
| 32 | + | src={beaver} |
|
| 33 | + | className="w-16 h-16 cursor-pointer" |
|
| 34 | + | alt="beaver logo" |
|
| 35 | + | /> |
|
| 36 | + | </a> |
|
| 37 | + | <h1 className="text-5xl font-black">bhvr</h1> |
|
| 38 | + | <h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2> |
|
| 39 | + | <p>A typesafe fullstack monorepo</p> |
|
| 40 | + | <div className="flex items-center gap-4"> |
|
| 41 | + | <Button onClick={() => sendRequest()}>Call API</Button> |
|
| 42 | + | <Button variant="secondary" asChild> |
|
| 43 | + | <a target="_blank" href="https://bhvr.dev" rel="noopener"> |
|
| 44 | + | Docs |
|
| 45 | + | </a> |
|
| 46 | + | </Button> |
|
| 47 | + | </div> |
|
| 48 | + | {data && ( |
|
| 49 | + | <pre className="bg-gray-100 p-4 rounded-md"> |
|
| 50 | + | <code> |
|
| 51 | + | Message: {data.message} <br /> |
|
| 52 | + | Success: {data.success.toString()} |
|
| 53 | + | </code> |
|
| 54 | + | </pre> |
|
| 55 | + | )} |
|
| 56 | + | </div> |
|
| 57 | + | ); |
|
| 58 | + | } |
|
| 59 | + | ||
| 60 | + | export default Home; |
| 1 | + | import { useState } from "react"; |
|
| 2 | + | import beaver from "@/assets/beaver.svg"; |
|
| 3 | + | import type { ApiResponse } from "shared"; |
|
| 4 | + | import { Button } from "@/components/ui/button"; |
|
| 5 | + | ||
| 6 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 7 | + | ||
| 8 | + | function Home() { |
|
| 9 | + | const [data, setData] = useState<ApiResponse | undefined>(); |
|
| 10 | + | ||
| 11 | + | async function sendRequest() { |
|
| 12 | + | try { |
|
| 13 | + | const req = await fetch(`${SERVER_URL}/hello`); |
|
| 14 | + | const res: ApiResponse = await req.json(); |
|
| 15 | + | setData(res); |
|
| 16 | + | } catch (error) { |
|
| 17 | + | console.log(error); |
|
| 18 | + | } |
|
| 19 | + | } |
|
| 20 | + | ||
| 21 | + | return ( |
|
| 22 | + | <div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen"> |
|
| 23 | + | <a |
|
| 24 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 25 | + | target="_blank" |
|
| 26 | + | rel="noopener" |
|
| 27 | + | > |
|
| 28 | + | <img |
|
| 29 | + | src={beaver} |
|
| 30 | + | className="w-16 h-16 cursor-pointer" |
|
| 31 | + | alt="beaver logo" |
|
| 32 | + | /> |
|
| 33 | + | </a> |
|
| 34 | + | <h1 className="text-5xl font-black">bhvr</h1> |
|
| 35 | + | <h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2> |
|
| 36 | + | <p>A typesafe fullstack monorepo</p> |
|
| 37 | + | <div className="flex items-center gap-4"> |
|
| 38 | + | <Button onClick={sendRequest}>Call API</Button> |
|
| 39 | + | <Button variant="secondary" asChild> |
|
| 40 | + | <a target="_blank" href="https://bhvr.dev" rel="noopener"> |
|
| 41 | + | Docs |
|
| 42 | + | </a> |
|
| 43 | + | </Button> |
|
| 44 | + | </div> |
|
| 45 | + | {data && ( |
|
| 46 | + | <pre className="bg-gray-100 p-4 rounded-md"> |
|
| 47 | + | <code> |
|
| 48 | + | Message: {data.message} <br /> |
|
| 49 | + | Success: {data.success.toString()} |
|
| 50 | + | </code> |
|
| 51 | + | </pre> |
|
| 52 | + | )} |
|
| 53 | + | </div> |
|
| 54 | + | ); |
|
| 55 | + | } |
|
| 56 | + | ||
| 57 | + | export default Home; |
| 1 | + | import { useState } from "react"; |
|
| 2 | + | import beaver from "../assets/beaver.svg"; |
|
| 3 | + | import type { ApiResponse } from "shared"; |
|
| 4 | + | import { useMutation } from "@tanstack/react-query"; |
|
| 5 | + | ||
| 6 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 7 | + | ||
| 8 | + | function Home() { |
|
| 9 | + | const [data, setData] = useState<ApiResponse | undefined>(); |
|
| 10 | + | ||
| 11 | + | const { mutate: sendRequest } = useMutation({ |
|
| 12 | + | mutationFn: async () => { |
|
| 13 | + | try { |
|
| 14 | + | const req = await fetch(`${SERVER_URL}/hello`); |
|
| 15 | + | const res: ApiResponse = await req.json(); |
|
| 16 | + | setData(res); |
|
| 17 | + | } catch (error) { |
|
| 18 | + | console.log(error); |
|
| 19 | + | } |
|
| 20 | + | }, |
|
| 21 | + | }); |
|
| 22 | + | ||
| 23 | + | return ( |
|
| 24 | + | <div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen"> |
|
| 25 | + | <a |
|
| 26 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 27 | + | target="_blank" |
|
| 28 | + | rel="noopener" |
|
| 29 | + | > |
|
| 30 | + | <img |
|
| 31 | + | src={beaver} |
|
| 32 | + | className="w-16 h-16 cursor-pointer" |
|
| 33 | + | alt="beaver logo" |
|
| 34 | + | /> |
|
| 35 | + | </a> |
|
| 36 | + | <h1 className="text-5xl font-black">bhvr</h1> |
|
| 37 | + | <h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2> |
|
| 38 | + | <p>A typesafe fullstack monorepo</p> |
|
| 39 | + | <div className="flex items-center gap-4"> |
|
| 40 | + | <button |
|
| 41 | + | type="button" |
|
| 42 | + | onClick={() => sendRequest()} |
|
| 43 | + | className="bg-black text-white px-2.5 py-1.5 rounded-md" |
|
| 44 | + | > |
|
| 45 | + | Call API |
|
| 46 | + | </button> |
|
| 47 | + | <a |
|
| 48 | + | target="_blank" |
|
| 49 | + | href="https://bhvr.dev" |
|
| 50 | + | className="border-1 border-black text-black px-2.5 py-1.5 rounded-md" |
|
| 51 | + | rel="noopener" |
|
| 52 | + | > |
|
| 53 | + | Docs |
|
| 54 | + | </a> |
|
| 55 | + | </div> |
|
| 56 | + | {data && ( |
|
| 57 | + | <pre className="bg-gray-100 p-4 rounded-md"> |
|
| 58 | + | <code> |
|
| 59 | + | Message: {data.message} <br /> |
|
| 60 | + | Success: {data.success.toString()} |
|
| 61 | + | </code> |
|
| 62 | + | </pre> |
|
| 63 | + | )} |
|
| 64 | + | </div> |
|
| 65 | + | ); |
|
| 66 | + | } |
|
| 67 | + | ||
| 68 | + | export default Home; |
| 1 | + | import { useState } from "react"; |
|
| 2 | + | import beaver from "../assets/beaver.svg"; |
|
| 3 | + | import type { ApiResponse } from "shared"; |
|
| 4 | + | ||
| 5 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 6 | + | ||
| 7 | + | function Home() { |
|
| 8 | + | const [data, setData] = useState<ApiResponse | undefined>(); |
|
| 9 | + | ||
| 10 | + | async function sendRequest() { |
|
| 11 | + | try { |
|
| 12 | + | const req = await fetch(`${SERVER_URL}/hello`); |
|
| 13 | + | const res: ApiResponse = await req.json(); |
|
| 14 | + | setData(res); |
|
| 15 | + | } catch (error) { |
|
| 16 | + | console.log(error); |
|
| 17 | + | } |
|
| 18 | + | } |
|
| 19 | + | ||
| 20 | + | return ( |
|
| 21 | + | <div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen"> |
|
| 22 | + | <a |
|
| 23 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 24 | + | target="_blank" |
|
| 25 | + | rel="noopener" |
|
| 26 | + | > |
|
| 27 | + | <img |
|
| 28 | + | src={beaver} |
|
| 29 | + | className="w-16 h-16 cursor-pointer" |
|
| 30 | + | alt="beaver logo" |
|
| 31 | + | /> |
|
| 32 | + | </a> |
|
| 33 | + | <h1 className="text-5xl font-black">bhvr</h1> |
|
| 34 | + | <h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2> |
|
| 35 | + | <p>A typesafe fullstack monorepo</p> |
|
| 36 | + | <div className="flex items-center gap-4"> |
|
| 37 | + | <button |
|
| 38 | + | type="button" |
|
| 39 | + | onClick={sendRequest} |
|
| 40 | + | className="bg-black text-white px-2.5 py-1.5 rounded-md" |
|
| 41 | + | > |
|
| 42 | + | Call API |
|
| 43 | + | </button> |
|
| 44 | + | <a |
|
| 45 | + | target="_blank" |
|
| 46 | + | href="https://bhvr.dev" |
|
| 47 | + | className="border-1 border-black text-black px-2.5 py-1.5 rounded-md" |
|
| 48 | + | rel="noopener" |
|
| 49 | + | > |
|
| 50 | + | Docs |
|
| 51 | + | </a> |
|
| 52 | + | </div> |
|
| 53 | + | {data && ( |
|
| 54 | + | <pre className="bg-gray-100 p-4 rounded-md"> |
|
| 55 | + | <code> |
|
| 56 | + | Message: {data.message} <br /> |
|
| 57 | + | Success: {data.success.toString()} |
|
| 58 | + | </code> |
|
| 59 | + | </pre> |
|
| 60 | + | )} |
|
| 61 | + | </div> |
|
| 62 | + | ); |
|
| 63 | + | } |
|
| 64 | + | ||
| 65 | + | export default Home; |
| 1 | + | import { useState } from "react"; |
|
| 2 | + | import beaver from "../assets/beaver.svg"; |
|
| 3 | + | import { useMutation } from "@tanstack/react-query"; |
|
| 4 | + | import type { ApiResponse } from "shared"; |
|
| 5 | + | import "../App.css"; |
|
| 6 | + | ||
| 7 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 8 | + | ||
| 9 | + | function Home() { |
|
| 10 | + | const [data, setData] = useState<ApiResponse | undefined>(); |
|
| 11 | + | ||
| 12 | + | const { mutate: sendRequest } = useMutation({ |
|
| 13 | + | mutationFn: async () => { |
|
| 14 | + | const req = await fetch(`${SERVER_URL}/hello`); |
|
| 15 | + | const res: ApiResponse = await req.json(); |
|
| 16 | + | setData(res); |
|
| 17 | + | }, |
|
| 18 | + | onError: (err) => console.log(err), |
|
| 19 | + | }); |
|
| 20 | + | ||
| 21 | + | return ( |
|
| 22 | + | <> |
|
| 23 | + | <div> |
|
| 24 | + | <a |
|
| 25 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 26 | + | target="_blank" |
|
| 27 | + | rel="noopener" |
|
| 28 | + | > |
|
| 29 | + | <img src={beaver} className="logo" alt="beaver logo" /> |
|
| 30 | + | </a> |
|
| 31 | + | </div> |
|
| 32 | + | <h1>bhvr</h1> |
|
| 33 | + | <h2>Bun + Hono + Vite + React</h2> |
|
| 34 | + | <p>A typesafe fullstack monorepo</p> |
|
| 35 | + | <div className="card"> |
|
| 36 | + | <div className="button-container"> |
|
| 37 | + | <button type="button" onClick={() => sendRequest()}> |
|
| 38 | + | Call API |
|
| 39 | + | </button> |
|
| 40 | + | <a |
|
| 41 | + | className="docs-link" |
|
| 42 | + | target="_blank" |
|
| 43 | + | href="https://bhvr.dev" |
|
| 44 | + | rel="noopener" |
|
| 45 | + | > |
|
| 46 | + | Docs |
|
| 47 | + | </a> |
|
| 48 | + | </div> |
|
| 49 | + | {data && ( |
|
| 50 | + | <pre className="response"> |
|
| 51 | + | <code> |
|
| 52 | + | Message: {data.message} <br /> |
|
| 53 | + | Success: {data.success.toString()} |
|
| 54 | + | </code> |
|
| 55 | + | </pre> |
|
| 56 | + | )} |
|
| 57 | + | </div> |
|
| 58 | + | </> |
|
| 59 | + | ); |
|
| 60 | + | } |
|
| 61 | + | ||
| 62 | + | export default Home; |
| 1 | + | import { useState } from "react"; |
|
| 2 | + | import beaver from "../assets/beaver.svg"; |
|
| 3 | + | import type { ApiResponse } from "shared"; |
|
| 4 | + | import "../App.css"; |
|
| 5 | + | ||
| 6 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 7 | + | ||
| 8 | + | function Home() { |
|
| 9 | + | const [data, setData] = useState<ApiResponse | undefined>(); |
|
| 10 | + | ||
| 11 | + | async function sendRequest() { |
|
| 12 | + | try { |
|
| 13 | + | const req = await fetch(`${SERVER_URL}/hello`); |
|
| 14 | + | const res: ApiResponse = await req.json(); |
|
| 15 | + | setData(res); |
|
| 16 | + | } catch (error) { |
|
| 17 | + | console.log(error); |
|
| 18 | + | } |
|
| 19 | + | } |
|
| 20 | + | ||
| 21 | + | return ( |
|
| 22 | + | <> |
|
| 23 | + | <div> |
|
| 24 | + | <a |
|
| 25 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 26 | + | target="_blank" |
|
| 27 | + | rel="noopener" |
|
| 28 | + | > |
|
| 29 | + | <img src={beaver} className="logo" alt="beaver logo" /> |
|
| 30 | + | </a> |
|
| 31 | + | </div> |
|
| 32 | + | <h1>bhvr</h1> |
|
| 33 | + | <h2>Bun + Hono + Vite + React</h2> |
|
| 34 | + | <p>A typesafe fullstack monorepo</p> |
|
| 35 | + | <div className="card"> |
|
| 36 | + | <div className="button-container"> |
|
| 37 | + | <button type="button" onClick={sendRequest}> |
|
| 38 | + | Call API |
|
| 39 | + | </button> |
|
| 40 | + | <a |
|
| 41 | + | className="docs-link" |
|
| 42 | + | target="_blank" |
|
| 43 | + | href="https://bhvr.dev" |
|
| 44 | + | rel="noopener" |
|
| 45 | + | > |
|
| 46 | + | Docs |
|
| 47 | + | </a> |
|
| 48 | + | </div> |
|
| 49 | + | {data && ( |
|
| 50 | + | <pre className="response"> |
|
| 51 | + | <code> |
|
| 52 | + | Message: {data.message} <br /> |
|
| 53 | + | Success: {data.success.toString()} |
|
| 54 | + | </code> |
|
| 55 | + | </pre> |
|
| 56 | + | )} |
|
| 57 | + | </div> |
|
| 58 | + | </> |
|
| 59 | + | ); |
|
| 60 | + | } |
|
| 61 | + | ||
| 62 | + | export default Home; |
| 1 | + | import { StrictMode } from "react"; |
|
| 2 | + | import ReactDOM from "react-dom/client"; |
|
| 3 | + | import { RouterProvider, createRouter } from "@tanstack/react-router"; |
|
| 4 | + | import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; |
|
| 5 | + | import "./index.css"; |
|
| 6 | + | ||
| 7 | + | const queryClient = new QueryClient(); |
|
| 8 | + | ||
| 9 | + | // Import the generated route tree |
|
| 10 | + | import { routeTree } from "./routeTree.gen"; |
|
| 11 | + | ||
| 12 | + | // Create a new router instance |
|
| 13 | + | const router = createRouter({ routeTree }); |
|
| 14 | + | ||
| 15 | + | // Register the router instance for type safety |
|
| 16 | + | declare module "@tanstack/react-router" { |
|
| 17 | + | interface Register { |
|
| 18 | + | router: typeof router; |
|
| 19 | + | } |
|
| 20 | + | } |
|
| 21 | + | ||
| 22 | + | const rootElement = document.getElementById("root"); |
|
| 23 | + | ||
| 24 | + | if (!rootElement) { |
|
| 25 | + | throw new Error( |
|
| 26 | + | "Root element not found. Check if it's in your index.html or if the id is correct.", |
|
| 27 | + | ); |
|
| 28 | + | } |
|
| 29 | + | ||
| 30 | + | // Render the app |
|
| 31 | + | if (!rootElement.innerHTML) { |
|
| 32 | + | const root = ReactDOM.createRoot(rootElement); |
|
| 33 | + | root.render( |
|
| 34 | + | <StrictMode> |
|
| 35 | + | <QueryClientProvider client={queryClient}> |
|
| 36 | + | <RouterProvider router={router} /> |
|
| 37 | + | </QueryClientProvider> |
|
| 38 | + | </StrictMode>, |
|
| 39 | + | ); |
|
| 40 | + | } |
| 1 | + | import { StrictMode } from "react"; |
|
| 2 | + | import ReactDOM from "react-dom/client"; |
|
| 3 | + | import { RouterProvider, createRouter } from "@tanstack/react-router"; |
|
| 4 | + | import "./index.css"; |
|
| 5 | + | ||
| 6 | + | // Import the generated route tree |
|
| 7 | + | import { routeTree } from "./routeTree.gen"; |
|
| 8 | + | ||
| 9 | + | // Create a new router instance |
|
| 10 | + | const router = createRouter({ routeTree }); |
|
| 11 | + | ||
| 12 | + | // Register the router instance for type safety |
|
| 13 | + | declare module "@tanstack/react-router" { |
|
| 14 | + | interface Register { |
|
| 15 | + | router: typeof router; |
|
| 16 | + | } |
|
| 17 | + | } |
|
| 18 | + | ||
| 19 | + | const rootElement = document.getElementById("root"); |
|
| 20 | + | ||
| 21 | + | if (!rootElement) { |
|
| 22 | + | throw new Error( |
|
| 23 | + | "Root element not found. Check if it's in your index.html or if the id is correct.", |
|
| 24 | + | ); |
|
| 25 | + | } |
|
| 26 | + | ||
| 27 | + | // Render the app |
|
| 28 | + | if (!rootElement.innerHTML) { |
|
| 29 | + | const root = ReactDOM.createRoot(rootElement); |
|
| 30 | + | root.render( |
|
| 31 | + | <StrictMode> |
|
| 32 | + | <RouterProvider router={router} /> |
|
| 33 | + | </StrictMode>, |
|
| 34 | + | ); |
|
| 35 | + | } |
| 1 | + | import { createRootRoute, Outlet } from "@tanstack/react-router"; |
|
| 2 | + | import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; |
|
| 3 | + | ||
| 4 | + | export const Route = createRootRoute({ |
|
| 5 | + | component: () => ( |
|
| 6 | + | <> |
|
| 7 | + | <Outlet /> |
|
| 8 | + | <TanStackRouterDevtools /> |
|
| 9 | + | </> |
|
| 10 | + | ), |
|
| 11 | + | }); |
| 1 | + | import { createFileRoute } from "@tanstack/react-router"; |
|
| 2 | + | import { useState } from "react"; |
|
| 3 | + | import beaver from "@/assets/beaver.svg"; |
|
| 4 | + | import { Button } from "@/components/ui/button"; |
|
| 5 | + | import { hcWithType } from "server/dist/client"; |
|
| 6 | + | import { useMutation } from "@tanstack/react-query"; |
|
| 7 | + | ||
| 8 | + | export const Route = createFileRoute("/")({ |
|
| 9 | + | component: Index, |
|
| 10 | + | }); |
|
| 11 | + | ||
| 12 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 13 | + | ||
| 14 | + | const client = hcWithType(SERVER_URL); |
|
| 15 | + | ||
| 16 | + | type ResponseType = Awaited<ReturnType<typeof client.hello.$get>>; |
|
| 17 | + | ||
| 18 | + | function Index() { |
|
| 19 | + | const [data, setData] = useState< |
|
| 20 | + | Awaited<ReturnType<ResponseType["json"]>> | undefined |
|
| 21 | + | >(); |
|
| 22 | + | ||
| 23 | + | const { mutate: sendRequest } = useMutation({ |
|
| 24 | + | mutationFn: async () => { |
|
| 25 | + | try { |
|
| 26 | + | const res = await client.hello.$get(); |
|
| 27 | + | if (!res.ok) { |
|
| 28 | + | console.log("Error fetching data"); |
|
| 29 | + | return; |
|
| 30 | + | } |
|
| 31 | + | const data = await res.json(); |
|
| 32 | + | setData(data); |
|
| 33 | + | } catch (error) { |
|
| 34 | + | console.log(error); |
|
| 35 | + | } |
|
| 36 | + | }, |
|
| 37 | + | }); |
|
| 38 | + | ||
| 39 | + | return ( |
|
| 40 | + | <div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen"> |
|
| 41 | + | <a |
|
| 42 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 43 | + | target="_blank" |
|
| 44 | + | rel="noopener" |
|
| 45 | + | > |
|
| 46 | + | <img |
|
| 47 | + | src={beaver} |
|
| 48 | + | className="w-16 h-16 cursor-pointer" |
|
| 49 | + | alt="beaver logo" |
|
| 50 | + | /> |
|
| 51 | + | </a> |
|
| 52 | + | <h1 className="text-5xl font-black">bhvr</h1> |
|
| 53 | + | <h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2> |
|
| 54 | + | <p>A typesafe fullstack monorepo</p> |
|
| 55 | + | <div className="flex items-center gap-4"> |
|
| 56 | + | <Button onClick={() => sendRequest()}>Call API</Button> |
|
| 57 | + | <Button variant="secondary" asChild> |
|
| 58 | + | <a target="_blank" href="https://bhvr.dev" rel="noopener"> |
|
| 59 | + | Docs |
|
| 60 | + | </a> |
|
| 61 | + | </Button> |
|
| 62 | + | </div> |
|
| 63 | + | {data && ( |
|
| 64 | + | <pre className="bg-gray-100 p-4 rounded-md"> |
|
| 65 | + | <code> |
|
| 66 | + | Message: {data.message} <br /> |
|
| 67 | + | Success: {data.success.toString()} |
|
| 68 | + | </code> |
|
| 69 | + | </pre> |
|
| 70 | + | )} |
|
| 71 | + | </div> |
|
| 72 | + | ); |
|
| 73 | + | } |
|
| 74 | + | ||
| 75 | + | export default Index; |
| 1 | + | import { createFileRoute } from "@tanstack/react-router"; |
|
| 2 | + | import { useState } from "react"; |
|
| 3 | + | import beaver from "@/assets/beaver.svg"; |
|
| 4 | + | import { Button } from "@/components/ui/button"; |
|
| 5 | + | import { hcWithType } from "server/dist/client"; |
|
| 6 | + | ||
| 7 | + | export const Route = createFileRoute("/")({ |
|
| 8 | + | component: Index, |
|
| 9 | + | }); |
|
| 10 | + | ||
| 11 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 12 | + | ||
| 13 | + | const client = hcWithType(SERVER_URL); |
|
| 14 | + | ||
| 15 | + | type ResponseType = Awaited<ReturnType<typeof client.hello.$get>>; |
|
| 16 | + | ||
| 17 | + | function Index() { |
|
| 18 | + | const [data, setData] = useState< |
|
| 19 | + | Awaited<ReturnType<ResponseType["json"]>> | undefined |
|
| 20 | + | >(); |
|
| 21 | + | ||
| 22 | + | async function sendRequest() { |
|
| 23 | + | try { |
|
| 24 | + | const res = await client.hello.$get(); |
|
| 25 | + | if (!res.ok) { |
|
| 26 | + | console.log("Error fetching data"); |
|
| 27 | + | return; |
|
| 28 | + | } |
|
| 29 | + | const data = await res.json(); |
|
| 30 | + | setData(data); |
|
| 31 | + | } catch (error) { |
|
| 32 | + | console.log(error); |
|
| 33 | + | } |
|
| 34 | + | } |
|
| 35 | + | ||
| 36 | + | return ( |
|
| 37 | + | <div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen"> |
|
| 38 | + | <a |
|
| 39 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 40 | + | target="_blank" |
|
| 41 | + | rel="noopener" |
|
| 42 | + | > |
|
| 43 | + | <img |
|
| 44 | + | src={beaver} |
|
| 45 | + | className="w-16 h-16 cursor-pointer" |
|
| 46 | + | alt="beaver logo" |
|
| 47 | + | /> |
|
| 48 | + | </a> |
|
| 49 | + | <h1 className="text-5xl font-black">bhvr</h1> |
|
| 50 | + | <h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2> |
|
| 51 | + | <p>A typesafe fullstack monorepo</p> |
|
| 52 | + | <div className="flex items-center gap-4"> |
|
| 53 | + | <Button onClick={sendRequest}>Call API</Button> |
|
| 54 | + | <Button variant="secondary" asChild> |
|
| 55 | + | <a target="_blank" href="https://bhvr.dev" rel="noopener"> |
|
| 56 | + | Docs |
|
| 57 | + | </a> |
|
| 58 | + | </Button> |
|
| 59 | + | </div> |
|
| 60 | + | {data && ( |
|
| 61 | + | <pre className="bg-gray-100 p-4 rounded-md"> |
|
| 62 | + | <code> |
|
| 63 | + | Message: {data.message} <br /> |
|
| 64 | + | Success: {data.success.toString()} |
|
| 65 | + | </code> |
|
| 66 | + | </pre> |
|
| 67 | + | )} |
|
| 68 | + | </div> |
|
| 69 | + | ); |
|
| 70 | + | } |
|
| 71 | + | ||
| 72 | + | export default Index; |
| 1 | + | import { createFileRoute } from "@tanstack/react-router"; |
|
| 2 | + | import { useState } from "react"; |
|
| 3 | + | import beaver from "../assets/beaver.svg"; |
|
| 4 | + | import { hcWithType } from "server/dist/client"; |
|
| 5 | + | import { useMutation } from "@tanstack/react-query"; |
|
| 6 | + | ||
| 7 | + | export const Route = createFileRoute("/")({ |
|
| 8 | + | component: Index, |
|
| 9 | + | }); |
|
| 10 | + | ||
| 11 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 12 | + | ||
| 13 | + | type ResponseType = Awaited<ReturnType<typeof client.hello.$get>>; |
|
| 14 | + | ||
| 15 | + | const client = hcWithType(SERVER_URL); |
|
| 16 | + | ||
| 17 | + | function Index() { |
|
| 18 | + | const [data, setData] = useState< |
|
| 19 | + | Awaited<ReturnType<ResponseType["json"]>> | undefined |
|
| 20 | + | >(); |
|
| 21 | + | ||
| 22 | + | const { mutate: sendRequest } = useMutation({ |
|
| 23 | + | mutationFn: async () => { |
|
| 24 | + | try { |
|
| 25 | + | const res = await client.hello.$get(); |
|
| 26 | + | if (!res.ok) { |
|
| 27 | + | console.log("Error fetching data"); |
|
| 28 | + | return; |
|
| 29 | + | } |
|
| 30 | + | const data = await res.json(); |
|
| 31 | + | setData(data); |
|
| 32 | + | } catch (error) { |
|
| 33 | + | console.log(error); |
|
| 34 | + | } |
|
| 35 | + | }, |
|
| 36 | + | }); |
|
| 37 | + | ||
| 38 | + | return ( |
|
| 39 | + | <div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen"> |
|
| 40 | + | <a |
|
| 41 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 42 | + | target="_blank" |
|
| 43 | + | rel="noopener" |
|
| 44 | + | > |
|
| 45 | + | <img |
|
| 46 | + | src={beaver} |
|
| 47 | + | className="w-16 h-16 cursor-pointer" |
|
| 48 | + | alt="beaver logo" |
|
| 49 | + | /> |
|
| 50 | + | </a> |
|
| 51 | + | <h1 className="text-5xl font-black">bhvr</h1> |
|
| 52 | + | <h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2> |
|
| 53 | + | <p>A typesafe fullstack monorepo</p> |
|
| 54 | + | <div className="flex items-center gap-4"> |
|
| 55 | + | <button |
|
| 56 | + | type="button" |
|
| 57 | + | onClick={() => sendRequest()} |
|
| 58 | + | className="bg-black text-white px-2.5 py-1.5 rounded-md" |
|
| 59 | + | > |
|
| 60 | + | Call API |
|
| 61 | + | </button> |
|
| 62 | + | <a |
|
| 63 | + | target="_blank" |
|
| 64 | + | href="https://bhvr.dev" |
|
| 65 | + | className="border-1 border-black text-black px-2.5 py-1.5 rounded-md" |
|
| 66 | + | rel="noopener" |
|
| 67 | + | > |
|
| 68 | + | Docs |
|
| 69 | + | </a> |
|
| 70 | + | </div> |
|
| 71 | + | {data && ( |
|
| 72 | + | <pre className="bg-gray-100 p-4 rounded-md"> |
|
| 73 | + | <code> |
|
| 74 | + | Message: {data.message} <br /> |
|
| 75 | + | Success: {data.success.toString()} |
|
| 76 | + | </code> |
|
| 77 | + | </pre> |
|
| 78 | + | )} |
|
| 79 | + | </div> |
|
| 80 | + | ); |
|
| 81 | + | } |
|
| 82 | + | ||
| 83 | + | export default Index; |
| 1 | + | import { createFileRoute } from "@tanstack/react-router"; |
|
| 2 | + | import { useState } from "react"; |
|
| 3 | + | import beaver from "../assets/beaver.svg"; |
|
| 4 | + | import { hcWithType } from "server/dist/client"; |
|
| 5 | + | ||
| 6 | + | export const Route = createFileRoute("/")({ |
|
| 7 | + | component: Index, |
|
| 8 | + | }); |
|
| 9 | + | ||
| 10 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 11 | + | ||
| 12 | + | type ResponseType = Awaited<ReturnType<typeof client.hello.$get>>; |
|
| 13 | + | ||
| 14 | + | const client = hcWithType(SERVER_URL); |
|
| 15 | + | ||
| 16 | + | function Index() { |
|
| 17 | + | const [data, setData] = useState< |
|
| 18 | + | Awaited<ReturnType<ResponseType["json"]>> | undefined |
|
| 19 | + | >(); |
|
| 20 | + | ||
| 21 | + | async function sendRequest() { |
|
| 22 | + | try { |
|
| 23 | + | const res = await client.hello.$get(); |
|
| 24 | + | if (!res.ok) { |
|
| 25 | + | console.log("Error fetching data"); |
|
| 26 | + | return; |
|
| 27 | + | } |
|
| 28 | + | const data = await res.json(); |
|
| 29 | + | setData(data); |
|
| 30 | + | } catch (error) { |
|
| 31 | + | console.log(error); |
|
| 32 | + | } |
|
| 33 | + | } |
|
| 34 | + | ||
| 35 | + | return ( |
|
| 36 | + | <div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen"> |
|
| 37 | + | <a |
|
| 38 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 39 | + | target="_blank" |
|
| 40 | + | rel="noopener" |
|
| 41 | + | > |
|
| 42 | + | <img |
|
| 43 | + | src={beaver} |
|
| 44 | + | className="w-16 h-16 cursor-pointer" |
|
| 45 | + | alt="beaver logo" |
|
| 46 | + | /> |
|
| 47 | + | </a> |
|
| 48 | + | <h1 className="text-5xl font-black">bhvr</h1> |
|
| 49 | + | <h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2> |
|
| 50 | + | <p>A typesafe fullstack monorepo</p> |
|
| 51 | + | <div className="flex items-center gap-4"> |
|
| 52 | + | <button |
|
| 53 | + | type="button" |
|
| 54 | + | onClick={sendRequest} |
|
| 55 | + | className="bg-black text-white px-2.5 py-1.5 rounded-md" |
|
| 56 | + | > |
|
| 57 | + | Call API |
|
| 58 | + | </button> |
|
| 59 | + | <a |
|
| 60 | + | target="_blank" |
|
| 61 | + | href="https://bhvr.dev" |
|
| 62 | + | className="border-1 border-black text-black px-2.5 py-1.5 rounded-md" |
|
| 63 | + | rel="noopener" |
|
| 64 | + | > |
|
| 65 | + | Docs |
|
| 66 | + | </a> |
|
| 67 | + | </div> |
|
| 68 | + | {data && ( |
|
| 69 | + | <pre className="bg-gray-100 p-4 rounded-md"> |
|
| 70 | + | <code> |
|
| 71 | + | Message: {data.message} <br /> |
|
| 72 | + | Success: {data.success.toString()} |
|
| 73 | + | </code> |
|
| 74 | + | </pre> |
|
| 75 | + | )} |
|
| 76 | + | </div> |
|
| 77 | + | ); |
|
| 78 | + | } |
|
| 79 | + | ||
| 80 | + | export default Index; |
| 1 | + | import { createFileRoute } from "@tanstack/react-router"; |
|
| 2 | + | import { useState } from "react"; |
|
| 3 | + | import beaver from "../assets/beaver.svg"; |
|
| 4 | + | import { hcWithType } from "server/dist/client"; |
|
| 5 | + | import { useMutation } from "@tanstack/react-query"; |
|
| 6 | + | import "../App.css"; |
|
| 7 | + | ||
| 8 | + | export const Route = createFileRoute("/")({ |
|
| 9 | + | component: Index, |
|
| 10 | + | }); |
|
| 11 | + | ||
| 12 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 13 | + | ||
| 14 | + | const client = hcWithType(SERVER_URL); |
|
| 15 | + | ||
| 16 | + | type ResponseType = Awaited<ReturnType<typeof client.hello.$get>>; |
|
| 17 | + | ||
| 18 | + | function Index() { |
|
| 19 | + | const [data, setData] = useState< |
|
| 20 | + | Awaited<ReturnType<ResponseType["json"]>> | undefined |
|
| 21 | + | >(); |
|
| 22 | + | ||
| 23 | + | const { mutate: sendRequest } = useMutation({ |
|
| 24 | + | mutationFn: async () => { |
|
| 25 | + | try { |
|
| 26 | + | const res = await client.hello.$get(); |
|
| 27 | + | if (!res.ok) { |
|
| 28 | + | console.log("Error fetching data"); |
|
| 29 | + | return; |
|
| 30 | + | } |
|
| 31 | + | const data = await res.json(); |
|
| 32 | + | setData(data); |
|
| 33 | + | } catch (error) { |
|
| 34 | + | console.log(error); |
|
| 35 | + | } |
|
| 36 | + | }, |
|
| 37 | + | }); |
|
| 38 | + | ||
| 39 | + | return ( |
|
| 40 | + | <> |
|
| 41 | + | <div> |
|
| 42 | + | <a |
|
| 43 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 44 | + | target="_blank" |
|
| 45 | + | rel="noopener" |
|
| 46 | + | > |
|
| 47 | + | <img src={beaver} className="logo" alt="beaver logo" /> |
|
| 48 | + | </a> |
|
| 49 | + | </div> |
|
| 50 | + | <h1>bhvr</h1> |
|
| 51 | + | <h2>Bun + Hono + Vite + React</h2> |
|
| 52 | + | <p>A typesafe fullstack monorepo</p> |
|
| 53 | + | <div className="card"> |
|
| 54 | + | <div className="button-container"> |
|
| 55 | + | <button type="button" onClick={() => sendRequest()}> |
|
| 56 | + | Call API |
|
| 57 | + | </button> |
|
| 58 | + | <a |
|
| 59 | + | className="docs-link" |
|
| 60 | + | target="_blank" |
|
| 61 | + | href="https://bhvr.dev" |
|
| 62 | + | rel="noopener" |
|
| 63 | + | > |
|
| 64 | + | Docs |
|
| 65 | + | </a> |
|
| 66 | + | </div> |
|
| 67 | + | {data && ( |
|
| 68 | + | <pre className="response"> |
|
| 69 | + | <code> |
|
| 70 | + | Message: {data.message} <br /> |
|
| 71 | + | Success: {data.success.toString()} |
|
| 72 | + | </code> |
|
| 73 | + | </pre> |
|
| 74 | + | )} |
|
| 75 | + | </div> |
|
| 76 | + | </> |
|
| 77 | + | ); |
|
| 78 | + | } |
|
| 79 | + | ||
| 80 | + | export default Index; |
| 1 | + | import { createFileRoute } from "@tanstack/react-router"; |
|
| 2 | + | import { useState } from "react"; |
|
| 3 | + | import beaver from "../assets/beaver.svg"; |
|
| 4 | + | import { hcWithType } from "server/dist/client"; |
|
| 5 | + | import "../App.css"; |
|
| 6 | + | ||
| 7 | + | export const Route = createFileRoute("/")({ |
|
| 8 | + | component: Index, |
|
| 9 | + | }); |
|
| 10 | + | ||
| 11 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 12 | + | ||
| 13 | + | const client = hcWithType(SERVER_URL); |
|
| 14 | + | ||
| 15 | + | type ResponseType = Awaited<ReturnType<typeof client.hello.$get>>; |
|
| 16 | + | ||
| 17 | + | function Index() { |
|
| 18 | + | const [data, setData] = useState< |
|
| 19 | + | Awaited<ReturnType<ResponseType["json"]>> | undefined |
|
| 20 | + | >(); |
|
| 21 | + | ||
| 22 | + | async function sendRequest() { |
|
| 23 | + | try { |
|
| 24 | + | const res = await client.hello.$get(); |
|
| 25 | + | if (!res.ok) { |
|
| 26 | + | console.log("Error fetching data"); |
|
| 27 | + | return; |
|
| 28 | + | } |
|
| 29 | + | const data = await res.json(); |
|
| 30 | + | setData(data); |
|
| 31 | + | } catch (error) { |
|
| 32 | + | console.log(error); |
|
| 33 | + | } |
|
| 34 | + | } |
|
| 35 | + | ||
| 36 | + | return ( |
|
| 37 | + | <> |
|
| 38 | + | <div> |
|
| 39 | + | <a |
|
| 40 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 41 | + | target="_blank" |
|
| 42 | + | rel="noopener" |
|
| 43 | + | > |
|
| 44 | + | <img src={beaver} className="logo" alt="beaver logo" /> |
|
| 45 | + | </a> |
|
| 46 | + | </div> |
|
| 47 | + | <h1>bhvr</h1> |
|
| 48 | + | <h2>Bun + Hono + Vite + React</h2> |
|
| 49 | + | <p>A typesafe fullstack monorepo</p> |
|
| 50 | + | <div className="card"> |
|
| 51 | + | <div className="button-container"> |
|
| 52 | + | <button type="button" onClick={sendRequest}> |
|
| 53 | + | Call API |
|
| 54 | + | </button> |
|
| 55 | + | <a |
|
| 56 | + | className="docs-link" |
|
| 57 | + | target="_blank" |
|
| 58 | + | href="https://bhvr.dev" |
|
| 59 | + | rel="noopener" |
|
| 60 | + | > |
|
| 61 | + | Docs |
|
| 62 | + | </a> |
|
| 63 | + | </div> |
|
| 64 | + | {data && ( |
|
| 65 | + | <pre className="response"> |
|
| 66 | + | <code> |
|
| 67 | + | Message: {data.message} <br /> |
|
| 68 | + | Success: {data.success.toString()} |
|
| 69 | + | </code> |
|
| 70 | + | </pre> |
|
| 71 | + | )} |
|
| 72 | + | </div> |
|
| 73 | + | </> |
|
| 74 | + | ); |
|
| 75 | + | } |
|
| 76 | + | ||
| 77 | + | export default Index; |
| 1 | + | import { createFileRoute } from "@tanstack/react-router"; |
|
| 2 | + | import { useState } from "react"; |
|
| 3 | + | import beaver from "@/assets/beaver.svg"; |
|
| 4 | + | import type { ApiResponse } from "shared"; |
|
| 5 | + | import { Button } from "@/components/ui/button"; |
|
| 6 | + | import { useMutation } from "@tanstack/react-query"; |
|
| 7 | + | ||
| 8 | + | export const Route = createFileRoute("/")({ |
|
| 9 | + | component: Index, |
|
| 10 | + | }); |
|
| 11 | + | ||
| 12 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 13 | + | ||
| 14 | + | function Index() { |
|
| 15 | + | const [data, setData] = useState<ApiResponse | undefined>(); |
|
| 16 | + | ||
| 17 | + | const { mutate: sendRequest } = useMutation({ |
|
| 18 | + | mutationFn: async () => { |
|
| 19 | + | try { |
|
| 20 | + | const req = await fetch(`${SERVER_URL}/hello`); |
|
| 21 | + | const res: ApiResponse = await req.json(); |
|
| 22 | + | setData(res); |
|
| 23 | + | } catch (error) { |
|
| 24 | + | console.log(error); |
|
| 25 | + | } |
|
| 26 | + | }, |
|
| 27 | + | }); |
|
| 28 | + | ||
| 29 | + | return ( |
|
| 30 | + | <div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen"> |
|
| 31 | + | <a |
|
| 32 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 33 | + | target="_blank" |
|
| 34 | + | rel="noopener" |
|
| 35 | + | > |
|
| 36 | + | <img |
|
| 37 | + | src={beaver} |
|
| 38 | + | className="w-16 h-16 cursor-pointer" |
|
| 39 | + | alt="beaver logo" |
|
| 40 | + | /> |
|
| 41 | + | </a> |
|
| 42 | + | <h1 className="text-5xl font-black">bhvr</h1> |
|
| 43 | + | <h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2> |
|
| 44 | + | <p>A typesafe fullstack monorepo</p> |
|
| 45 | + | <div className="flex items-center gap-4"> |
|
| 46 | + | <Button onClick={() => sendRequest()}>Call API</Button> |
|
| 47 | + | <Button variant="secondary" asChild> |
|
| 48 | + | <a target="_blank" href="https://bhvr.dev" rel="noopener"> |
|
| 49 | + | Docs |
|
| 50 | + | </a> |
|
| 51 | + | </Button> |
|
| 52 | + | </div> |
|
| 53 | + | {data && ( |
|
| 54 | + | <pre className="bg-gray-100 p-4 rounded-md"> |
|
| 55 | + | <code> |
|
| 56 | + | Message: {data.message} <br /> |
|
| 57 | + | Success: {data.success.toString()} |
|
| 58 | + | </code> |
|
| 59 | + | </pre> |
|
| 60 | + | )} |
|
| 61 | + | </div> |
|
| 62 | + | ); |
|
| 63 | + | } |
|
| 64 | + | ||
| 65 | + | export default Index; |
| 1 | + | import { createFileRoute } from "@tanstack/react-router"; |
|
| 2 | + | import { useState } from "react"; |
|
| 3 | + | import beaver from "../assets/beaver.svg"; |
|
| 4 | + | import type { ApiResponse } from "shared"; |
|
| 5 | + | import { Button } from "@/components/ui/button"; |
|
| 6 | + | ||
| 7 | + | export const Route = createFileRoute("/")({ |
|
| 8 | + | component: Index, |
|
| 9 | + | }); |
|
| 10 | + | ||
| 11 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 12 | + | ||
| 13 | + | function Index() { |
|
| 14 | + | const [data, setData] = useState<ApiResponse | undefined>(); |
|
| 15 | + | ||
| 16 | + | async function sendRequest() { |
|
| 17 | + | try { |
|
| 18 | + | const req = await fetch(`${SERVER_URL}/hello`); |
|
| 19 | + | const res: ApiResponse = await req.json(); |
|
| 20 | + | setData(res); |
|
| 21 | + | } catch (error) { |
|
| 22 | + | console.log(error); |
|
| 23 | + | } |
|
| 24 | + | } |
|
| 25 | + | ||
| 26 | + | return ( |
|
| 27 | + | <div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen"> |
|
| 28 | + | <a |
|
| 29 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 30 | + | target="_blank" |
|
| 31 | + | rel="noopener" |
|
| 32 | + | > |
|
| 33 | + | <img |
|
| 34 | + | src={beaver} |
|
| 35 | + | className="w-16 h-16 cursor-pointer" |
|
| 36 | + | alt="beaver logo" |
|
| 37 | + | /> |
|
| 38 | + | </a> |
|
| 39 | + | <h1 className="text-5xl font-black">bhvr</h1> |
|
| 40 | + | <h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2> |
|
| 41 | + | <p>A typesafe fullstack monorepo</p> |
|
| 42 | + | <div className="flex items-center gap-4"> |
|
| 43 | + | <Button onClick={sendRequest}>Call API</Button> |
|
| 44 | + | <Button variant="secondary" asChild> |
|
| 45 | + | <a target="_blank" href="https://bhvr.dev" rel="noopener"> |
|
| 46 | + | Docs |
|
| 47 | + | </a> |
|
| 48 | + | </Button> |
|
| 49 | + | </div> |
|
| 50 | + | {data && ( |
|
| 51 | + | <pre className="bg-gray-100 p-4 rounded-md"> |
|
| 52 | + | <code> |
|
| 53 | + | Message: {data.message} <br /> |
|
| 54 | + | Success: {data.success.toString()} |
|
| 55 | + | </code> |
|
| 56 | + | </pre> |
|
| 57 | + | )} |
|
| 58 | + | </div> |
|
| 59 | + | ); |
|
| 60 | + | } |
| 1 | + | import { createFileRoute } from "@tanstack/react-router"; |
|
| 2 | + | import { useState } from "react"; |
|
| 3 | + | import beaver from "../assets/beaver.svg"; |
|
| 4 | + | import type { ApiResponse } from "shared"; |
|
| 5 | + | import { useMutation } from "@tanstack/react-query"; |
|
| 6 | + | ||
| 7 | + | export const Route = createFileRoute("/")({ |
|
| 8 | + | component: Index, |
|
| 9 | + | }); |
|
| 10 | + | ||
| 11 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 12 | + | ||
| 13 | + | function Index() { |
|
| 14 | + | const [data, setData] = useState<ApiResponse | undefined>(); |
|
| 15 | + | ||
| 16 | + | const { mutate: sendRequest } = useMutation({ |
|
| 17 | + | mutationFn: async () => { |
|
| 18 | + | try { |
|
| 19 | + | const req = await fetch(`${SERVER_URL}/hello`); |
|
| 20 | + | const res: ApiResponse = await req.json(); |
|
| 21 | + | setData(res); |
|
| 22 | + | } catch (error) { |
|
| 23 | + | console.log(error); |
|
| 24 | + | } |
|
| 25 | + | }, |
|
| 26 | + | }); |
|
| 27 | + | ||
| 28 | + | return ( |
|
| 29 | + | <div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen"> |
|
| 30 | + | <a |
|
| 31 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 32 | + | target="_blank" |
|
| 33 | + | rel="noopener" |
|
| 34 | + | > |
|
| 35 | + | <img |
|
| 36 | + | src={beaver} |
|
| 37 | + | className="w-16 h-16 cursor-pointer" |
|
| 38 | + | alt="beaver logo" |
|
| 39 | + | /> |
|
| 40 | + | </a> |
|
| 41 | + | <h1 className="text-5xl font-black">bhvr</h1> |
|
| 42 | + | <h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2> |
|
| 43 | + | <p>A typesafe fullstack monorepo</p> |
|
| 44 | + | <div className="flex items-center gap-4"> |
|
| 45 | + | <button |
|
| 46 | + | type="button" |
|
| 47 | + | onClick={() => sendRequest()} |
|
| 48 | + | className="bg-black text-white px-2.5 py-1.5 rounded-md" |
|
| 49 | + | > |
|
| 50 | + | Call API |
|
| 51 | + | </button> |
|
| 52 | + | <a |
|
| 53 | + | target="_blank" |
|
| 54 | + | href="https://bhvr.dev" |
|
| 55 | + | className="border-1 border-black text-black px-2.5 py-1.5 rounded-md" |
|
| 56 | + | rel="noopener" |
|
| 57 | + | > |
|
| 58 | + | Docs |
|
| 59 | + | </a> |
|
| 60 | + | </div> |
|
| 61 | + | {data && ( |
|
| 62 | + | <pre className="bg-gray-100 p-4 rounded-md"> |
|
| 63 | + | <code> |
|
| 64 | + | Message: {data.message} <br /> |
|
| 65 | + | Success: {data.success.toString()} |
|
| 66 | + | </code> |
|
| 67 | + | </pre> |
|
| 68 | + | )} |
|
| 69 | + | </div> |
|
| 70 | + | ); |
|
| 71 | + | } |
|
| 72 | + | ||
| 73 | + | export default Index; |
| 1 | + | import { createFileRoute } from "@tanstack/react-router"; |
|
| 2 | + | import { useState } from "react"; |
|
| 3 | + | import beaver from "../assets/beaver.svg"; |
|
| 4 | + | import type { ApiResponse } from "shared"; |
|
| 5 | + | ||
| 6 | + | export const Route = createFileRoute("/")({ |
|
| 7 | + | component: Index, |
|
| 8 | + | }); |
|
| 9 | + | ||
| 10 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 11 | + | ||
| 12 | + | function Index() { |
|
| 13 | + | const [data, setData] = useState<ApiResponse | undefined>(); |
|
| 14 | + | ||
| 15 | + | async function sendRequest() { |
|
| 16 | + | try { |
|
| 17 | + | const req = await fetch(`${SERVER_URL}/hello`); |
|
| 18 | + | const res: ApiResponse = await req.json(); |
|
| 19 | + | setData(res); |
|
| 20 | + | } catch (error) { |
|
| 21 | + | console.log(error); |
|
| 22 | + | } |
|
| 23 | + | } |
|
| 24 | + | ||
| 25 | + | return ( |
|
| 26 | + | <div className="max-w-xl mx-auto flex flex-col gap-6 items-center justify-center min-h-screen"> |
|
| 27 | + | <a |
|
| 28 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 29 | + | target="_blank" |
|
| 30 | + | rel="noopener" |
|
| 31 | + | > |
|
| 32 | + | <img |
|
| 33 | + | src={beaver} |
|
| 34 | + | className="w-16 h-16 cursor-pointer" |
|
| 35 | + | alt="beaver logo" |
|
| 36 | + | /> |
|
| 37 | + | </a> |
|
| 38 | + | <h1 className="text-5xl font-black">bhvr</h1> |
|
| 39 | + | <h2 className="text-2xl font-bold">Bun + Hono + Vite + React</h2> |
|
| 40 | + | <p>A typesafe fullstack monorepo</p> |
|
| 41 | + | <div className="flex items-center gap-4"> |
|
| 42 | + | <button |
|
| 43 | + | type="button" |
|
| 44 | + | onClick={sendRequest} |
|
| 45 | + | className="bg-black text-white px-2.5 py-1.5 rounded-md" |
|
| 46 | + | > |
|
| 47 | + | Call API |
|
| 48 | + | </button> |
|
| 49 | + | <a |
|
| 50 | + | target="_blank" |
|
| 51 | + | href="https://bhvr.dev" |
|
| 52 | + | className="border-1 border-black text-black px-2.5 py-1.5 rounded-md" |
|
| 53 | + | rel="noopener" |
|
| 54 | + | > |
|
| 55 | + | Docs |
|
| 56 | + | </a> |
|
| 57 | + | </div> |
|
| 58 | + | {data && ( |
|
| 59 | + | <pre className="bg-gray-100 p-4 rounded-md"> |
|
| 60 | + | <code> |
|
| 61 | + | Message: {data.message} <br /> |
|
| 62 | + | Success: {data.success.toString()} |
|
| 63 | + | </code> |
|
| 64 | + | </pre> |
|
| 65 | + | )} |
|
| 66 | + | </div> |
|
| 67 | + | ); |
|
| 68 | + | } |
| 1 | + | import { createFileRoute } from "@tanstack/react-router"; |
|
| 2 | + | import { useState } from "react"; |
|
| 3 | + | import beaver from "../assets/beaver.svg"; |
|
| 4 | + | import { useMutation } from "@tanstack/react-query"; |
|
| 5 | + | import type { ApiResponse } from "shared"; |
|
| 6 | + | import "../App.css"; |
|
| 7 | + | ||
| 8 | + | export const Route = createFileRoute("/")({ |
|
| 9 | + | component: Index, |
|
| 10 | + | }); |
|
| 11 | + | ||
| 12 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 13 | + | ||
| 14 | + | function Index() { |
|
| 15 | + | const [data, setData] = useState<ApiResponse | undefined>(); |
|
| 16 | + | ||
| 17 | + | const { mutate: sendRequest } = useMutation({ |
|
| 18 | + | mutationFn: async () => { |
|
| 19 | + | const req = await fetch(`${SERVER_URL}/hello`); |
|
| 20 | + | const res: ApiResponse = await req.json(); |
|
| 21 | + | setData(res); |
|
| 22 | + | }, |
|
| 23 | + | onError: (err) => console.log(err), |
|
| 24 | + | }); |
|
| 25 | + | ||
| 26 | + | return ( |
|
| 27 | + | <> |
|
| 28 | + | <div> |
|
| 29 | + | <a |
|
| 30 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 31 | + | target="_blank" |
|
| 32 | + | rel="noopener" |
|
| 33 | + | > |
|
| 34 | + | <img src={beaver} className="logo" alt="beaver logo" /> |
|
| 35 | + | </a> |
|
| 36 | + | </div> |
|
| 37 | + | <h1>bhvr</h1> |
|
| 38 | + | <h2>Bun + Hono + Vite + React</h2> |
|
| 39 | + | <p>A typesafe fullstack monorepo</p> |
|
| 40 | + | <div className="card"> |
|
| 41 | + | <div className="button-container"> |
|
| 42 | + | <button type="button" onClick={() => sendRequest()}> |
|
| 43 | + | Call API |
|
| 44 | + | </button> |
|
| 45 | + | <a |
|
| 46 | + | className="docs-link" |
|
| 47 | + | target="_blank" |
|
| 48 | + | href="https://bhvr.dev" |
|
| 49 | + | rel="noopener" |
|
| 50 | + | > |
|
| 51 | + | Docs |
|
| 52 | + | </a> |
|
| 53 | + | </div> |
|
| 54 | + | {data && ( |
|
| 55 | + | <pre className="response"> |
|
| 56 | + | <code> |
|
| 57 | + | Message: {data.message} <br /> |
|
| 58 | + | Success: {data.success.toString()} |
|
| 59 | + | </code> |
|
| 60 | + | </pre> |
|
| 61 | + | )} |
|
| 62 | + | </div> |
|
| 63 | + | </> |
|
| 64 | + | ); |
|
| 65 | + | } |
|
| 66 | + | ||
| 67 | + | export default Index; |
| 1 | + | import { createFileRoute } from "@tanstack/react-router"; |
|
| 2 | + | import { useState } from "react"; |
|
| 3 | + | import beaver from "../assets/beaver.svg"; |
|
| 4 | + | import type { ApiResponse } from "shared"; |
|
| 5 | + | import "../App.css"; |
|
| 6 | + | ||
| 7 | + | export const Route = createFileRoute("/")({ |
|
| 8 | + | component: Index, |
|
| 9 | + | }); |
|
| 10 | + | ||
| 11 | + | const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"; |
|
| 12 | + | ||
| 13 | + | function Index() { |
|
| 14 | + | const [data, setData] = useState<ApiResponse | undefined>(); |
|
| 15 | + | ||
| 16 | + | async function sendRequest() { |
|
| 17 | + | try { |
|
| 18 | + | const req = await fetch(`${SERVER_URL}/hello`); |
|
| 19 | + | const res: ApiResponse = await req.json(); |
|
| 20 | + | setData(res); |
|
| 21 | + | } catch (error) { |
|
| 22 | + | console.log(error); |
|
| 23 | + | } |
|
| 24 | + | } |
|
| 25 | + | ||
| 26 | + | return ( |
|
| 27 | + | <> |
|
| 28 | + | <div> |
|
| 29 | + | <a |
|
| 30 | + | href="https://github.com/stevedylandev/bhvr" |
|
| 31 | + | target="_blank" |
|
| 32 | + | rel="noopener" |
|
| 33 | + | > |
|
| 34 | + | <img src={beaver} className="logo" alt="beaver logo" /> |
|
| 35 | + | </a> |
|
| 36 | + | </div> |
|
| 37 | + | <h1>bhvr</h1> |
|
| 38 | + | <h2>Bun + Hono + Vite + React</h2> |
|
| 39 | + | <p>A typesafe fullstack monorepo</p> |
|
| 40 | + | <div className="card"> |
|
| 41 | + | <div className="button-container"> |
|
| 42 | + | <button type="button" onClick={sendRequest}> |
|
| 43 | + | Call API |
|
| 44 | + | </button> |
|
| 45 | + | <a |
|
| 46 | + | className="docs-link" |
|
| 47 | + | target="_blank" |
|
| 48 | + | href="https://bhvr.dev" |
|
| 49 | + | rel="noopener" |
|
| 50 | + | > |
|
| 51 | + | Docs |
|
| 52 | + | </a> |
|
| 53 | + | </div> |
|
| 54 | + | {data && ( |
|
| 55 | + | <pre className="response"> |
|
| 56 | + | <code> |
|
| 57 | + | Message: {data.message} <br /> |
|
| 58 | + | Success: {data.success.toString()} |
|
| 59 | + | </code> |
|
| 60 | + | </pre> |
|
| 61 | + | )} |
|
| 62 | + | </div> |
|
| 63 | + | </> |
|
| 64 | + | ); |
|
| 65 | + | } |
| 1 | + | import { defineConfig } from "vite"; |
|
| 2 | + | import react from "@vitejs/plugin-react"; |
|
| 3 | + | import tailwindcss from "@tailwindcss/vite"; |
|
| 4 | + | import path from "node:path"; |
|
| 5 | + | import { tanstackRouter } from "@tanstack/router-plugin/vite"; |
|
| 6 | + | ||
| 7 | + | export default defineConfig({ |
|
| 8 | + | plugins: [ |
|
| 9 | + | // Please make sure that '@tanstack/router-plugin' is passed before '@vitejs/plugin-react' |
|
| 10 | + | tanstackRouter({ |
|
| 11 | + | target: "react", |
|
| 12 | + | autoCodeSplitting: true, |
|
| 13 | + | }), |
|
| 14 | + | react(), |
|
| 15 | + | tailwindcss(), |
|
| 16 | + | ], |
|
| 17 | + | resolve: { |
|
| 18 | + | alias: { |
|
| 19 | + | "@": path.resolve(__dirname, "./src"), |
|
| 20 | + | }, |
|
| 21 | + | }, |
|
| 22 | + | }); |
| 1 | + | import { defineConfig } from "vite"; |
|
| 2 | + | import react from "@vitejs/plugin-react"; |
|
| 3 | + | import tailwindcss from "@tailwindcss/vite"; |
|
| 4 | + | import { tanstackRouter } from "@tanstack/router-plugin/vite"; |
|
| 5 | + | ||
| 6 | + | export default defineConfig({ |
|
| 7 | + | plugins: [ |
|
| 8 | + | // Please make sure that '@tanstack/router-plugin' is passed before '@vitejs/plugin-react' |
|
| 9 | + | tanstackRouter({ |
|
| 10 | + | target: "react", |
|
| 11 | + | autoCodeSplitting: true, |
|
| 12 | + | }), |
|
| 13 | + | react(), |
|
| 14 | + | tailwindcss(), |
|
| 15 | + | ], |
|
| 16 | + | }); |
| 1 | + | import { defineConfig } from "vite"; |
|
| 2 | + | import react from "@vitejs/plugin-react"; |
|
| 3 | + | import { tanstackRouter } from "@tanstack/router-plugin/vite"; |
|
| 4 | + | ||
| 5 | + | export default defineConfig({ |
|
| 6 | + | plugins: [ |
|
| 7 | + | // Please make sure that '@tanstack/router-plugin' is passed before '@vitejs/plugin-react' |
|
| 8 | + | tanstackRouter({ |
|
| 9 | + | target: "react", |
|
| 10 | + | autoCodeSplitting: true, |
|
| 11 | + | }), |
|
| 12 | + | react(), |
|
| 13 | + | ], |
|
| 14 | + | }); |
| 14 | 14 | shadcn?: boolean; |
|
| 15 | 15 | rpc?: boolean; |
|
| 16 | 16 | linter?: "eslint" | "biome"; |
|
| 17 | + | router?: "none" | "reactrouter" | "tanstackrouter"; |
|
| 17 | 18 | tanstackQuery?: boolean; |
|
| 18 | 19 | }; |
|
| 19 | 20 |