UNPKG

waibu-mpa

Version:

MPA support for Waibu Framework

84 lines (80 loc) 3.52 kB
import path from 'path' async function isCacheable (req, cachedUrls) { const { hash } = this.app.bajoExtra const { get, omit, isFunction } = this.app.lib._ const ns = get(req, 'routeOptions.config.ns') let cache = get(req, 'routeOptions.config.cache', omit(this.config.page.cache, ['urls'])) cache.methods = cache.methods ?? ['GET'] if (!ns || (!this.app.bajoCache) || (!req.site) || !cache.methods.includes(req.method)) return { ttl: 0 } if (isFunction(cache)) { cache = await cache.call(this.app[ns], req, cachedUrls) } const url = req.url.split('?')[0].split('#')[0] for (const item of cachedUrls) { if (item.isMatch(url)) cache.ttlDur = item.ttlDur ?? cache.ttlDur } const key = `waibu-mpa-page-${req.site.id}-${cache.key ?? (await hash(req.url))}` return { key, ttl: cache.ttlDur } } async function decorate () { const { importModule } = this.app.bajo const buildLocals = await importModule('waibu:/lib/build-locals.js') const { importPkg } = this.app.bajo const { isString, cloneDeep, isEmpty, get } = this.app.lib._ const { get: getCache, set: setCache } = this.app.bajoCache ?? {} const { outmatch } = this.app.lib const { routePath } = this.app.waibu const mime = await importPkg('waibu:mime') const cfg = this.config const me = this const cachedUrls = cloneDeep(this.config.page.cache.urls).map(item => { if (isString(item)) item = { url: item } item.url = routePath(item.url) item.isMatch = outmatch(item.url) return item }) this.webAppCtx.decorateRequest('theme', cfg.theme.set) this.webAppCtx.decorateRequest('iconset', cfg.iconset.set) this.webAppCtx.decorateRequest('darkMode', cfg.darkMode.set) this.webAppCtx.decorateRequest('referer', '') this.webAppCtx.decorateReply('ctags', null) this.webAppCtx.decorateReply('view', async function (tpl, params = {}, opts = {}) { // this = fastify context! let ext = path.extname(tpl) if (ext === '.md') ext = '.html' let mimeType = isEmpty(ext) ? 'text/html' : mime.getType(ext) mimeType += `; charset=${cfg.page.charset}` this.header('Content-Type', mimeType) this.header('Content-Language', this.request.lang) this.header('X-Req-Id', this.request.id) opts.req = this.request opts.reply = this for (const item of ['theme', 'iconset']) { if (!this.request[item]) this.request[item] = me[item + 's'][0].name if (me[item + 's'].length === 1) this.request[item] = me[item + 's'][0].name } const { key, ttl } = await isCacheable.call(me, this.request, cachedUrls) if (ttl > 0) { const cached = await getCache({ key }) if (cached) { this.header('X-Wmpa-Cached', true) return cached } } const locals = await buildLocals.call(me, { tpl, params, opts }) if (!get(this.request, 'routeOptions.config.noCacheReq')) { await me.app.cache.save(`${me.ns}.req:/${opts.req.id}-locals.json`, locals, me.config.reqTtlDur) } const result = await me.render(tpl, locals, opts) if (ttl > 0) await setCache({ key, value: result, ttl }) if (this.request.session) { ext = path.extname(this.request.url) if (isEmpty(ext) || ['.html'].includes(ext)) { if (this.request.session.prevUrl !== this.request.url) this.request.session.prevUrl = this.request.url else this.request.session.prevUrl = '' } } return result }) } export default decorate