Newer
Older
TelosDB / tools / serve-frontend.mjs
import { createServer } from 'http';
import { readFile } from 'fs/promises';
import path from 'path';
const { join, extname, resolve } = path;
import { fileURLToPath } from 'url';

// 即時出力(Tauri の beforeDevCommand が子プロセスを認識しやすくする)
console.log('Frontend dev server starting (port 8474)...');

const __dirname = fileURLToPath(new URL('.', import.meta.url));
const root = resolve(join(__dirname, '..', 'src', 'frontend'));
const PORT = 8474;

const MIME = {
  '.html': 'text/html', '.js': 'application/javascript', '.mjs': 'application/javascript',
  '.css': 'text/css', '.json': 'application/json', '.svg': 'image/svg+xml',
  '.png': 'image/png', '.ico': 'image/x-icon', '.woff2': 'font/woff2',
};

function startServer() {
  const server = createServer(async (req, res) => {
    const pathname = new URL(req.url, 'http://localhost').pathname;
    const filePath = resolve(root, pathname === '/' ? 'index.html' : pathname.slice(1));
    const rel = path.relative(root, filePath);
    if (rel.startsWith('..') || path.isAbsolute(rel)) {
      res.writeHead(403);
      res.end('Forbidden');
      return;
    }
    try {
      const data = await readFile(filePath);
      res.writeHead(200, { 'Content-Type': MIME[extname(filePath)] || 'application/octet-stream' });
      res.end(data);
    } catch {
      res.writeHead(404);
      res.end('Not Found');
    }
  });
  server.listen(PORT, '127.0.0.1', () => {
    console.log(`Frontend dev server ready on http://127.0.0.1:${PORT}`);
  });
  server.on('error', (err) => {
    if (err.code === 'EADDRINUSE') {
      console.error(`Port ${PORT} in use. Run "npm run kill-ports" and try again.`);
      process.exit(1);
    }
    throw err;
  });
}

// Tauri が devUrl に接続して「準備完了」を待つため、遅延せずすぐ listen する
startServer();