UNPKG

@hqjs/hq

Version:

Universal static web server for frontend development

119 lines (113 loc) 3.58 kB
import { HTTP_CODES, isInternal } from '../utils.mjs'; import { getCache, getInputSourceMap, save, saveContent } from '../compilers/tools.mjs'; import fs from 'fs-extra'; const buildSource = async ctx => { const content = await fs.readFile(ctx.srcPath, { encoding: 'utf8' }); const inputSourceMap = await getInputSourceMap(ctx.srcPath, content); let res; // TODO: make dynamic extension resolver // TODO: move to utils switch (ctx.stats.ext) { case '.js': case '.jsx': case '.es6': case '.vue': case '.svelte': case '.mjs': case '.ts': case '.tsx': { const { default: compileJS } = await import('../compilers/js.mjs'); res = await compileJS(ctx, content, inputSourceMap, { skipSM: isInternal(ctx.dpath) || ctx.app.build }); break; } case '.css': case '.scss': case '.sass': case '.less': { const { default: compileCSS } = await import('../compilers/css.mjs'); res = await compileCSS(ctx, content, inputSourceMap, { skipSM: ctx.app.build }); break; } case '.pug': case '.html': { const { default: compileHTML } = await import('../compilers/html.mjs'); res = await compileHTML(ctx, content); break; } // default: { // const { default: compileReplace } = await import('../compilers/replace.mjs'); // res = await replace(ctx, content); // break; // } default: return save(ctx); } const { code, map } = res; if (map) { const { ua } = ctx.store; const stats = ctx.app.table.touch(`${ctx.srcPath}.map`); // TODO: add map byte length here const mapBuildPromise = saveContent(JSON.stringify(map), { dpath: `${ctx.dpath}.map`, path: `${ctx.path}.map`, stats, store: ctx.store, }); stats.build.set(ua, mapBuildPromise); } return saveContent(code, ctx); }; const buildAsset = async ctx => { // return save(ctx); switch (ctx.stats.ext) { // case '.webp': case '.gif': case '.png': case '.jpg': case '.jpeg': case '.svg': { const content = await fs.readFile(ctx.srcPath); const { default: minifyImage } = await import('../compilers/image.mjs'); return minifyImage(ctx, content); } default: return save(ctx); } }; const makeBuild = ctx => ctx.stats.isSrc ? buildSource(ctx) : buildAsset(ctx); const getBuild = async ctx => { const { ext } = ctx.stats; const { ua } = ctx.store; if (ext === '.map') { const { build: srcBuild } = ctx.app.table.get(ctx.srcPath.slice(0, -4)) || {}; if (srcBuild) await srcBuild.get(ua); } const { build } = ctx.stats; const isDirty = build.isDirty(ua); if (isDirty) { if (ext === '.map') ctx.throw(HTTP_CODES.NOT_FOUND, `File ${ctx.dpath} not found`); if (ctx.app.verbose) console.log(`🛠️ BUILD ${ctx.path}: ${ua.name} ${ua.ver} for ${ua.target}`); const buildPromise = makeBuild(ctx); build.set(ua, buildPromise); return buildPromise; } else { if (ctx.app.verbose) console.log(`⚙️ CACHE ${ctx.path}: ${ua.name} ${ua.ver} for ${ua.target}`); return build.get(ua); } }; export default () => async (ctx, next) => { const { build } = ctx.stats; const { ua } = ctx.store; try { await getBuild(ctx); if (ctx.app.verbose) console.log(`🚀 SEND ${ctx.path}`); ctx.type = ctx.stats.type; ctx.body = getCache(ctx); } catch (err) { build.setDirty(ua); ctx.body = err.message; ctx.throw(HTTP_CODES.INTERNAL_SERVER_ERROR, err); return null; } return next(); };