waibu-mpa
Version:
MPA support for Waibu Framework
127 lines (122 loc) • 5.4 kB
JavaScript
export async function build ({ files, pathPrefix, dir, ns, cfg, parent, urlPrefix, subRoute }) {
const { defaultsDeep } = this.lib.aneka
const { importModule } = this.app.bajo
const { isFunction, isPlainObject, pick, last, camelCase } = this.lib._
const { titleize } = this.lib.aneka
const { getPluginPrefix } = this.app.waibu
const mergeRouteHooks = await importModule('waibu:/lib/webapp-scope/merge-route-hooks.js')
const mods = []
const me = this
for (const f of files) {
const url = f.slice(0, f.length - 3).replace(`${dir}/${pathPrefix}`, '').replaceAll('@', ':')
let mod = await importModule(f)
if (isFunction(mod)) mod = [{ handler: mod }]
else if (isPlainObject(mod)) mod = [mod]
for (let m of mod) {
m.url = m.url ?? url
if (isFunction(m.url)) m.url = await m.url.call(this)
if (!m.handler) {
m.handler = async function (req, reply) {
const params = {}
let tpl = m.view ?? `${ns}.template:${m.url}.html`
if (m.tbd) {
params.page = { title: titleize(last(m.url.split('/'))) }
tpl = 'waibuMpa.template:/tbd.html'
}
return reply.view(tpl, params)
}
}
if (urlPrefix) m.url = `/${urlPrefix}/${m.url}`
m.method = m.method ?? 'GET'
await mergeRouteHooks.call(me, m)
m.config = m.config ?? {}
m.config.prefix = getPluginPrefix(ns)
m.config.pathSrc = m.url
m.config.webApp = parent ?? ns
m.config.ns = ns
m.config.subNs = ''
m.config.title = m.title ?? camelCase(last(m.url.split('/')))
m.config.subRoute = subRoute
delete m.title
m = defaultsDeep(pick(cfg, ['exposeHeadRoute', 'bodyLimit']), m)
mods.push(m)
}
}
return mods
}
async function addRoutes ({ appPrefix, prefix, mods, ctx, appCtx, cfg }) {
const { importModule } = this.app.bajo
const isRouteDisabled = await importModule('waibu:/lib/webapp-scope/is-route-disabled.js')
const reroutedPath = await importModule('waibu:/lib/webapp-scope/rerouted-path.js')
for (const mod of mods) {
const fullPath = `/${appPrefix}${mod.url}`
if (await isRouteDisabled.call(this, fullPath, mod.method, cfg.disabled)) {
this.log.warn('routeDisabled%s%s', `${prefix}${fullPath}`, mod.method)
continue
}
const rpath = await reroutedPath.call(this, fullPath, cfg.rerouted)
if (rpath) {
this.log.warn('rerouted%s%s', `${prefix}${fullPath}`, `${prefix}${rpath}`)
mod.url = rpath
mod.pathReroutedTo = rpath
await ctx.route(mod)
} else await appCtx.route(mod)
}
}
async function buildRoutes (ctx, prefix) {
const { eachPlugins, runHook } = this.app.bajo
const { getPluginPrefix } = this.app.waibu
const { fastGlob } = this.lib
const { groupBy } = this.lib._
const cfg = this.config
const pathPrefix = 'waibuMpa/route'
const me = this
const appCtxs = {}
let subRoutes = []
await runHook(`${this.name}:beforeBuildRoutes`, ctx)
await eachPlugins(async function ({ dir, alias, ns }) {
let appPrefix = getPluginPrefix(ns)
if (ns === me.ns || (ns === me.app.bajo.mainNs && cfg.mountMainAsRoot)) appPrefix = ''
const pattern = `${dir}/${pathPrefix}/**/*.js`
const files = await fastGlob(pattern)
// subRoutes
const spattern = `${dir}/waibuMpa/extend/{${me.app.bajo.pluginNames.join(',')}}/route/**/*.js`
const sfiles = await fastGlob(spattern)
for (const file of sfiles) {
const [sns] = file.replace(`${dir}/waibuMpa/extend/`, '').split('/')
subRoutes.push({ file, ns: sns, sns: ns, dir })
}
if (files.length === 0) return undefined
await ctx.register(async (appCtx) => {
appCtxs[ns] = appCtx
await runHook(`${me.name}.${this.name}:beforeBuildRoutes`, appCtx, appPrefix)
const mods = await build.call(this, { appCtx, files, appPrefix, pathPrefix, dir, ns, cfg, parent: me.name })
await addRoutes.call(me, { appPrefix, prefix, mods, ctx, appCtx, cfg })
await runHook(`${me.name}.${this.name}:afterBuildRoutes`, appCtx, appPrefix)
}, { prefix: appPrefix })
})
if (subRoutes.length > 0) {
subRoutes = groupBy(subRoutes, 'ns')
for (const k in subRoutes) {
const items = subRoutes[k]
if (items.length === 0) continue
const { sns, ns } = items[0]
const appCtx = appCtxs[ns]
if (!appCtx) throw this.error('cantHaveSubroutesWithoutContext%s', ns)
let appPrefix = getPluginPrefix(sns)
if (sns === me.ns || (sns === me.app.bajo.mainNs && cfg.mountMainAsRoot)) appPrefix = ''
await runHook(`${me.name}.${k}:beforeBuildSubRoutes`, appCtx, appPrefix)
for (const item of items) {
const { file, sns, ns, dir } = item
const scope = this.app[ns]
const pathPrefix = `waibuMpa/extend/${ns}/route/`
const urlPrefix = getPluginPrefix(sns)
const mods = await build.call(scope, { appCtx, files: [file], pathPrefix, dir, ns, cfg, parent: me.name, urlPrefix, subRoute: sns })
await addRoutes.call(me, { appPrefix, prefix, mods, ctx, appCtx, cfg })
}
await runHook(`${me.name}.${k}:afterBuildSubRoutes`, appCtx, appPrefix)
}
}
await runHook(`${this.name}:afterBuildRoutes`, ctx)
}
export default buildRoutes