diff --git a/api/collections/backups.yml b/api/collections/backups.yml index 1876bef..0d6051a 100644 --- a/api/collections/backups.yml +++ b/api/collections/backups.yml @@ -29,6 +29,13 @@ hooks: create: type: javascript file: hooks/backups/post_create.js + return: + type: javascript + file: hooks/clear_cache.js + put: + return: + type: javascript + file: hooks/clear_cache.js fields: - name: collectionName diff --git a/api/collections/banner.yml b/api/collections/banner.yml index 81d4eaf..eeee386 100644 --- a/api/collections/banner.yml +++ b/api/collections/banner.yml @@ -25,6 +25,15 @@ permissions: post: true put: true delete: true +hooks: + post: + return: + type: javascript + file: hooks/clear_cache.js + put: + return: + type: javascript + file: hooks/clear_cache.js fields: - name: banner diff --git a/api/collections/content.yml b/api/collections/content.yml index 9fb33ab..1f55b0b 100644 --- a/api/collections/content.yml +++ b/api/collections/content.yml @@ -98,6 +98,16 @@ projections: select: path: 1 +hooks: + post: + return: + type: javascript + file: hooks/clear_cache.js + put: + return: + type: javascript + file: hooks/clear_cache.js + fields: - type: string name: path diff --git a/api/collections/navigation.yml b/api/collections/navigation.yml index 4186c58..b2a88bc 100644 --- a/api/collections/navigation.yml +++ b/api/collections/navigation.yml @@ -82,6 +82,15 @@ x-seite: &seite mapping: id: id name: path +hooks: + post: + return: + type: javascript + file: hooks/clear_cache.js + put: + return: + type: javascript + file: hooks/clear_cache.js fields: - name: tree diff --git a/api/hooks/clear_cache.js b/api/hooks/clear_cache.js new file mode 100644 index 0000000..7491038 --- /dev/null +++ b/api/hooks/clear_cache.js @@ -0,0 +1,5 @@ +var utils = require("./lib/utils") + +;(function () { + utils.clearSSRCache() +})() diff --git a/api/hooks/config.js b/api/hooks/config.js index 86fa44d..f4e436a 100644 --- a/api/hooks/config.js +++ b/api/hooks/config.js @@ -1,18 +1,26 @@ +const apiSsrBaseURL = "http://localhost:8080/api/v1/_/allkids_erfurt" + module.exports = { + apiSsrBaseURL, ssrValidatePath: function (path) { // validate if path ssr rendering is ok, -1 = NOTFOUND, 0 = NO SSR, 1 = SSR // pe. use context.readCollection("product", {filter: {path: path}}) ... to validate dynamic urls - // / is de home - if (path == "/") return 1 + // // / is de home + // if (path == "/") return 1 + // // all other sites are in db + //path = path?.replace(/^\//, "") + console.log("PATH:", path) // filter for path or alternativePaths const resp = context.db.find("content", { filter: { - $or: [{ path }], + $and: [{ path }], }, + selector: { _id: 1 }, }) + console.log("RESP:", resp?.length) if (resp && resp.length) { return 1 } @@ -20,5 +28,5 @@ module.exports = { // not found return -1 }, - ssrAllowedAPIEndpoints: ["content", "medialib"], + ssrPublishCheckCollections: ["content"], } diff --git a/api/hooks/lib/ssr-server.js b/api/hooks/lib/ssr-server.js new file mode 100644 index 0000000..14a87b5 --- /dev/null +++ b/api/hooks/lib/ssr-server.js @@ -0,0 +1,36 @@ +const { apiSsrBaseURL, ssrPublishCheckCollections } = require("../config") + +/** + * api request via server, cache result in context.ssrCache + * should be elimated in client code via tree shaking + * + * @param {string} cacheKey + * @param {string} endpoint + * @param {ApiOptions} options + * @returns {ApiResult} + */ +function ssrRequest(cacheKey, endpoint, query, options) { + let url = endpoint + (query ? "?" + query : "") + + // console.log("############ FETCHING ", apiSsrBaseURL + url) + + const response = context.http.fetch(apiSsrBaseURL + "/" + url, { + method: options.method, + headers: options.headers, + }) + + const json = response.body.json() + const count = parseInt(response.headers["x-results-count"] || "0") + + // json is go data structure and incompatible with js, so we need to convert it + const r = { data: JSON.parse(JSON.stringify(json)), count: count } + + // @ts-ignore + context.ssrCache[cacheKey] = r + + return r +} + +module.exports = { + ssrRequest, +} diff --git a/api/hooks/lib/ssr.js b/api/hooks/lib/ssr.js index e97f4fb..0f1def6 100644 --- a/api/hooks/lib/ssr.js +++ b/api/hooks/lib/ssr.js @@ -110,6 +110,7 @@ function apiRequest(endpoint, options, body) { // first check cache if on client const cacheKey = obj2str({ endpoint: endpoint, options: options }) + options.method = options?.method || "GET" // @ts-ignore if (typeof window !== "undefined" && window.__SSR_CACHE__ && options?.method === "GET") { @@ -153,6 +154,7 @@ function apiRequest(endpoint, options, body) { } else { // client let url = endpoint + (query ? "?" + query : "") + console.log("URL:", url) const requestOptions = { method, mode: "cors", diff --git a/api/hooks/lib/utils.js b/api/hooks/lib/utils.js index 9020477..922ef24 100644 --- a/api/hooks/lib/utils.js +++ b/api/hooks/lib/utils.js @@ -38,8 +38,6 @@ function obj2str(obj) { if (obj) return obj } - - /** * clear SSR cache */ diff --git a/api/hooks/ssr/get_read.js b/api/hooks/ssr/get_read.js index 13c78cc..94784ab 100644 --- a/api/hooks/ssr/get_read.js +++ b/api/hooks/ssr/get_read.js @@ -1,16 +1,19 @@ -const { ssrValidatePath, ssrAllowedAPIEndpoints } = require("../config") +// TODO: add query string functionality to cache + +const { ssrValidatePath } = require("../config") +const { log } = require("../lib/utils") +const { ssrRequest } = require("../lib/ssr-server.js") -const { obj2str, log } = require("../lib/utils") ;(function () { /** @type {HookResponse} */ - var response = null - console.log("SSR GET READ") - var request = context.request() - var url = request.query("url") - var noCache = request.query("noCache") + let response = null + + const request = context.request() + let url = request.query("url") + const noCache = request.query("noCache") // add sentry trace id to head - var trace_id = context.debug.sentryTraceId() + const trace_id = context.debug.sentryTraceId() function addSentryTrace(content) { return content.replace("", '') } @@ -18,7 +21,9 @@ const { obj2str, log } = require("../lib/utils") if (url) { // comment will be printed to html later - var comment = "" + let comment = "" + /** @type {Date} */ // @ts-ignore + context.ssrCacheValidUntil = null url = url.split("?")[0] comment += "url: " + url @@ -31,7 +36,8 @@ const { obj2str, log } = require("../lib/utils") } // check if url is in cache - var cache = + /** @type {Ssr[]} */ // @ts-ignore + const cache = !noCache && context.db.find("ssr", { filter: { @@ -40,6 +46,7 @@ const { obj2str, log } = require("../lib/utils") }) if (cache && cache.length) { // use cache + context.response.header("X-SSR-Cache", "true") throw { status: 200, log: false, @@ -48,85 +55,50 @@ const { obj2str, log } = require("../lib/utils") } // validate url - var status = 200 + let status = 200 - var pNorender = false - var pNotfound = false + let pNorender = false + let pNotfound = false - var pR = ssrValidatePath(url) + const pR = ssrValidatePath(url) if (pR < 0) { pNotfound = true } else if (!pR) { pNorender = true } - var head = "" - var html = "" - var error = "" + let head = "" + let html = "" + let error = "" comment += ", path: " + url - var cacheIt = false + let cacheIt = false if (pNorender) { html = "" } else if (pNotfound) { status = 404 - console.log("IS 404") html = "404 NOT FOUND" } else { + // @ts-ignore + context.ssrCache = {} + // @ts-ignore + context.ssrRequest = ssrRequest + // try rendering, if error output plain html try { - // @ts-ignore - context.ssrCache = {} - // @ts-ignore - context.ssrFetch = function (endpoint, options) { - var data - if (ssrAllowedAPIEndpoints.indexOf(endpoint) > -1) { - var _options = Object.assign({}, options) - - if (_options.sort) _options.sort = [_options.sort] - - try { - /*console.log( - "SSR", - endpoint, - JSON.stringify(_options) - )*/ - var goSlice = context.db.find(endpoint, _options || {}) - // need to deep copy, so shift and delete on pure js is possible - data = JSON.parse(JSON.stringify(goSlice)) - } catch (e) { - console.log("ERROR", JSON.stringify(e)) - data = [] - } - } else { - console.log("SSR forbidden", endpoint) - data = [] - } - - var count = (data && data.length) || 0 - if (options && count == options.limit) { - // read count from db - count = context.db.count(endpoint, _options || {}) - } - var r = { data: data, count: count } - - // @ts-ignore - context.ssrCache[obj2str({ endpoint: endpoint, options: options })] = r - - return r - } - // include App.svelte and render it // @ts-ignore - var app = require("../lib/app.server") - var rendered = app.default.render({ + + // console.log("####### RENDERING ", url) + const app = require("../lib/app.server") + const rendered = app.default.render({ url: url, }) head = rendered.head html = rendered.html - // add ssrCache to head + // add ssrCache to head, cache is built in ssr.js/apiRequest head += "\n\n" + "
- {#if index % 2 == 0 || window?.innerWidth < 1023} + {#if index % 2 == 0 || typeof window !== 'undefined' && window?.innerWidth < 1023} {/if}
@@ -14,7 +14,7 @@

{site?.teaserDescription}

- {#if index % 2 == 1 && window?.innerWidth > 1023} + {#if index % 2 == 1 && typeof window !== 'undefined' && window?.innerWidth > 1023} {/if}
diff --git a/types/global.d.ts b/types/global.d.ts index 7c4c1a1..6a9a136 100644 --- a/types/global.d.ts +++ b/types/global.d.ts @@ -6,7 +6,12 @@ interface ApiResult { data: T count: number } - +interface Ssr { + id?: string + path: string + content: string + validUntil: any // go Time +} interface ApiOptions { method?: string filter?: any