c8r/genのserverのコードを分析してみる
引き続きgenを実際に読む。
<!--truncate-->serverの主な役割はこうだ
const start = async (dirname: string, opts: Options) => { // 利用可能なポートを探す const socketPort: number = await portfinder.getPortPromise() // 定義だけ let socket: WebSocket // 初回に表示するページの取得 let gPages = await getPages(dirname, opts) // ファイルの変更監視 const watcher: chokidar.FSWatcher = chokidar.watch(dirname, { depth: 1, ignoreInitial: true, ignored: '!*.(jsx|md|json)', }) // WebSocketサーバーの立ち上げ const socketServer = new WebSocket.Server({ port: socketPort }) // 接続時にsocket渡す socketServer.on('connection', (res: WebSocket) => { // 最後に接続したものだけ更新の対象とする socket = res }) // 更新時に得られたsocketに対してpayloadを投げる const update = async () => { if (!socket) { return } gPages = await getPages(dirname, opts) socket.send(JSON.stringify({ reload: true })) } // 省略 } export { start as server }
続きは、HTTPサーバー部分
const start = async (dirname: string, opts: Options) => { // 中略 const app = http.createServer((req: http.IncomingMessage, res: http.ServerResponse) => { if (!req.url) { return } const { pathname } = url.parse(req.url) if (!pathname) { return } // URIとディレクトリ名を結合することで、ファイル名を生成する const filepath = path.join(dirname, pathname) // ローカルディレクトリに存在しているかどうか確認 if (fs.existsSync(filepath) && fs.statSync(filepath).isFile()) { fs.createReadStream(filepath).pipe(res) return } // `/`終わりの場合はindexでに変換する const name = pathname === '/' ? 'index' : pathname.replace(/^\//, '').replace(/\/$/, '') const page = gPages.find((localPage: any) => localPage.name === name) if (!page) { res.write('page not found: ' + pathname) res.end() return } // レンダリングするページをレスポンスに含める res.write(page.html) // hot reloadをかける用のscriptを最後尾に追加する res.write(makeScript(socketPort)) res.end() }) try { const server = await app.listen(socketPort + 2) return server } catch (err) { console.log(err) throw err } }