UNPKG

waibu-mpa

Version:

MPA support for Waibu Framework

67 lines (63 loc) 3.05 kB
import path from 'path' import { printLink } from './inject-elements/css.js' import { printScript } from './inject-elements/script.js' async function apply ({ $, req, tag, attr, type }) { const { includes } = this.app.lib.aneka const { routePath } = this.app.waibu const { hash, fetch } = this.app.bajoExtra const { isEmpty, map, without } = this.app.lib._ const { get: getCache, set: setCache } = this.app.bajoCache ?? {} const prefix = this.app.bajoCache.config.exportPrefix const excluded = map(this.config.concatResource.excluded, item => routePath(item)) const baseUrl = `${req.protocol}://${req.hostname}${req.port ? `:${req.port}` : ''}` // TODO: auth, if any const items = [] $(`${tag}[${attr}]`).each(function () { items.push(this.attribs[attr]) }) if (items.length === 0) return let keys = [] const notKeys = [] const key = `${prefix}-waibu-mpa-concat-resource-${await hash(items)}` const cached = await getCache({ key }) if (!cached) { const contents = [] for (const item of items) { try { if (excluded.includes(item)) throw this.error('excludedFromRscConcat%s', item) let url = item if (!item.startsWith('http')) { const u = new URL(req.url, baseUrl) if (item[0] === '/') url = u.origin + url else url = u.origin + path.dirname(u.pathname) + '/' + url } const resp = await fetch(url, undefined, { rawResponse: true }) if (!resp.ok) throw this.error('respError%s', resp.status) const text = await resp.text() if (type === 'css' && includes(['url(".', 'url(.', 'url(\'.'], text)) throw this.error('cssContainsRelPath%s', item) contents.push(`/* waibu resource: ${item} */`, text) keys.push(item) } catch (err) { notKeys.push(item) } } if (isEmpty(contents)) return $(map(keys, k => `${tag}[${attr}="${k}"]`).join(',')).remove() const value = { contents, notKeys, type, tag, attr } await setCache({ key, value, ttl: this.config.concatResource.ttlDur }) } else { keys = without(items, ...cached.notKeys) $(map(keys, k => `${tag}[${attr}="${k}"]`).join(',')).remove() } const rsc = `bajoCache:/external/${key.slice(prefix.length + 1)}.${type}` if (tag === 'link') $('head').prepend(printLink.call(this, rsc)) else if (tag === 'script') $('body').append(printScript.call(this, rsc)) } async function concatResources (options) { const { $, req } = options ?? {} if (!(this.app.bajoExtra && this.app.bajoCache)) return if (this.config.concatResource.ttlDur === 0) return if (this.config.concatResource.css) await apply.call(this, { $, req, tag: 'link', attr: 'href', type: 'css' }) if (this.config.concatResource.links) await apply.call(this, { $, req, tag: 'link', attr: 'href', type: 'css' }) if (this.config.concatResource.scripts) await apply.call(this, { $, req, tag: 'script', attr: 'src', type: 'js' }) } export default concatResources