The starter mono repo of the SSR framework, no name for it yet
Tech stack: Hono, HTMX, Tailwind CSS, Web Components, Vite
Inspo on how to build the Fullstack SSR framework: The BETH Stack, Hono's SonikJS and Deno land's Fresh
These are some pointers that I would need to look into and brake down even further as to better understand what I need to research, what problems I'm solving and what I would actually need to implement.
- How am I structuring the folders? A central App folder with a client and server folder inside it? or two folders, one server and one client?
- Routing. Do I want file based routing like SvelteKit or do I want normal routing
- How can I compile the Astro Client Directive's into a web component? Instead of doing it like this, maybe compile a JSX component to a web components so that compiles to . And how can I work with VanillaJS or Vite so that this can work? Look into this, might not be possible
- What kind of database will I need to integrate? Do I have BetterSQlite3 pre-installed or do you use Cloudflare's D1 database? Either way both can be used and reference inside Hono's bindings. See which one to use, if cloud flare is available for free then great! How would I use something like supabase or firebase for authentication on the server?
- How would I deploy this application? Fly seems to be an option but I would be required to learn more about docker which is nice but there is also a vercel adapter with Hono.
- How can I add type safety when working with this framework? type safety with html elements using htmx for example, might not be needed
- What do I do about caching? Is this some middleware I'll be creating, Hono only has one for Deno and Cloudflare
These the points I need to research futher. Keep in mind this is a opinionated fullstack application. This project is divided into two parts one for creating the package with core functionality like Island Architecture, file based routing and maybe database management, and then src folder that has the general file structure of how to use the framework.
- Research on how to provide Island architecture to web-component or client side scripting with out having to re-implement
<client-islands src="my-components" client:load></client-islands>
again.- I read something in Islands.js might need to write something with the build times or run times.
- Implement the idea I got from SonikJS. Looks a lot like my implementation of
<client-islands></client-islands>
take inspo from here and see if you can querySelectAll Web Components before they've been loaded in and then process client directives that way. Check this one out - Think of how the naming convention could affect the imports/file reads. I want the web component defined name to match the file name. A standard could be in order like naming a file part1-part2 or Part1Part2, split them and then join them. Either way a naming standard is in order it seems.
- If there is no
client:
attribute it will load as client:load - Implement the client directive.
- Research what router to use and try and implement it.
- These, 1 & 2 videos put it well into perspective, what is it that I want to solve with a file based router and how well does it play along with HTMX. The purpose of this framework is to work with HTMX and HTMX needs rest end points to shine. I could provide a controllers folder that has all the API end points but if for some reason people want CRUD operations in the same file that would pose an issue. But either way I'll provide two solutions, the controllers folder will then act as the api end point for our for both the filed based one and path based one or a combination of both.
- Do I wan't to have completed file based routing? I.e no
jsxRenderer
middleware for the layout page as I would in a page based routing project? 'cos each file is supposed to be rendered as a child inside the layout using the jsxRenderer middleware. My idea of implementing a file based routing system was to have aLayout.tsx
component to which I add in the middleware and then from there the files inside the routes folder will render as children. Because my solution is not a true file based routing system but a half-arsed one. Compared to Hono's solution they have reserved files for errors and layouts. The idea of having a reserved files do look good but I want to see how hard it would be to implement a error, not found and nested layouts for myself. If I want to created a nested layout all I need is to add another jsxRenderer middleware for that route and it's done but the process could be smoothed maybe and be a reversed file, idk yet. For the 404 Not Found page there needs to be a final get request for each page url for exampleapp.get().post().get('*', c => c.body('what?', 404))
. In regards to the error page maybe a middleware for every 500 Internal server error? But nonetheless the idea of having some reserved files is nice. The point of this is to learn about file based routing, why it's needed what problems it solves and why I would want to work with it. Since the "implementation" of a page based router is yeah... - information links: File-base routing #1277, Vite plug in, Vike
- Implement my idea of a file based routing solution where only the routes folder will act as url paths. I'll have a jsxRenderer layout root, a routes folder with all the files and then
- Use SonikJS's implementation of file based routing
- "Implement" page based routing
-
Database integration (SQLite)- How can I ensure that the db is persisted throughout the application? Do I need to create a context file that keeps track of it? Like with bindings and then call it via
c.var.db
orc.env.db
. Hono can have both bindings for cloudflare and then Variables for other things which then provides a global context. - What kind of database would I integrate and where would I host it + how well can I secure it? This could be left to the user to create their own solutions but I could also use something like Turso, I really like SQLite. I can also provide integration of Cloudflare's own SQLite db. I need to check out how they can be implemented and set up by the user. I don't want to work with ORMs, I can maybe provide support for drizzle and prisma but I don't think so, I prefer raw SQL.
- In terms of picking a database, this is for the user to decide. I'll provide two options for databases to use and a third one with the folder empty so that the user can pick what they want.
- How can I ensure that the db is persisted throughout the application? Do I need to create a context file that keeps track of it? Like with bindings and then call it via
- How do I create a CLI or npm package so that people can create their projects.
- Project name ofc
- Pick filed based routing yes or no
- Pick a db cloud flare, turso or nothing.
- Type safety when working with HTML elements using htmx
- I actually found this when checking out the BETH stack, might add some improvements to this when adding dynamic.
- If I want to have end points inside filed based routing I would need to account for those types as well.
- T3.gg config maybe? Easier to work with instead of having a bunch of process.ENV that aren't type safe.
- Database integration (SQLite)
- See of the DX would with drizzle
- Implement bare bones Turso with LibSQLite and node
- Integrate-ish Cloudflare with node
- No database option, leave it to the user
- Vite config for building the web components i.e production vs development
- Deployment
- Docker with vite?
- Cloudflare workers, I need to check this.
- Vercel using hono adapter
- [ ] Stuff needed to understand and use the package. At a later date...
Display of how the file structure could look like based on what type of routing is used File based routing:
.
├── app
│ ├── client.ts // client entry file
│ ├── Island.ts // Astro Client Directives web component
│ ├── islands
│ │ └── counter.ts // island component
│ ├── components // reusable components
│ │ ├── Button.tsx
│ │ └── Navbar.tsx
│ ├── routes
│ │ ├── _404.tsx // not found page
│ │ ├── _error.tsx // error page
│ │ ├── _layout.tsx // layout template
│ │ ├── about
│ │ │ └── [name].tsx // matches `/about/:name`
│ │ └── index.tsx // matches `/`
│ ├── controllers // api controllers.
│ │ └── login.tsx // login api controller
│ └── server.ts // server entry file
├── package.json
├── public
│ └── favicon.ico
├── tsconfig.json
└── vite.config.ts
Normal routing:
.
├── app
│ ├── client //All client side scripting files
│ │ ├── client.ts // client entry file
│ │ ├── Island.ts // Astro Client Directives (Subject to change)
│ │ └── islands
│ │ └── counter.ts // web components
│ └── server
│ ├── components //Common reusable component
│ │ ├── Button.tsx
│ │ └── Navbar.tsx
│ ├── controllers // api controllers.
│ │ └── login.tsx // login api controller
│ ├── pages // each page would be represented as it's own route end point along with it's own HTMX operations + Web components
│ │ ├── _404.tsx // not found page
│ │ ├── _error.tsx // error page
│ │ ├── _layout.tsx // layout template for JSXRender
│ │ ├── about.tsx // matches `/about/:name` and renders a html file that way
│ │ └── index.tsx // this would have the `/` end point for example i.e our homepage
│ └── server.tsx // server entry file with endpoint for each page
├── package.json
├── public
│ └── favicon.ico
├── tsconfig.json
└── vite.config.ts
This is dependent on how well I implement the idea for my client directives!
Updated File based routing:
.
├── app
│ ├── client.ts // client entry file
│ ├── islands
│ │ └── counter.ts // island component
│ ├── config // T3.gg config schema using zod
│ ├── components // reusable components
│ │ ├── Button.tsx
│ │ └── Navbar.tsx
│ ├── routes
│ │ ├── _404.tsx // not found page
│ │ ├── _error.tsx // error page
│ │ ├── _layout.tsx // layout template
│ │ ├── about
│ │ │ └── [name].tsx // matches `/about/:name`
│ │ └── index.tsx // matches `/`
│ ├── controllers // api controllers.
│ │ └── login.tsx // login api controller
│ └── server.ts // server entry file
├── package.json
├── public
│ └── favicon.ico
├── tsconfig.json
└── vite.config.ts
Updated Normal routing:
.
├── app
│ ├── client.ts // client entry file
│ ├── islands // depending on how well the implementation of client directive goes
│ │ └── counter.ts // island component
│ ├── components //Common reusable component
│ │ ├── Button.tsx
│ │ └── Navbar.tsx
│ ├── controllers // api controllers.
│ │ ├── *.ts // collected routes as a final export
│ │ └── login.tsx // login api controller
│ ├── db // database
│ ├── pages // each page would be represented as it's own route end point along with it's own HTMX operations + Web components
│ │ ├── _404.tsx // not found page
│ │ ├── _error.tsx // error page
│ │ ├── _layout.tsx // layout template for JSXRender
│ │ ├── about.tsx // matches `/about/:name` and renders a html file that way
│ │ └── index.tsx // this would have the `/` end point for example i.e our homepage
│ └── server.tsx // server entry file with endpoint for each page
├── package.json
├── public
│ └── favicon.ico
├── tsconfig.json
└── vite.config.ts