An open API service indexing awesome lists of open source software.

https://github.com/devchitchat/index97

A Bun-native web framework that trusts the platform. File-based routing, zero build steps, HTML that works, JavaScript that ships.
https://github.com/devchitchat/index97

Last synced: about 2 months ago
JSON representation

A Bun-native web framework that trusts the platform. File-based routing, zero build steps, HTML that works, JavaScript that ships.

Awesome Lists containing this project

README

          

# index97

A Bun-native web framework. File-based routing, server-side templates, zero config.

---

## Prerequisites

Install [Bun](https://bun.sh):

```bash
curl -fsSL https://bun.sh/install | bash
```

---

## Phase 1 — Up and running in 5 minutes

**1. Create a project**

```bash
mkdir my-site && cd my-site
bun init -y
bun add @devchitchat/index97
```

**2. Create the entry point**

```js
// server.js
import { createServer } from '@devchitchat/index97'
createServer({ pagesDir: './pages' })
```

**3. Create your first page and layout**

```bash
mkdir pages pages/public
```

```html



{{slot:title || My Site}}


Home
About


{{content}}

```

```html

Home — My Site

Hello, world.

```

```html

Welcome to index97. Files are routes. No config needed.


```

```css
/* pages/public/style.css */
body { font-family: system-ui, sans-serif; max-width: 800px; margin: 2rem auto; padding: 0 1rem; }
nav a { margin-right: 1rem; }
```

**4. Run it**

```bash
bun server.js
```

Open [http://localhost:3000](http://localhost:3000). Edit any file — the browser updates instantly.

---

## Phase 2 — Level up

### Dynamic routes

Wrap a folder name in brackets to make it a parameter.

```
pages/
blog/
[slug].js ← handles /blog/hello-world
[slug].phtml ← template for the above
```

```js
// pages/blog/[slug].js
import db from './_db.js'

export async function GET(req) {
const post = db.query('SELECT * FROM posts WHERE slug = ?').get(req.params.slug)
if (!post) return new Response('', { status: 404 })
return { post }
}
```

```html

{{post.title}}


{{post.body}}


```

### Templates

| Syntax | What it does |
|--------|-------------|
| `{{name}}` | Render value, HTML-escaped |
| `{{{name}}}` | Render value, raw HTML |
| `{{#if name}}...{{/if}}` | Conditional |
| `{{#each items}}...{{/each}}` | Loop — `{{this}}` is each item |
| `` | Server-side partial |
| `` | Pass data to partial |

### Layout slots

Pages can inject into named slots in the layout:

```html

About — My Site

About


```

```html

{{slot:title || My Site}}
{{slot:head}}
{{content}}
```

### Server-side layout data

Export a `data` function from `_layout.js` to make values available across every page — useful for navigation, session state, feature flags:

```js
// pages/_layout.js
export function data(req) {
const session = getSession(req)
return { session }
}
```

```html

{{#if session}}Sign out{{/if}}
```

### Forms with PUT / PATCH / DELETE

Forms only support GET and POST natively. index97 rewrites the others automatically:

```html

Delete

```

Export the matching method from your handler:

```js
export async function DELETE(req) {
db.run('DELETE FROM posts WHERE id = ?', [req.params.id])
return Response.redirect('/posts', 303)
}
```

### Static site generation

Export `staticPaths()` from any dynamic handler to tell the build which URLs to render:

```js
// pages/blog/[slug].js
export function staticPaths() {
return db.query('SELECT slug FROM posts').all().map(p => ({ slug: p.slug }))
}
```

```bash
bunx index97 build # renders all routes to dist/
bunx index97 serve # serves dist/ as a static site
```

---

## CLI

| Command | What it does |
|---------|-------------|
| `bunx index97` | Start dev server with HMR |
| `bunx index97 start` | Start production server |
| `bunx index97 build` | Generate static site to `dist/` |
| `bunx index97 serve` | Serve a pre-built `dist/` |

## Project layout

```
my-site/
server.js ← entry point
pages/
_layout.html ← wraps every page
_layout.js ← server-side data for the layout
index.html ← /
about.html ← /about
blog/
index.html ← /blog
[slug].js ← /blog/:slug (handler)
[slug].phtml ← template for the handler
public/
style.css ← served as static files
logo.png
```

Files starting with `_` are private — they are not routes.

---

## Security

### Content Security Policy

index97 sets the following CSP header on every response by default:

```
default-src 'self'; style-src 'self'; script-src 'self'
```

This means **inline styles and inline scripts are blocked**. Use external stylesheets and script files served from `pages/public/` instead.

```html

hello

body { margin: 0 }

```

To override the CSP, pass a `csp` option to `createServer`:

```js
import { createServer } from '@devchitchat/index97'
createServer({
pagesDir: './pages',
csp: "default-src 'self'; style-src 'self' 'unsafe-inline'"
})
```