waibu-mpa 2.10.1 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,5 +4,6 @@
4
4
  "session,object"
5
5
  ],
6
6
  "features": ["dobo:createdAt", "dobo:updatedAt"],
7
- "attachment": false
7
+ "attachment": false,
8
+ "cache": false
8
9
  }
package/index.js CHANGED
@@ -33,12 +33,16 @@ async function factory (pkgName) {
33
33
  prefix: ''
34
34
  },
35
35
  waibuAdmin: {
36
- modelDisabled: ['session']
36
+ menuHandler: false,
37
+ modelDisabled: '*'
37
38
  },
38
39
  mountMainAsRoot: true,
39
40
  page: {
40
41
  charset: 'utf-8',
41
- cacheMaxAge: 0,
42
+ cache: {
43
+ ttlDur: 0,
44
+ urls: []
45
+ },
42
46
  insertWarning: false,
43
47
  usePluginTitle: false,
44
48
  scriptsAtEndOfBody: true
@@ -63,7 +67,6 @@ async function factory (pkgName) {
63
67
  },
64
68
  emoji: true,
65
69
  viewEngine: {
66
- cacheMaxAge: 0,
67
70
  layout: {
68
71
  default: 'waibuMpa:/default.html',
69
72
  fallback: true
@@ -81,7 +84,7 @@ async function factory (pkgName) {
81
84
  },
82
85
  component: {
83
86
  unknownTag: 'replaceWithDiv',
84
- cacheMaxAgeDur: '1m'
87
+ ttlDur: '1m'
85
88
  }
86
89
  },
87
90
  iconset: {
@@ -95,7 +98,7 @@ async function factory (pkgName) {
95
98
  }
96
99
  },
97
100
  concatResource: {
98
- cacheMaxAge: 0,
101
+ ttlDur: 0,
99
102
  excluded: [],
100
103
  css: false,
101
104
  scripts: false,
@@ -144,13 +147,10 @@ async function factory (pkgName) {
144
147
  }
145
148
 
146
149
  this.configProd = {
147
- viewEngine: {
148
- cacheMaxAge: 300
149
- },
150
150
  theme: {
151
151
  component: {
152
152
  unknownTag: 'remove',
153
- cacheMaxAge: 300
153
+ ttlDur: '5m'
154
154
  }
155
155
  },
156
156
  prettier: false,
@@ -509,7 +509,6 @@ async function factory (pkgName) {
509
509
  const ext = path.extname(tpl)
510
510
  if (['.json', '.js', '.css'].includes(ext)) opts.partial = true
511
511
  opts.ext = ext
512
- opts.cacheMaxAge = this.config.page.cacheMaxAgeDur
513
512
  const viewEngine = this.getViewEngine(ext)
514
513
  return await viewEngine.render(tpl, locals, opts)
515
514
  }
@@ -7,22 +7,19 @@ async function apply ({ $, req, tag, attr, type }) {
7
7
  const { routePath } = this.app.waibu
8
8
  const { hash, fetch } = this.app.bajoExtra
9
9
  const { isEmpty, map, without } = this.app.lib._
10
- const cache = this.app.bajoCache
10
+ const { get: getCache, set: setCache } = this.app.bajoCache ?? {}
11
+ const prefix = this.app.bajoCache.config.exportPrefix
11
12
  const excluded = map(this.config.concatResource.excluded, item => routePath(item))
12
- let cachePrefix = this.app.bajoCache.config.externalPrefix
13
- if (!cachePrefix) return
14
- cachePrefix += ':'
15
-
16
13
  const baseUrl = `${req.protocol}://${req.hostname}${req.port ? `:${req.port}` : ''}` // TODO: auth, if any
17
14
  const items = []
18
15
  $(`${tag}[${attr}]`).each(function () {
19
16
  items.push(this.attribs[attr])
20
17
  })
21
18
  if (items.length === 0) return
22
- const key = cachePrefix + await hash(items)
23
- const cached = await cache.get({ key })
24
19
  let keys = []
25
20
  const notKeys = []
21
+ const key = `${prefix}-waibu-mpa-concat-resource-${await hash(items)}`
22
+ const cached = await getCache({ key })
26
23
  if (!cached) {
27
24
  const contents = []
28
25
  for (const item of items) {
@@ -46,14 +43,13 @@ async function apply ({ $, req, tag, attr, type }) {
46
43
  }
47
44
  if (isEmpty(contents)) return
48
45
  $(map(keys, k => `${tag}[${attr}="${k}"]`).join(',')).remove()
49
- // await cache.set({ key, value: contents.join('\n'), ttl: this.config.page.cacheMaxAge * 1000 })
50
46
  const value = { contents, notKeys, type, tag, attr }
51
- await cache.set({ key, value, ttl: this.config.concatResource.cacheMaxAge * 1000 })
47
+ await setCache({ key, value, ttl: this.config.concatResource.ttlDur })
52
48
  } else {
53
49
  keys = without(items, ...cached.notKeys)
54
50
  $(map(keys, k => `${tag}[${attr}="${k}"]`).join(',')).remove()
55
51
  }
56
- const rsc = `bajoCache:/external/${key.replace(cachePrefix, '')}.${type}`
52
+ const rsc = `bajoCache:/external/${key.slice(prefix.length + 1)}.${type}`
57
53
  if (tag === 'link') $('head').prepend(printLink.call(this, rsc))
58
54
  else if (tag === 'script') $('body').append(printScript.call(this, rsc))
59
55
  }
@@ -61,7 +57,7 @@ async function apply ({ $, req, tag, attr, type }) {
61
57
  async function concatResources (options) {
62
58
  const { $, req } = options ?? {}
63
59
  if (!(this.app.bajoExtra && this.app.bajoCache)) return
64
- if (this.config.concatResource.cacheMaxAge < 1) return
60
+ if (this.config.concatResource.ttlDur === 0) return
65
61
  if (this.config.concatResource.css) await apply.call(this, { $, req, tag: 'link', attr: 'href', type: 'css' })
66
62
  if (this.config.concatResource.links) await apply.call(this, { $, req, tag: 'link', attr: 'href', type: 'css' })
67
63
  if (this.config.concatResource.scripts) await apply.call(this, { $, req, tag: 'script', attr: 'src', type: 'js' })
@@ -3,7 +3,7 @@ import path from 'path'
3
3
  export async function build ({ files, pathPrefix, dir, ns, cfg, parent, urlPrefix, subRoute }) {
4
4
  const { defaultsDeep } = this.app.lib.aneka
5
5
  const { importModule, readJson } = this.app.bajo
6
- const { isFunction, isPlainObject, pick, last, camelCase } = this.app.lib._
6
+ const { isFunction, isPlainObject, pick, last, camelCase, omit } = this.app.lib._
7
7
  const { titleize } = this.app.lib.aneka
8
8
  const { getPluginPrefix } = this.app.waibu
9
9
  const mergeRouteHooks = await importModule('waibu:/lib/webapp-scope/merge-route-hooks.js')
@@ -45,10 +45,14 @@ export async function build ({ files, pathPrefix, dir, ns, cfg, parent, urlPrefi
45
45
  m.config.prefix = getPluginPrefix(ns)
46
46
  m.config.pathSrc = m.url
47
47
  m.config.webApp = parent ?? ns
48
+ m.config.interSite = m.interSite
48
49
  m.config.ns = ns
49
50
  m.config.subNs = ''
50
51
  m.config.title = m.title ?? camelCase(last(m.url.split('/')))
51
52
  m.config.subRoute = subRoute
53
+ if (m.cache === true) m.cache = omit(me.config.page.cache, ['urls'])
54
+ m.config.cache = defaultsDeep(m.cache ?? {}, { ttlDur: 0 })
55
+
52
56
  delete m.title
53
57
  m = defaultsDeep(pick(cfg, ['exposeHeadRoute', 'bodyLimit']), m)
54
58
  mods.push(m)
@@ -11,7 +11,7 @@ async function componentFactory () {
11
11
  this.locals = locals
12
12
  this.reply = reply
13
13
  this.req = req
14
- this.cacheMaxAge = get(plugin, 'app.waibuMpa.config.theme.component.cacheMaxAgeDur', 0)
14
+ this.ttlDur = get(plugin, 'app.waibuMpa.config.theme.component.ttlDur', 0)
15
15
  this.namespace = 'c:'
16
16
  this.noTags = []
17
17
  this.scriptBlock = scriptBlock
@@ -118,7 +118,7 @@ async function componentFactory () {
118
118
  if (isEmpty(params.html)) return await this.render(params)
119
119
 
120
120
  const merged = merge({}, params.locals, { attr: params.attr })
121
- const result = await compile(params.html, merged, { ttl: this.cacheMaxAge })
121
+ const result = await compile(params.html, merged, { ttl: this.ttlDur })
122
122
  params.html = result
123
123
  return await this.render(params)
124
124
  }
package/lib/decorate.js CHANGED
@@ -1,17 +1,45 @@
1
1
  import path from 'path'
2
2
 
3
+ async function isCacheable (req, cachedUrls) {
4
+ const { hash } = this.app.bajoExtra
5
+ const { get, omit, isFunction } = this.app.lib._
6
+ const ns = get(req, 'routeOptions.config.ns')
7
+ let cache = get(req, 'routeOptions.config.cache', omit(this.config.page.cache, ['urls']))
8
+ cache.methods = cache.methods ?? ['GET']
9
+ if (!ns || (!this.app.bajoCache) || (!req.site) || !cache.methods.includes(req.method)) return { ttl: 0 }
10
+ if (isFunction(cache)) {
11
+ cache = await cache.call(this.app[ns], req, cachedUrls)
12
+ }
13
+ const url = req.url.split('?')[0].split('#')[0]
14
+ for (const item of cachedUrls) {
15
+ if (item.isMatch(url)) cache.ttlDur = item.ttlDur ?? cache.ttlDur
16
+ }
17
+ const key = `waibu-mpa-page-${req.site.id}-${cache.key ?? (await hash(req.url))}`
18
+ return { key, ttl: cache.ttlDur }
19
+ }
20
+
3
21
  async function decorate () {
4
22
  const { importPkg } = this.app.bajo
5
- const { isEmpty } = this.app.lib._
23
+ const { isString, cloneDeep, isEmpty } = this.app.lib._
24
+ const { get: getCache, set: setCache } = this.app.bajoCache ?? {}
25
+ const { outmatch } = this.app.lib
26
+ const { routePath } = this.app.waibu
6
27
  const mime = await importPkg('waibu:mime')
7
28
  const cfg = this.config
8
29
  const me = this
30
+ const cachedUrls = cloneDeep(this.config.page.cache.urls).map(item => {
31
+ if (isString(item)) item = { url: item }
32
+ item.url = routePath(item.url)
33
+ item.isMatch = outmatch(item.url)
34
+ return item
35
+ })
9
36
  this.webAppCtx.decorateRequest('theme', cfg.theme.set)
10
37
  this.webAppCtx.decorateRequest('iconset', cfg.iconset.set)
11
38
  this.webAppCtx.decorateRequest('darkMode', cfg.darkMode.set)
12
39
  this.webAppCtx.decorateRequest('referer', '')
13
40
  this.webAppCtx.decorateReply('ctags', null)
14
41
  this.webAppCtx.decorateReply('view', async function (tpl, params = {}, opts = {}) {
42
+ // this = fastify context!
15
43
  let ext = path.extname(tpl)
16
44
  if (ext === '.md') ext = '.html'
17
45
  let mimeType = isEmpty(ext) ? 'text/html' : mime.getType(ext)
@@ -24,7 +52,16 @@ async function decorate () {
24
52
  if (!this.request[item]) this.request[item] = me[item + 's'][0].name
25
53
  if (me[item + 's'].length === 1) this.request[item] = me[item + 's'][0].name
26
54
  }
55
+ const { key, ttl } = await isCacheable.call(me, this.request, cachedUrls)
56
+ if (ttl > 0) {
57
+ const cached = await getCache({ key })
58
+ if (cached) {
59
+ this.header('X-Wmpa-Cached', true)
60
+ return cached
61
+ }
62
+ }
27
63
  const result = await me.render(tpl, params, opts)
64
+ if (ttl > 0) await setCache({ key, value: result, ttl })
28
65
  if (this.request.session) {
29
66
  ext = path.extname(this.request.url)
30
67
  if (isEmpty(ext) || ['.html'].includes(ext)) {
@@ -19,7 +19,7 @@ async function loadResource (mod = [], item) {
19
19
  } else items.push(mod[item][i])
20
20
  }
21
21
  for (const c of extItems) {
22
- let emod = await readConfig(`${c.ns}:${c.path}`, { ns: c.ns })
22
+ let emod = await readConfig(`${c.ns}:${c.path}`, { ns: c.ns, ignoreError: false })
23
23
  if (!isArray(emod)) emod = [emod]
24
24
  for (const m of emod) {
25
25
  items.push(m)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "waibu-mpa",
3
- "version": "2.10.1",
3
+ "version": "2.12.0",
4
4
  "description": "MPA support for Waibu Framework",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/wiki/CHANGES.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changes
2
2
 
3
+ ## 2026-03-30
4
+
5
+ - [2.12.0] Add inter site module support
6
+
7
+ ## 2026-03-27
8
+
9
+ - [2.11.0] Add options to enable cache with Bajo Cache module
10
+ - [2.11.0] Change all ```cacheMaxAge``` keys to ```ttlDur``` to align with above mentioned cache engine
11
+
3
12
  ## 2026-03-22
4
13
 
5
14
  - [2.10.1] Bug fix in applying routes to ```webCtx```