Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/blankeos/realtime-user-status
Quick demo on a making realtime user status with timer.
https://github.com/blankeos/realtime-user-status
Last synced: 4 days ago
JSON representation
Quick demo on a making realtime user status with timer.
- Host: GitHub
- URL: https://github.com/blankeos/realtime-user-status
- Owner: Blankeos
- Created: 2024-06-20T22:28:16.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2024-08-04T18:20:35.000Z (3 months ago)
- Last Synced: 2024-08-05T18:53:10.647Z (3 months ago)
- Language: TypeScript
- Size: 857 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Realtime User Status Change
![alt text](docs/preview.png)
**Feature Demonstrations**
- [x] Auth
- [x] Image change
- [x] Last Status Updated with Timer
- [x] Realtime pubsub with websockets
- [x] HMR using a custom `vite.middlewares` + `connectToWeb`.
- [x] Watch with Nodemon (bun run --watch is broken because it conflicts with Vite's `createServer`)**Notable Stack**
- Hono
- tRPC (subscriptions)
- Bun (websockets)**Used**
- Hono and Bun Websocket Upgrading to 101 Switching Protocol: https://hono.dev/docs/helpers/websocket
- Bun Websocket Handling the tRPC router: https://github.com/cah4a/trpc-bun-adapter---
Bootstrapped with:
## ๐ Solid Launch
> An sophisticated boiler-plate built for **simplicity**.
![Image](https://assets.solidjs.com/banner?type=Starter%20Kit&background=tiles&project=Solid%20Launch)
[Carlo](https://carlo.vercel.app/)'s starter for making a Vike + Solid app with batteries included on stuff I like after experimenting for years.
This is handcrafted from my own research. This might not work for you, but it works for me. ๐ค
Alternatively:
- [๐ Solid Hop](https://github.com/blankeos/solid-hop) - Less-opinionated Vike Solid boilerplate. Like `npx create solid` but simpler.
- [๐งก Svelte Launch](https://github.com/blankeos/svelte-launch) - Svelte, but same robust practices.### Benefits
- [x] ๐ญ **Handcrafted and minimal** - picked and chose "do one thing, do it well" libraries that are just enough to get the job done. Just looks a bit bloated at a glance. (I kinda made my own NextJS from scatch here)
- [x] โก๏ธ **Super-fast dev server** - way faster than NextJS thanks to Vite. You need to feel it to believe it! It can also literally build your app in seconds.
- [x] ๐จ **Fast, efficient, fine-grained Reactivity** - thanks to Solid, it's possibly the most enjoyable framework I used that uses JSX. Has state management primitives out-of-the-box and keeps the experience a breeze.
- [x] ๐ **Extremely customizable** - you're not at the mercy of limited APIs and paradigms set by big frameworks or third-party services. Swap with your preferred JS backend framework/runtime if you want. Vike is just a middleware. Most of the tech I use here are open-source and roll-your-own type of thing. Hack it up! You're a dev aren't you?
- [x] โ๏ธ **Selfhost-ready** - Crafted with simple hosting in mind that'll still probably scale to millions. Just spin up Docker container on a good'ol VPS without locking into serverless. DHH and Shayan influenced me on this. You can still host it on serverless tho. I think? lol
- [x] **๐ Batteries-included** - took care of the hard stuff for you. A well-thought-out folder structure from years of making projects: a design system, components, utilities, hooks, constants, an adequate backend DDD-inspired sliced architecture that isn't overkill, dockerizing your app, and most importantly---perfectly-crafted those pesky config files.### Tech Stack
- [x] **Bun** - Runtime and package manager. You can always switch to Node and PNPM if you wish.
- [x] **SolidJS** - Frontend framework that I like. Pretty underrated, but awesome!
- [x] **Vike** - Like NextJS, but just a middleware. SSR library on-top of Vite. Use on any JS backend. Flexible, Simple, and Fast!
- [x] **Hono** - 2nd fastest Bun framework(?), run anywhere, uses easy-to-understand web-standard paradigms.
- [x] **tRPC** - E2E typesafety without context switching. Just amazing DevX.
- [x] **Tailwind** - Styling the web has been pretty pleasant with it. I even use it on React Native for work. It's amazing.
- [x] **Prisma** - Great _migrations_ workflow, but I want to maximize perf.
- [x] **Kysely** - Great typesafe _query builder_ for SQL, minimally wraps around db connection.
- [x] **SQLite/LibSQL (Turso)** - Cheapest database, easy to use.
- [x] **Lucia** - Makes self-rolling auth easy.
- [ ] **SES or MimePost** - Emails
- [ ] **Backblaze** - Cheap blob object storage with an S3-compatible API.
- [ ] **Stripe, Payrex, or Xendit** - Accept payments.> You can also easily swap the database if you want.
>
> - [ ] **Postgres** - powerful relational DB. (TBD)
> - [ ] **CockroachDB** - serverless database. (TBD)
> - [ ] **MongoDB** - cheap easy to use database. (TBD)### QuickStart
I'll assume you don't want to change anything with this setup after cloning so let's get to work!
1. Copy the environment variables
```sh
cp .env.example .env
```2. Replace the `` in the local database with:
```sh
pwd # If it outputs: /User/Projects/solid-launch# Replace the .env with:
DATABASE_URL="file:/User/Projects/solid-launch/local.db"
```3. Generate
```sh
bun db:generate # generates Kysely and Prisma client types.
bun db:migrate # migrates your database.
```4. Install deps and run dev
```sh
bun install
bun dev
```### Useful Development Tips
I took care of the painstaking parts to help you develop easily on a SPA + SSR + backend paradigm. You can take take these practices to different projects as well.
1. Make use of the `code-snippets` I added. It'll help!
2. Check all typescript errors (`Cmd` + `Shift` + `B` > `tsc:watch tsconfig.json`).
3. Authentication Practices - I have these out-of-the-box for you so you won't have to build it.- Getting Current User
```ts
import { useAuthContext } from '@/context/auth.context';export default function MyComponent() {
const { user } = useAuthContext();
}
```- Login, Logout, Register
```tsx
import { useAuthContext } from '@/context/auth.context';export default function MyComponent() {
const { login, logout, register } = useAuthContext();
}
```- Hydrating Current User
This will also automatically hydrate in your layouts. Anywhere you use `useAuthStore()`, it's magic. (Thanks to Vike's `useData()`. Fun fact: You actually can't do this in SolidStart because it's architecturally different to Vike).
```tsx
// +data.ts
import { initTRPCSSRClient } from '@/lib/trpc-ssr-client';
import { PageContext } from 'vike/types';export type Data = ReturnType>;
export async function data(pageContext: PageContext) {
const { request, response } = pageContext;const trpcClient = initTRPCSSRClient(request.header(), response.headers); // Pass the headers here.
const result = await trpcClient.currentUser.query();
return {
user: result.user ?? null,
};
}
```- Protecting Routes (Client-Side)
```tsx
import ProtectedRoute from '@/components/common/protected-route';export default MyComponent() {
return (
On the server (hydration), this part will not be rendered if unauthenticated.On the client, you will be redirected to a public route if unauthenticated.
)
}
```- Protecting Routes (SSR)
```ts
// +guard.ts (If you don't have +data.ts in the same route).
export async function guard(pageContext: PageContext) {
const { request, response } = pageContext;const trpcClient = initTRPCSSRClient(request.header(), response.headers); // Pass the headers here.
const result = await trpcClient.currentUser.query();
if (!result.user) {
throw redirect("/") // Must be a public route.
}
}// +guard.ts (If you already have a +data.ts that gets the user).
// โ ๏ธ I have not tested this. This depends on `+guard` being called after `+data` is resolved.
export async function guard(pageContext: PageContext) {if (!pageContext.data?.user) {
throw redirect("/"); // Must be a public route.
}
}
```4. Dataloading Practices - Also have these out-of-the-box for most usecases since they're tricky to do if you're clueless:
- Tanstack Query (Client-only) - Use `trpc-client.ts`
- Hydrated Tanstack Query (SSR) - Use `create-dehydrated-state.ts` + `trpc-ssr-client.ts`### Backend Architecture
My backend architecture is inspired by DDD where I separate in layers, but I keep it pragmatic by not going too overkill with Entities, Domains, and Aggregates. I personally still like the anemic data-driven architecture for most of my apps since the
apps I make aren't too business-logic-heavy.```sh
.
โโโ server/ # - root
โโโ dao/ # - data-access-objects
โ โโโ *.dao.ts
โโโ modules/
โ โโโ /
โ โโโ services/
โ โ โโโ *.service.ts # 1 service usecase
โ โโโ .controller.ts
โโโ _app.ts # - root TRPC router.
```- **`dao`** - abstracted away all queries here to interface with them as plain functions. It actually helps me mentally collocate db queries from service logic when I'm using them inside the service.
- **`modules`** - a vertical slice of each module-group. This just depends on how I feel about grouping them. You get better overtime.
- **`.controller.ts`** - pretty much a group of http endpoints. I can put the DTOs/Validations for each endpoint here without context-switching.
- **`services`** - these are even smaller pieces of logic that can be used inside each endpoint. It's not necessary to use if the app isn't too big, but it helps.
- **`_app.ts`** - The root trpc router where the `AppRouter` type is exported.### Deployment
> [!WARNING]
>
> Still in progressHere are some guides on how to deploy.
- [ ] Kamal (self-host VPS - I recommend)
- [ ] Dokku (self-host VPS)
- [ ] Caprover (self-host VPS)
- [ ] Cloudflare (serverless + static)
- [ ] Vercel (serverless + static)
- [ ] Netlify (static)### Future Plans
> I'll probably make a swapping guide soon. To replace to these:
>
> - Runtime: Bun -> Node
> - Package Manager: Bun -> PNPM
> - ORM: Prisma -> Drizzle
> - Database: SQLite -> PostgreSQL, CockroachDB, MongoDB