Compare commits
No commits in common. "06af1be66637390500db8c61b8db174fc2d57788" and "c7a3af96f7f4d15d74ed58ec75b57a9c4de49256" have entirely different histories.
06af1be666
...
c7a3af96f7
@ -10,5 +10,7 @@ RUN bun install --frozen-lockfile
|
|||||||
COPY ./src ./src
|
COPY ./src ./src
|
||||||
COPY ./posts ./posts
|
COPY ./posts ./posts
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
USER bun
|
USER bun
|
||||||
CMD [ "bun", "src/index.tsx" ]
|
CMD [ "bun", "src/index.tsx" ]
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
---
|
---
|
||||||
title: Adventures with Bun and Hono
|
title: Adventures with Bun and Hono
|
||||||
description: A blog post wherein I talk about building this blog with Bun and Hono.
|
description: A blog post wherein I talk about building this blog with Bun and Hono.
|
||||||
date: 2024-08-11
|
date: 2024-08-01
|
||||||
tags:
|
tags:
|
||||||
- development
|
- development
|
||||||
- javascript
|
- javascript
|
||||||
- typescript
|
|
||||||
- bun
|
- bun
|
||||||
- hono
|
- hono
|
||||||
slug: fullstack-hono
|
slug: fullstack-hono
|
||||||
|
draft: true
|
||||||
---
|
---
|
||||||
|
|
||||||
## Context and My Blog
|
## Context and My Blog
|
||||||
@ -223,26 +223,4 @@ sudo certbot revoke --cert-name davesmithhayes.com
|
|||||||
|
|
||||||
At this time Let's Encrypt had rate-limited my many, many failed attempts to get a new certificate for my own domain. Time to wait it out. An hour to be exact.
|
At this time Let's Encrypt had rate-limited my many, many failed attempts to get a new certificate for my own domain. Time to wait it out. An hour to be exact.
|
||||||
|
|
||||||
So, instead of actually waiting an hour I went to bed and waited for a few days to get back to work. I knew I had previously deployed a really basic Node.js application with Dokku, hence why I decided to keep using it as a platform to deploy applications on.
|
|
||||||
|
|
||||||
I realized that application was running, by default, on port `3000` and I think Dokku is expecting all the applications to run on `5000` by default. I can't seem to find any documentation on that but the moment I removed the following line from the `Dockerfile`:
|
|
||||||
|
|
||||||
```dockerfile
|
|
||||||
EXPOSE 3000
|
|
||||||
```
|
|
||||||
|
|
||||||
And set the application environment required an update to the `APP_PORT` envvar that I run the application on.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
dokku config:set davesmithhayes.com APP_PORT=5000
|
|
||||||
```
|
|
||||||
|
|
||||||
_et voila_! Now I could set up certificates with Let's Encrypt and we are good to go.
|
|
||||||
|
|
||||||
## Conclusions
|
|
||||||
|
|
||||||
Its been a long time since I started and _finished_ a software project, on my time, and I am happy with. Using Hono and Bun, two technologies I am adjacently familiar with, was also a huge plus to me. I enjoyed it so much that I think this PHP project I have been hobbling together for the last couple of months will get a complete rewrite in TypeScript using Hono and Bun.
|
|
||||||
|
|
||||||
I really hope that you read this far and took something away about how to do projects on your own, how viable these technologies are, and how to have fun doing basic things. I don't think this blog would have required as much work as I had put into it, but I am happy that I did. Please [feel free to contact me](mailto:me@davesmithhayes.com) about my Bun and Hono experience.
|
|
||||||
|
|
||||||
That's it. I'm a convert. Praise Bun.
|
|
||||||
|
@ -1,83 +0,0 @@
|
|||||||
---
|
|
||||||
title: HS(D)P
|
|
||||||
description: Describing the architecture of Handlers, Services, (Domains), and Presentation
|
|
||||||
date: 2024-08-11
|
|
||||||
tags:
|
|
||||||
- development
|
|
||||||
- javascript
|
|
||||||
- typescript
|
|
||||||
- hono
|
|
||||||
slug: hsdp
|
|
||||||
draft: true
|
|
||||||
---
|
|
||||||
|
|
||||||
## Handlers, Services, (Domains?), Presentation
|
|
||||||
|
|
||||||
In [my last blog post](https://davesmithhayes.com/posts/fullstack-hono) I talked about how I have stopped thinking of my Node.js applications as Model-View-Controller and started thinking of the applications in a new, fun acronym: Handlers, Services, (_sometimes Domains_), and Prfesentation. I thought this would be a good topic for a new blog post. So here it is.
|
|
||||||
|
|
||||||
I am going to be talking about this pattern in relationship to JavaScript and why the language lends itself to the pattern when working on applications.
|
|
||||||
|
|
||||||
## The Application
|
|
||||||
|
|
||||||
Like the previous post, I talked about building this blog with Bun and Hono. I am going to do the same here, however the application we are going to build is the all time classic - The TODO Application.
|
|
||||||
|
|
||||||
## JavaScript
|
|
||||||
|
|
||||||
One of the important things about JavaScript that alluded me for far too long was how the modules actually worked with Node.js. A module before ES6 was simply a JavaScript file that declares a `module.exports` value with the code you want to expose to other modules with the `require` function. Like so:
|
|
||||||
|
|
||||||
```js
|
|
||||||
function doSomething() {
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = doSomething;
|
|
||||||
```
|
|
||||||
_`example.js`_
|
|
||||||
|
|
||||||
Then we can pull in `doSomething` with `require`:
|
|
||||||
|
|
||||||
```js
|
|
||||||
const doSomething = require('./example');
|
|
||||||
```
|
|
||||||
_`index.js`_
|
|
||||||
|
|
||||||
I don't know why I didn't know this, but the code in the `example.js` file is evaluated **and** run during the `require()` call.
|
|
||||||
|
|
||||||
In my past life I would try and build a Singleton class for holding onto an application's Connection Pool to a database. But because of how the Modules in Node.js work, we only need to instantiate the Pool and export it. Here's an example of how we can set up a single pool using the MariaDB official package:
|
|
||||||
|
|
||||||
```js
|
|
||||||
const mariadb = require('mariadb');
|
|
||||||
|
|
||||||
const config = { ... };
|
|
||||||
const pool = mariadb.createPool(config);
|
|
||||||
|
|
||||||
module.eports = pool;
|
|
||||||
```
|
|
||||||
_`pool.js`_
|
|
||||||
|
|
||||||
Now the connection pool is only created once and you can require this
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Outline:
|
|
||||||
|
|
||||||
* Explain what I know about JavaScript
|
|
||||||
* How does this differ to my experience with PHP
|
|
||||||
* Describe modules
|
|
||||||
* Describe how we can set up singletons thinking in modules
|
|
||||||
* Talk about avoiding classes
|
|
||||||
* Talk about big express applications
|
|
||||||
* And how I used to make MVC applications
|
|
||||||
|
|
||||||
Different programming languages require different approaches for organizing code.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -29,8 +29,3 @@ pre code.hljs {
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
background-color: #fafafa;
|
background-color: #fafafa;
|
||||||
}
|
}
|
||||||
|
|
||||||
main .post-meta {
|
|
||||||
font-style: italic;
|
|
||||||
font-size: 12pt;
|
|
||||||
}
|
|
||||||
|
@ -23,7 +23,6 @@ app.get("/", async (c) => {
|
|||||||
return c.render(<Home posts={postList} />, {
|
return c.render(<Home posts={postList} />, {
|
||||||
meta: {
|
meta: {
|
||||||
description: "The blog for Dave Smith-Hayes, a dad and developer.",
|
description: "The blog for Dave Smith-Hayes, a dad and developer.",
|
||||||
mastodonUrl: "https://hachyderm.io/@davesh"
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -24,7 +24,6 @@ export async function handleSinglePost(c: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const meta: SiteMeta = {
|
const meta: SiteMeta = {
|
||||||
title: post.meta.title,
|
|
||||||
description: post.meta.description,
|
description: post.meta.description,
|
||||||
tags: post.meta.tags,
|
tags: post.meta.tags,
|
||||||
author: "Dave Smith-Hayes"
|
author: "Dave Smith-Hayes"
|
||||||
|
@ -3,6 +3,4 @@ export type SiteMeta = {
|
|||||||
tags?: string[],
|
tags?: string[],
|
||||||
author?: string,
|
author?: string,
|
||||||
viewport?: string,
|
viewport?: string,
|
||||||
title?: string,
|
|
||||||
mastodonUrl?: string
|
|
||||||
};
|
};
|
||||||
|
@ -2,20 +2,13 @@ import { Style } from 'hono/css';
|
|||||||
import { SiteMeta } from '@blog/models/SiteMeta';
|
import { SiteMeta } from '@blog/models/SiteMeta';
|
||||||
import { MetaTags } from '@blog/templates/components/MetaTags';
|
import { MetaTags } from '@blog/templates/components/MetaTags';
|
||||||
|
|
||||||
function getPageTitle(title: string|undefined): string {
|
|
||||||
if (!title) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
return title + " - ";
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Page({ children, meta }: { children: any, meta: SiteMeta }) {
|
export function Page({ children, meta }: { children: any, meta: SiteMeta }) {
|
||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>{ getPageTitle(meta.title) }davesmithhayes.com</title>
|
<title>davesmithhayes.com</title>
|
||||||
<MetaTags meta={meta} />
|
<MetaTags meta={meta} />
|
||||||
|
<Style />
|
||||||
<link rel="stylesheet" href="/static/main.css" />
|
<link rel="stylesheet" href="/static/main.css" />
|
||||||
<link rel="stylesheet" href="/static/intellij-light.min.css" />
|
<link rel="stylesheet" href="/static/intellij-light.min.css" />
|
||||||
</head>
|
</head>
|
||||||
|
@ -1,15 +1,10 @@
|
|||||||
import { Post } from "@blog/models/Post";
|
import { Post } from "@blog/models/Post";
|
||||||
|
|
||||||
export function parseDate(date: Date): string {
|
|
||||||
return date.toISOString().slice(0,10);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function PostPage({ post }: { post: Post }) {
|
export function PostPage({ post }: { post: Post }) {
|
||||||
const html = { __html: post.html ?? '' };
|
const html = { __html: post.html ?? '' };
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h1>{post.meta.title}</h1>
|
<h1>{post.meta.title}</h1>
|
||||||
<div class="post-meta">Posted on {parseDate(post.meta.date)}</div>
|
|
||||||
<div class="post-content" dangerouslySetInnerHTML={html} />
|
<div class="post-content" dangerouslySetInnerHTML={html} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -36,16 +36,6 @@ export function ViewPort({ meta }: { meta: SiteMeta }) {
|
|||||||
return (<meta name="viewport" content={meta.viewport} />);
|
return (<meta name="viewport" content={meta.viewport} />);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MeRel({ meta }: { meta: SiteMeta }) {
|
|
||||||
if (!meta?.mastodonUrl) {
|
|
||||||
return (
|
|
||||||
<></>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (<link rel="me" href={meta.mastodonUrl} />);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function MetaTags({ meta }: { meta: SiteMeta }) {
|
export function MetaTags({ meta }: { meta: SiteMeta }) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -53,7 +43,6 @@ export function MetaTags({ meta }: { meta: SiteMeta }) {
|
|||||||
<Tags meta={meta} />
|
<Tags meta={meta} />
|
||||||
<Author meta={meta} />
|
<Author meta={meta} />
|
||||||
<ViewPort meta={meta} />
|
<ViewPort meta={meta} />
|
||||||
<MeRel meta={meta} />
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user