Replace Elysia with bun.serve for hot reloading and static serving
This commit is contained in:
parent
b136c6e63a
commit
cd88f570a0
24
bun.lock
24
bun.lock
@ -7,6 +7,8 @@
|
||||
"@elysiajs/html": "1.4.0",
|
||||
"@elysiajs/static": "1.4.4",
|
||||
"elysia": "^1.4.11",
|
||||
"gray-matter": "^4.0.3",
|
||||
"marked": "^16.4.1",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "^1.3.0",
|
||||
@ -40,6 +42,8 @@
|
||||
|
||||
"ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
|
||||
|
||||
"argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="],
|
||||
|
||||
"bun-types": ["bun-types@1.3.0", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-u8X0thhx+yJ0KmkxuEo9HAtdfgCBaM/aI9K90VQcQioAmkVp3SG3FkwWGibUFz3WdXAdcsqOcbU40lK7tbHdkQ=="],
|
||||
|
||||
"chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
|
||||
@ -58,8 +62,12 @@
|
||||
|
||||
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
||||
|
||||
"esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="],
|
||||
|
||||
"exact-mirror": ["exact-mirror@0.2.2", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-CrGe+4QzHZlnrXZVlo/WbUZ4qQZq8C0uATQVGVgXIrNXgHDBBNFD1VRfssRA2C9t3RYvh3MadZSdg2Wy7HBoQA=="],
|
||||
|
||||
"extend-shallow": ["extend-shallow@2.0.1", "", { "dependencies": { "is-extendable": "^0.1.0" } }, "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug=="],
|
||||
|
||||
"fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="],
|
||||
|
||||
"fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="],
|
||||
@ -70,16 +78,32 @@
|
||||
|
||||
"get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="],
|
||||
|
||||
"gray-matter": ["gray-matter@4.0.3", "", { "dependencies": { "js-yaml": "^3.13.1", "kind-of": "^6.0.2", "section-matter": "^1.0.0", "strip-bom-string": "^1.0.0" } }, "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q=="],
|
||||
|
||||
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
|
||||
|
||||
"is-extendable": ["is-extendable@0.1.1", "", {}, "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="],
|
||||
|
||||
"js-yaml": ["js-yaml@3.14.1", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g=="],
|
||||
|
||||
"kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="],
|
||||
|
||||
"marked": ["marked@16.4.1", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-ntROs7RaN3EvWfy3EZi14H4YxmT6A5YvywfhO+0pm+cH/dnSQRmdAmoFIc3B9aiwTehyk7pESH4ofyBY+V5hZg=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
|
||||
|
||||
"section-matter": ["section-matter@1.0.0", "", { "dependencies": { "extend-shallow": "^2.0.1", "kind-of": "^6.0.0" } }, "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA=="],
|
||||
|
||||
"sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="],
|
||||
|
||||
"string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
|
||||
|
||||
"strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="],
|
||||
|
||||
"strip-bom-string": ["strip-bom-string@1.0.0", "", {}, "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g=="],
|
||||
|
||||
"strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="],
|
||||
|
||||
"token-types": ["token-types@6.1.1", "", { "dependencies": { "@borewit/text-codec": "^0.1.0", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-kh9LVIWH5CnL63Ipf0jhlBIy0UsrMj/NJDfpsy1SqOXlLKEVyXXYrnFxFT1yOOYVGBSApeVnjPw/sBz5BfEjAQ=="],
|
||||
|
||||
19
bun_plugins/markdown-loader.ts
Normal file
19
bun_plugins/markdown-loader.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import type {BunPlugin} from 'bun';
|
||||
import { marked } from 'marked';
|
||||
|
||||
const markdownLoader: BunPlugin = {
|
||||
name: 'markdown-loader',
|
||||
setup(build) {
|
||||
// Plugin implementation
|
||||
build.onLoad({filter: /\.md$/}, async args => {
|
||||
const text = await Bun.file(args.path).text();
|
||||
const html = marked.parse(text);
|
||||
return {
|
||||
contents: `export default ${html};`,
|
||||
loader: 'html',
|
||||
};
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default markdownLoader;
|
||||
2
bunfig.toml
Normal file
2
bunfig.toml
Normal file
@ -0,0 +1,2 @@
|
||||
[serve.static]
|
||||
plugins = ["./bun_plugins/markdown-loader.ts"]
|
||||
34
content/.template.md
Normal file
34
content/.template.md
Normal file
@ -0,0 +1,34 @@
|
||||
---
|
||||
title: Your Post Title
|
||||
date: 2025-10-21
|
||||
tags: [Web Development, TypeScript]
|
||||
excerpt: A brief summary of your post (2-3 sentences). This will appear in post listings and search results.
|
||||
draft: false
|
||||
---
|
||||
|
||||
# Your Post Title
|
||||
|
||||
Your content here. You can use standard markdown syntax:
|
||||
|
||||
## Section Heading
|
||||
|
||||
Write your paragraphs with proper spacing.
|
||||
|
||||
### Subsection
|
||||
|
||||
- Bullet points
|
||||
- Another point
|
||||
- And another
|
||||
|
||||
**Bold text** and *italic text* are supported.
|
||||
|
||||
```typescript
|
||||
// Code blocks work too
|
||||
const example = "Hello World";
|
||||
console.log(example);
|
||||
```
|
||||
|
||||
> Blockquotes for important callouts or quotes.
|
||||
|
||||
This is just a template - delete this file or ignore it when writing your actual posts.
|
||||
|
||||
93
content/2024/12/year-in-review.md
Normal file
93
content/2024/12/year-in-review.md
Normal file
@ -0,0 +1,93 @@
|
||||
---
|
||||
title: 2024 Year in Review
|
||||
date: 2024-12-28
|
||||
tags: [Career, Productivity]
|
||||
excerpt: Reflecting on 2024 - the projects I built, lessons I learned, and goals for 2025. A year of growth, challenges, and accomplishments.
|
||||
draft: false
|
||||
---
|
||||
|
||||
# 2024 Year in Review!
|
||||
|
||||
As 2024 comes to a close, I wanted to take some time to reflect on the year. It's been a year of significant growth, both professionally and personally.
|
||||
|
||||
## Professional Highlights
|
||||
|
||||
### Projects
|
||||
|
||||
This year, I worked on several exciting projects:
|
||||
|
||||
**E-commerce Platform**: Led the frontend architecture for a new e-commerce platform serving 100k+ daily users. We achieved a 40% improvement in page load times through careful optimization.
|
||||
|
||||
**Design System**: Built a comprehensive design system from scratch, complete with documentation and Storybook. This is now used across 5 different products.
|
||||
|
||||
**Open Source**: Made my first significant open source contributions! Contributed to several Bun-related projects and created a few small utilities that others found useful.
|
||||
|
||||
### Skills Developed
|
||||
|
||||
- **Performance Optimization**: Learned a ton about web performance, Core Web Vitals, and how to actually make sites fast
|
||||
- **System Design**: Started thinking more about architecture and scalability
|
||||
- **TypeScript**: Became much more proficient with advanced TypeScript patterns
|
||||
- **Testing**: Finally built a solid testing practice
|
||||
|
||||
## Personal Growth
|
||||
|
||||
### Writing
|
||||
|
||||
Started this blog! Writing has helped me:
|
||||
- Clarify my thinking
|
||||
- Learn more deeply
|
||||
- Connect with others in the community
|
||||
|
||||
### Work-Life Balance
|
||||
|
||||
Made a conscious effort to improve work-life balance:
|
||||
- Implemented a hard stop at 6 PM
|
||||
- Started exercising regularly (3x per week)
|
||||
- Picked up reading again (finished 12 books!)
|
||||
|
||||
## Challenges
|
||||
|
||||
Not everything was smooth sailing:
|
||||
|
||||
**Burnout**: Hit a rough patch in Q2 where I was working too much. Learned the importance of rest and boundaries.
|
||||
|
||||
**Imposter Syndrome**: Still struggles with this occasionally, but getting better at recognizing it and pushing through.
|
||||
|
||||
**Saying No**: Learned that saying no to some opportunities is necessary to say yes to the right ones.
|
||||
|
||||
## Lessons Learned
|
||||
|
||||
1. **Quality > Quantity**: Better to do fewer things well than many things poorly
|
||||
2. **Ask for Help**: Nobody knows everything, and asking for help is a strength
|
||||
3. **Document Everything**: Future you will thank present you
|
||||
4. **Take Breaks**: Rest isn't laziness - it's necessary for sustained performance
|
||||
5. **Community Matters**: Connecting with other developers has been invaluable
|
||||
|
||||
## Goals for 2025
|
||||
|
||||
Looking ahead to 2025:
|
||||
|
||||
### Professional
|
||||
- Contribute to a major open source project
|
||||
- Speak at a local meetup or conference
|
||||
- Learn Rust (for real this time)
|
||||
- Build and launch a side project
|
||||
|
||||
### Personal
|
||||
- Write 24 blog posts (2 per month)
|
||||
- Read 20 books
|
||||
- Maintain exercise routine
|
||||
- Learn to cook 10 new recipes
|
||||
|
||||
### Learning
|
||||
- Deep dive into system design
|
||||
- Master web performance
|
||||
- Learn more about databases
|
||||
- Get better at writing
|
||||
|
||||
## Thank You
|
||||
|
||||
Thanks to everyone who supported me this year - colleagues, friends, family, and the online tech community. Looking forward to 2025!
|
||||
|
||||
What were your highlights from 2024? What are you looking forward to in 2025?
|
||||
|
||||
108
content/2025/09/typescript-tips.md
Normal file
108
content/2025/09/typescript-tips.md
Normal file
@ -0,0 +1,108 @@
|
||||
---
|
||||
title: 5 TypeScript Tips I Wish I Knew Earlier
|
||||
date: 2025-09-18
|
||||
tags: [TypeScript, JavaScript, Productivity]
|
||||
excerpt: Five practical TypeScript tips that will make your code more type-safe and your development experience smoother. From utility types to const assertions.
|
||||
draft: false
|
||||
---
|
||||
|
||||
# 5 TypeScript Tips I Wish I Knew Earlier
|
||||
|
||||
TypeScript is an amazing tool, but it takes time to learn all its features. Here are five tips that significantly improved my TypeScript development.
|
||||
|
||||
## 1. Use `satisfies` for Type Checking
|
||||
|
||||
The `satisfies` keyword (added in TS 4.9) lets you validate that a value matches a type without widening its type:
|
||||
|
||||
```typescript
|
||||
type RGB = { r: number; g: number; b: number };
|
||||
|
||||
// Before: Type is widened to RGB
|
||||
const color: RGB = { r: 255, g: 0, b: 0 };
|
||||
|
||||
// After: Type is preserved as literal values
|
||||
const color = { r: 255, g: 0, b: 0 } satisfies RGB;
|
||||
```
|
||||
|
||||
This is especially useful when you want both type safety and precise types.
|
||||
|
||||
## 2. Const Assertions
|
||||
|
||||
Adding `as const` to an object or array makes all properties readonly and infers literal types:
|
||||
|
||||
```typescript
|
||||
// Regular array: type is string[]
|
||||
const fruits = ['apple', 'banana'];
|
||||
|
||||
// With const assertion: type is readonly ['apple', 'banana']
|
||||
const fruits = ['apple', 'banana'] as const;
|
||||
```
|
||||
|
||||
This is perfect for configuration objects and enum-like values.
|
||||
|
||||
## 3. Utility Type: `Awaited<T>`
|
||||
|
||||
Need to get the resolved type of a Promise? Use `Awaited`:
|
||||
|
||||
```typescript
|
||||
async function fetchUser() {
|
||||
return { id: 1, name: 'Alice' };
|
||||
}
|
||||
|
||||
// Gets the return type without the Promise wrapper
|
||||
type User = Awaited<ReturnType<typeof fetchUser>>;
|
||||
// User is { id: number; name: string }
|
||||
```
|
||||
|
||||
## 4. Template Literal Types
|
||||
|
||||
Create types based on string patterns:
|
||||
|
||||
```typescript
|
||||
type EventName = 'click' | 'focus' | 'blur';
|
||||
type EventHandler = `on${Capitalize<EventName>}`;
|
||||
// Result: 'onClick' | 'onFocus' | 'onBlur'
|
||||
```
|
||||
|
||||
This is incredibly powerful for creating type-safe APIs.
|
||||
|
||||
## 5. Discriminated Unions
|
||||
|
||||
Use a common property to narrow union types:
|
||||
|
||||
```typescript
|
||||
type Success = { status: 'success'; data: string };
|
||||
type Error = { status: 'error'; error: string };
|
||||
type Result = Success | Error;
|
||||
|
||||
function handle(result: Result) {
|
||||
if (result.status === 'success') {
|
||||
// TypeScript knows this is Success
|
||||
console.log(result.data);
|
||||
} else {
|
||||
// TypeScript knows this is Error
|
||||
console.log(result.error);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This pattern eliminates entire classes of runtime errors.
|
||||
|
||||
## Bonus: Non-Null Assertion Operator
|
||||
|
||||
While I generally avoid the `!` operator, it's useful when you know better than TypeScript:
|
||||
|
||||
```typescript
|
||||
// When you're certain the element exists
|
||||
const button = document.getElementById('submit')!;
|
||||
button.click();
|
||||
```
|
||||
|
||||
Use sparingly and only when you're absolutely sure.
|
||||
|
||||
## Wrapping Up
|
||||
|
||||
These tips have made my TypeScript code more robust and easier to maintain. The key is to leverage TypeScript's type system to catch errors at compile time rather than runtime.
|
||||
|
||||
What are your favorite TypeScript features? Let me know!
|
||||
|
||||
34
content/2025/10/a-new-post.md
Normal file
34
content/2025/10/a-new-post.md
Normal file
@ -0,0 +1,34 @@
|
||||
---
|
||||
title: Your Post Title
|
||||
date: 2025-10-21
|
||||
tags: [Web Development, TypeScript]
|
||||
excerpt: A brief summary of your post (2-3 sentences). This will appear in post listings and search results.
|
||||
draft: false
|
||||
---
|
||||
|
||||
# Your Post Title
|
||||
|
||||
Your content here. You can use standard markdown syntax:
|
||||
|
||||
## Section Heading
|
||||
|
||||
Write your paragraphs with proper spacing.
|
||||
|
||||
### Subsection
|
||||
|
||||
- Bullet points
|
||||
- Another point
|
||||
- And another
|
||||
|
||||
**Bold text** and *italic text* are supported.
|
||||
|
||||
```typescript
|
||||
// Code blocks work too
|
||||
const example = "Hello World";
|
||||
console.log(example);
|
||||
```
|
||||
|
||||
> Blockquotes for important callouts or quotes.
|
||||
|
||||
This is just a template - delete this file or ignore it when writing your actual posts.
|
||||
|
||||
103
content/2025/10/building-with-bun.md
Normal file
103
content/2025/10/building-with-bun.md
Normal file
@ -0,0 +1,103 @@
|
||||
---
|
||||
title: Building a Modern Blog with Bun and TypeScript
|
||||
date: 2025-10-20
|
||||
tags: [Web Development, TypeScript, JavaScript]
|
||||
excerpt: A deep dive into building a performant, modern blog using Bun's runtime, TypeScript, and server-side rendering. Learn about the architecture decisions and tradeoffs.
|
||||
draft: false
|
||||
---
|
||||
|
||||
# Building a Modern Blog with Bun and TypeScript
|
||||
|
||||
When I set out to build this blog, I had a few key requirements in mind: fast page loads, minimal JavaScript shipped to the client, and a great developer experience. Here's how I achieved all three.
|
||||
|
||||
## Why Bun?
|
||||
|
||||
Bun is an all-in-one JavaScript runtime that's significantly faster than Node.js for many operations. It includes:
|
||||
|
||||
- A blazing-fast JavaScript/TypeScript runtime
|
||||
- Built-in bundler
|
||||
- Native TypeScript support
|
||||
- Package manager
|
||||
- Test runner
|
||||
|
||||
For this blog, the combination of native TypeScript support and the built-in bundler made Bun an obvious choice.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
The blog uses a hybrid approach:
|
||||
|
||||
### Server-Side Rendering
|
||||
|
||||
All HTML is generated on the server using JSX as a templating language. This means:
|
||||
|
||||
- **Fast initial page loads** - No waiting for JavaScript to download and execute
|
||||
- **SEO friendly** - Search engines see fully rendered HTML
|
||||
- **Works without JavaScript** - Core functionality doesn't depend on client-side JS
|
||||
|
||||
### AppShell Pattern
|
||||
|
||||
The blog implements an "AppShell" pattern where:
|
||||
|
||||
1. First visit loads the full page with AppShell (sidebar, header, etc.)
|
||||
2. Navigation replaces only the `<main>` content
|
||||
3. Subsequent requests send a custom header to indicate AppShell is already loaded
|
||||
4. Server returns just the content, not the full shell
|
||||
|
||||
This gives us SPA-like navigation speed with SSR benefits.
|
||||
|
||||
## Markdown Processing
|
||||
|
||||
Blog posts are written in Markdown and processed at build time:
|
||||
|
||||
```typescript
|
||||
// Simplified example
|
||||
import { marked } from 'marked';
|
||||
|
||||
const html = marked.parse(markdownContent);
|
||||
```
|
||||
|
||||
The plugin:
|
||||
- Scans the content directory
|
||||
- Parses frontmatter (title, date, tags, etc.)
|
||||
- Converts markdown to HTML
|
||||
- Stores everything in SQLite for fast queries
|
||||
|
||||
## Performance Results
|
||||
|
||||
The result? Page loads under 128KB including:
|
||||
- All HTML
|
||||
- All CSS (inlined)
|
||||
- Minimal JavaScript for interactivity
|
||||
|
||||
First contentful paint happens in under 100ms on a fast connection.
|
||||
|
||||
## Developer Experience
|
||||
|
||||
With Bun's `--watch` flag, the entire development workflow is seamless:
|
||||
|
||||
```bash
|
||||
bun run --watch ./index.tsx
|
||||
```
|
||||
|
||||
This watches for changes and hot-reloads the server. Combined with the markdown plugin, changing a blog post immediately reflects in the browser.
|
||||
|
||||
## Lessons Learned
|
||||
|
||||
### What Worked Well
|
||||
|
||||
- **JSX for templating** - Familiar, type-safe, and no new syntax to learn
|
||||
- **SQLite for search** - Fast, embedded, and perfect for a small blog
|
||||
- **Bun's speed** - Development is incredibly fast
|
||||
|
||||
### What Could Be Better
|
||||
|
||||
- **Hot reloading** - Would love client-side HMR for styles
|
||||
- **Build step** - Currently all processing happens at runtime
|
||||
- **TypeScript types** - Virtual modules need proper type definitions
|
||||
|
||||
## Conclusion
|
||||
|
||||
Building with Bun has been a great experience. The performance is excellent, and the developer experience is top-notch. If you're building a new project and want to try something modern, I highly recommend giving Bun a shot.
|
||||
|
||||
The code for this blog is open source - check it out on GitHub!
|
||||
|
||||
51
content/2025/10/my-first-post.md
Normal file
51
content/2025/10/my-first-post.md
Normal file
@ -0,0 +1,51 @@
|
||||
---
|
||||
title: Welcome to My Blog
|
||||
date: 2025-10-15
|
||||
tags: [Career, Web Development]
|
||||
excerpt: Starting a new blog to share my thoughts on web development, programming, and building great software. Here's why I decided to start writing.
|
||||
draft: false
|
||||
---
|
||||
|
||||
# Welcome to My Blog
|
||||
|
||||
I'm excited to finally launch my personal blog! After years of thinking about it, I've decided it's time to start sharing my experiences, learnings, and thoughts about web development and software engineering.
|
||||
|
||||
## Why Start a Blog?
|
||||
|
||||
There are a few reasons I decided to finally take the plunge:
|
||||
|
||||
**Learning in Public**: Writing about what I learn helps solidify my understanding. Teaching is one of the best ways to learn, and writing blog posts forces me to really understand a topic deeply.
|
||||
|
||||
**Building a Knowledge Base**: I often solve problems and then forget the solution months later. This blog will serve as my personal reference guide for future me.
|
||||
|
||||
**Contributing to the Community**: The developer community has given me so much through blog posts, tutorials, and open source. This is my way of giving back.
|
||||
|
||||
## What to Expect
|
||||
|
||||
I plan to write about:
|
||||
|
||||
- Web development best practices
|
||||
- TypeScript and JavaScript tips
|
||||
- Architecture and design patterns
|
||||
- Career advice and lessons learned
|
||||
- Tools and productivity
|
||||
|
||||
## The Tech Stack
|
||||
|
||||
This blog itself is built with some fun technologies:
|
||||
|
||||
- **Bun** - The all-in-one JavaScript runtime
|
||||
- **TypeScript** - For type safety
|
||||
- **Elysia** - Fast web framework for Bun
|
||||
- **SQLite** - For blog post search and metadata
|
||||
|
||||
I'll be writing more about the technical implementation in future posts.
|
||||
|
||||
## Let's Connect
|
||||
|
||||
If you enjoy the content, feel free to reach out! You can find me on Twitter, GitHub, and LinkedIn (links in the sidebar).
|
||||
|
||||
Thanks for reading, and I hope you find something useful here!
|
||||
|
||||
Test change at Wed Oct 22 06:20:32 PDT 2025
|
||||
<!-- test change -->
|
||||
71
index.tsx
71
index.tsx
@ -1,28 +1,49 @@
|
||||
import { Elysia } from "elysia";
|
||||
import { html } from "@elysiajs/html";
|
||||
import { staticPlugin } from "@elysiajs/static";
|
||||
// import { Elysia } from "elysia";
|
||||
// import { html } from "@elysiajs/html";
|
||||
// import { staticPlugin } from "@elysiajs/static";
|
||||
|
||||
import { AppShell } from "./src/frontend/AppShell";
|
||||
import { app } from "./src/backend";
|
||||
// import { AppShell } from "./src/frontend/AppShell";
|
||||
// import { app } from "./src/backend";
|
||||
|
||||
const index = new Elysia()
|
||||
.use(html())
|
||||
.onRequest(({ request }) => {
|
||||
console.log(`Request ${request.method} ${request.url}`);
|
||||
})
|
||||
.onAfterHandle(({ request, responseValue }) => {
|
||||
if (request.headers.get("shell-loaded") === "true") {
|
||||
return responseValue; // Return the <main> element if the AppShell has already been loaded
|
||||
}
|
||||
return AppShell(responseValue); // Return the <main> element wrapped by the AppShell
|
||||
})
|
||||
.use(staticPlugin({
|
||||
assets: './src/public',
|
||||
prefix: '/public'
|
||||
}))
|
||||
.use(app)
|
||||
.listen(3000);
|
||||
// const index = new Elysia()
|
||||
// .use(html())
|
||||
// .onRequest(({ request }) => {
|
||||
// console.log(`Request ${request.method} ${request.url}`);
|
||||
// })
|
||||
// .onAfterHandle(({ request, responseValue }) => {
|
||||
// if (request.headers.get("shell-loaded") === "true") {
|
||||
// return responseValue; // Return the <main> element if the AppShell has already been loaded
|
||||
// }
|
||||
// return AppShell(responseValue); // Return the <main> element wrapped by the AppShell
|
||||
// })
|
||||
// .use(staticPlugin({
|
||||
// assets: './src/public',
|
||||
// prefix: '/public'
|
||||
// }))
|
||||
// .use(app)
|
||||
// .listen(3000);
|
||||
|
||||
console.log(
|
||||
`🦊 Elysia is running at ${index.server?.hostname}:${index.server?.port}`
|
||||
);
|
||||
// console.log(
|
||||
// `🦊 Elysia is running at ${index.server?.hostname}:${index.server?.port}`
|
||||
// );
|
||||
|
||||
|
||||
import { serve } from "bun";
|
||||
import AppShell from "./temp/appshell.html"
|
||||
|
||||
// Dynamically import all markdown files
|
||||
const glob = new Bun.Glob("**/*.md");
|
||||
const routes: Record<string, any> = {
|
||||
'/': AppShell,
|
||||
};
|
||||
|
||||
for await (const file of glob.scan("./content")) {
|
||||
const post = await import(`./content/${file}`, { with: { type: "html" } });
|
||||
const route = `/${file.replace(/\.md$/, '')}`;
|
||||
routes[route] = post.default;
|
||||
}
|
||||
|
||||
serve({
|
||||
routes,
|
||||
development: true,
|
||||
})
|
||||
|
||||
4
markdown.d.ts
vendored
Normal file
4
markdown.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
declare module "*.md" {
|
||||
const content: import("html").HtmlString;
|
||||
export default content;
|
||||
}
|
||||
@ -8,7 +8,9 @@
|
||||
"dependencies": {
|
||||
"@elysiajs/html": "1.4.0",
|
||||
"@elysiajs/static": "1.4.4",
|
||||
"elysia": "^1.4.11"
|
||||
"elysia": "^1.4.11",
|
||||
"gray-matter": "^4.0.3",
|
||||
"marked": "^16.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "^1.3.0"
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||
|
||||
/* Modules */
|
||||
"module": "ES2022", /* Specify what module code is generated. */
|
||||
"module": "esnext", /* Specify what module code is generated. */
|
||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||
"moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
|
||||
Loading…
Reference in New Issue
Block a user