22 lines
1.6 KiB
JavaScript
22 lines
1.6 KiB
JavaScript
import { createServer } from 'node:http';
|
|
import { createReadStream, existsSync } from 'node:fs';
|
|
import { stat } from 'node:fs/promises';
|
|
import { resolve, sep, extname } from 'node:path';
|
|
const root=resolve('out');
|
|
if(!existsSync(root)){console.error('Run npm run build before npm start.');process.exit(1)}
|
|
const types={'.html':'text/html; charset=utf-8','.js':'text/javascript; charset=utf-8','.css':'text/css; charset=utf-8','.json':'application/json','.txt':'text/plain; charset=utf-8','.png':'image/png','.jpg':'image/jpeg','.jpeg':'image/jpeg','.svg':'image/svg+xml','.woff':'font/woff','.woff2':'font/woff2','.ico':'image/x-icon'};
|
|
createServer(async(req,res)=>{
|
|
if(!['GET','HEAD'].includes(req.method)){res.writeHead(405,{Allow:'GET, HEAD'});res.end();return}
|
|
try{
|
|
const pathname=decodeURIComponent(new URL(req.url,'http://localhost').pathname);
|
|
let file=resolve(root,`.${pathname}`);
|
|
if(file!==root&&!file.startsWith(root+sep)){res.writeHead(403);res.end();return}
|
|
let info=await stat(file).catch(()=>null);
|
|
if(info?.isDirectory()){file=resolve(file,'index.html');info=await stat(file).catch(()=>null)}
|
|
const status=info?.isFile()?200:404;
|
|
if(status===404){file=resolve(root,'404.html');info=await stat(file)}
|
|
res.writeHead(status,{'Content-Type':types[extname(file)]??'application/octet-stream','Content-Length':info.size});
|
|
if(req.method==='HEAD')res.end();else createReadStream(file).pipe(res);
|
|
}catch{res.writeHead(400);res.end('Bad request')}
|
|
}).listen(Number(process.env.PORT??3000),'127.0.0.1',()=>console.log(`Static site: http://localhost:${process.env.PORT??3000}`));
|