Val Town Static Server

A flexible, exportable static file server for Val Town that can serve HTML, JavaScript, CSS, and other text files from your project directory.

Features

  • šŸš€ Zero configuration - Works out of the box
  • šŸ“ Dynamic file serving - No hardcoded file paths
  • šŸŽÆ Proper MIME types - Automatic content-type detection
  • šŸ”§ Highly configurable - Custom options for advanced use cases
  • šŸ›£ļø API routes - Mix static files with dynamic endpoints
  • šŸ”Œ Middleware support - Add logging, auth, or custom processing
  • šŸ“± SPA support - Built-in Single Page Application routing
  • āŒ Smart 404 handling - Customizable error responses

Quick Start

Basic Setup

import { quickStaticServer } from "./static-server.ts"; // Serves index.html at root, any .js/.css/.html files by path export default quickStaticServer();

Custom Index File

import { quickStaticServer } from "./static-server.ts"; export default quickStaticServer('/app.html');

Advanced Usage

Custom Configuration

import { createStaticServer } from "./static-server.ts"; const { handler } = createStaticServer({ indexFile: '/index.html', headers: { 'Cache-Control': 'no-cache', 'X-Powered-By': 'My App' }, mimeTypes: { '.ts': 'text/typescript; charset=utf-8' }, notFoundHandler: (pathname) => { return new Response(`Custom 404: ${pathname} not found`, { status: 404, headers: { 'Content-Type': 'text/plain' } }); } }); export default handler;

API Routes + Static Files

import { advancedStaticServer } from "./static-server.ts"; export default advancedStaticServer({ routes: { '/api/health': () => new Response('OK'), '/api/data': () => new Response(JSON.stringify({ message: 'Hello from API!' }), { headers: { 'Content-Type': 'application/json' } }) }, middleware: [ async (req, next) => { console.log(`${req.method} ${new URL(req.url).pathname}`); return await next(); } ] });

Single Page Application (SPA)

import { createStaticServer } from "./static-server.ts"; const { handler, serveFile } = createStaticServer({ importMetaUrl: import.meta.url, // Required! notFoundHandler: async (pathname) => { // Serve index.html for routes without file extensions if (!pathname.includes('.')) { return await serveFile('/index.html', { importMetaUrl: import.meta.url }); } return new Response('File not found', { status: 404 }); } }); export default handler;

Configuration Options

StaticServerOptions

OptionTypeDefaultDescription
indexFilestring'/index.html'File to serve at root path
notFoundHandlerfunctionBuilt-in 404Custom 404 response handler
errorHandlerfunctionBuilt-in errorCustom error response handler
mimeTypesobjectBuilt-in typesAdditional MIME type mappings
headersobject{}Headers added to all responses

Built-in MIME Types

  • .html → text/html; charset=utf-8
  • .js → application/javascript; charset=utf-8
  • .css → text/css; charset=utf-8
  • .json → application/json; charset=utf-8
  • .txt → text/plain; charset=utf-8
  • .md → text/markdown; charset=utf-8
  • .xml → application/xml; charset=utf-8
  • .svg → image/svg+xml; charset=utf-8

Project Structure

your-project/
ā”œā”€ā”€ index.html          # Main HTML file
ā”œā”€ā”€ script.js           # JavaScript files
ā”œā”€ā”€ style.css           # CSS files
ā”œā”€ā”€ static-server.ts    # The server module
ā”œā”€ā”€ server.ts           # Your HTTP val
└── api/
    └── data.json       # Static data files

Examples

See the /examples/ directory for complete working examples:

  • basic-server.ts - Minimal setup
  • custom-server.ts - Custom configuration
  • advanced-server.ts - API routes + middleware
  • spa-server.ts - Single Page Application

HTML Integration

Your HTML files can reference any JavaScript or CSS files:

<!DOCTYPE html> <html> <head> <link rel="stylesheet" href="/styles/main.css"> <link rel="stylesheet" href="/components/header.css"> </head> <body> <div id="app"></div> <!-- All these JS files will be served automatically --> <script src="/utils/helpers.js"></script> <script src="/components/header.js"></script> <script src="/app.js"></script> </body> </html>

Error Handling

The server provides helpful error messages:

  • 404 for missing files: "JavaScript file not found: /missing.js"
  • 500 for server errors: "Server error: [error message]"
  • Custom handlers: Override with your own error responses

Best Practices

  1. File Organization: Keep related files in subdirectories
  2. Error Handling: Provide custom 404 pages for better UX
  3. Caching: Use appropriate cache headers for production
  4. Security: Don't serve sensitive files (use proper file extensions)
  5. Performance: Consider middleware for compression, logging, etc.

Migration from Basic Server

If you have an existing basic server, migration is simple:

// Before export default async function(req: Request) { // manual file serving logic } // After import { quickStaticServer } from "./static-server.ts"; export default quickStaticServer();

Contributing

This server module is designed to be:

  • Extensible - Easy to add new features
  • Maintainable - Clear separation of concerns
  • Reusable - Works across different Val Town projects

Feel free to extend it for your specific needs!