diff --git a/content b/content index fa930e8..b171557 160000 --- a/content +++ b/content @@ -1 +1 @@ -Subproject commit fa930e8ffd2d0701dca51ef301f838e2d0c90ac2 +Subproject commit b17155773ee5df21bebc69dc53bbb3548f383cde diff --git a/package.json b/package.json index 8004987..ff34fff 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,9 @@ "stop-main": "node_modules/pm2/bin/pm2 delete expressjs-blog-main", "stop-testing": "node_modules/pm2/bin/pm2 delete expressjs-blog-testing", "test:prepush": "node scripts/test-prepush.js --no-color", + "test:prepush:coverage": "node scripts/test-prepush.js --no-color --coverage", "test:postreceive": "node scripts/test-postreceive.js --no-color", + "test:postreceive:coverage": "node scripts/test-postreceive.js --no-color --coverage", "update-submodules": "git submodule update --init --recursive --remote" }, "imports": { @@ -68,6 +70,7 @@ }, "devDependencies": { "@faker-js/faker": "^9.9.0", + "c8": "^11.0.0", "chai": "^6.2.2", "chai-as-promised": "^8.0.1", "fast-check": "^4.2.0", diff --git a/src/utils/htmlRoutes.js b/src/utils/htmlRoutes.js index 2b1ba96..bdbb50c 100644 --- a/src/utils/htmlRoutes.js +++ b/src/utils/htmlRoutes.js @@ -9,6 +9,8 @@ class HtmlRoutes extends BaseRoute { constructor() { super(); + this.shouldCache = process.env.NODE_ENV === "production"; + this.cache = new Map(); } /** @@ -23,56 +25,60 @@ `../../content/html/${contentFolder}`, ); const configPath = path.join(folderPath, `config.yaml`); + // The router's endpoint + const assetsRouterPath = path.join(routePath, "assets"); + this.router.use(assetsRouterPath, express.static(folderPath)); const configRaw = await fs.readFile(configPath, "utf8"); const pageConfig = yaml.load(configRaw); - // Fetch the actual HTML file name from the YAML config - const filePath = path.join(folderPath, pageConfig.file); - const htmlContent = await fs.readFile(filePath, "utf8"); - - const assetsDir = path.join( - __dirname, - `../../content/html/${pageConfig.slug}`, - ); - - // The router's endpoint - const assetsRouterPath = path.join(routePath, "assets"); - - // -- The uri - const assetsUri = baseUrl + assetsRouterPath; - - const extraStyles = pageConfig.styles.map( - (stylePath) => assetsUri + "/" + stylePath, - ); - const extraScripts = pageConfig.scripts.map( - (scriptsPath) => assetsUri + "/" + scriptsPath, - ); - - const context = { - title: pageConfig.title || "Default Title", - slug: routePath, - content: htmlContent, - extraStyles: extraStyles || [], - extraScripts: extraScripts || [], - meta: pageConfig.meta || {}, - }; - - /* - console.log("Assets Router Path", assetsRouterPath); - console.log("Assets URI", assetsUri); - console.log("Assets Dir", assetsDir); - console.log("extraScripts", extraScripts); - console.log("extraStyles", extraStyles); - */ - - this.router.use(assetsRouterPath, express.static(assetsDir)); this.router.get(routePath, async (req, res, next) => { // Renders the web page on each request // Moving the logic outside of the function would read contents ahead of time // Keeping the logic intact would allow editing files without reloading the server try { - res.renderWithBaseContext(`pages/${pageConfig.page}`, context); + // Return cached version if enabled and exists + if (this.shouldCache && this.cache.has(routePath)) { + return res.renderWithBaseContext( + this.cache.get(routePath).template, + this.cache.get(routePath).context, + ); + } + // Fetch the actual HTML file name from the YAML config + const filePath = path.join(folderPath, pageConfig.file); + const htmlContent = await fs.readFile(filePath, "utf8"); + + // -- The uri + const assetsUri = baseUrl + assetsRouterPath; + + const extraStyles = pageConfig.styles.map( + (stylePath) => assetsUri + "/" + stylePath, + ); + const extraScripts = pageConfig.scripts.map( + (scriptsPath) => assetsUri + "/" + scriptsPath, + ); + + const context = { + title: pageConfig.title || "Default Title", + slug: routePath, + content: htmlContent, + extraStyles: extraStyles || [], + extraScripts: extraScripts || [], + meta: pageConfig.meta || {}, + }; + /* + console.log("Assets Router Path", assetsRouterPath); + console.log("Assets URI", assetsUri); + console.log("extraScripts", extraScripts); + console.log("extraStyles", extraStyles); + */ + const template = `pages/${pageConfig.page}`; + + // 4. Update Cache + if (this.shouldCache) { + this.cache.set(routePath, { template, context }); + } + res.renderWithBaseContext(template, context); } catch (err) { err.statusCode = 500; next(err); diff --git a/yarn.lock b/yarn.lock index 0a925f4..17c8df5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23,6 +23,13 @@ languageName: node linkType: hard +"@bcoe/v8-coverage@npm:^1.0.1": + version: 1.0.2 + resolution: "@bcoe/v8-coverage@npm:1.0.2" + checksum: 10c0/1eb1dc93cc17fb7abdcef21a6e7b867d6aa99a7ec88ec8207402b23d9083ab22a8011213f04b2cf26d535f1d22dc26139b7929e6c2134c254bd1e14ba5e678c3 + languageName: node + linkType: hard + "@colors/colors@npm:1.6.0, @colors/colors@npm:^1.6.0": version: 1.6.0 resolution: "@colors/colors@npm:1.6.0" @@ -381,6 +388,37 @@ languageName: node linkType: hard +"@istanbuljs/schema@npm:^0.1.2, @istanbuljs/schema@npm:^0.1.3": + version: 0.1.3 + resolution: "@istanbuljs/schema@npm:0.1.3" + checksum: 10c0/61c5286771676c9ca3eb2bd8a7310a9c063fb6e0e9712225c8471c582d157392c88f5353581c8c9adbe0dff98892317d2fdfc56c3499aa42e0194405206a963a + languageName: node + linkType: hard + +"@jridgewell/resolve-uri@npm:^3.1.0": + version: 3.1.2 + resolution: "@jridgewell/resolve-uri@npm:3.1.2" + checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e + languageName: node + linkType: hard + +"@jridgewell/sourcemap-codec@npm:^1.4.14": + version: 1.5.5 + resolution: "@jridgewell/sourcemap-codec@npm:1.5.5" + checksum: 10c0/f9e538f302b63c0ebc06eecb1dd9918dd4289ed36147a0ddce35d6ea4d7ebbda243cda7b2213b6a5e1d8087a298d5cf630fb2bd39329cdecb82017023f6081a0 + languageName: node + linkType: hard + +"@jridgewell/trace-mapping@npm:^0.3.12": + version: 0.3.31 + resolution: "@jridgewell/trace-mapping@npm:0.3.31" + dependencies: + "@jridgewell/resolve-uri": "npm:^3.1.0" + "@jridgewell/sourcemap-codec": "npm:^1.4.14" + checksum: 10c0/4b30ec8cd56c5fd9a661f088230af01e0c1a3888d11ffb6b47639700f71225be21d1f7e168048d6d4f9449207b978a235c07c8f15c07705685d16dc06280e9d9 + languageName: node + linkType: hard + "@npmcli/agent@npm:^4.0.0": version: 4.0.0 resolution: "@npmcli/agent@npm:4.0.0" @@ -561,6 +599,13 @@ languageName: node linkType: hard +"@types/istanbul-lib-coverage@npm:^2.0.1": + version: 2.0.6 + resolution: "@types/istanbul-lib-coverage@npm:2.0.6" + checksum: 10c0/3948088654f3eeb45363f1db158354fb013b362dba2a5c2c18c559484d5eb9f6fd85b23d66c0a7c2fcfab7308d0a585b14dadaca6cc8bf89ebfdc7f8f5102fb7 + languageName: node + linkType: hard + "@types/node@npm:*": version: 24.1.0 resolution: "@types/node@npm:24.1.0" @@ -1143,6 +1188,32 @@ languageName: node linkType: hard +"c8@npm:^11.0.0": + version: 11.0.0 + resolution: "c8@npm:11.0.0" + dependencies: + "@bcoe/v8-coverage": "npm:^1.0.1" + "@istanbuljs/schema": "npm:^0.1.3" + find-up: "npm:^5.0.0" + foreground-child: "npm:^3.1.1" + istanbul-lib-coverage: "npm:^3.2.0" + istanbul-lib-report: "npm:^3.0.1" + istanbul-reports: "npm:^3.1.6" + test-exclude: "npm:^8.0.0" + v8-to-istanbul: "npm:^9.0.0" + yargs: "npm:^17.7.2" + yargs-parser: "npm:^21.1.1" + peerDependencies: + monocart-coverage-reports: ^2 + peerDependenciesMeta: + monocart-coverage-reports: + optional: true + bin: + c8: bin/c8.js + checksum: 10c0/94b0cf8756715ca8fedb9331c61ebda0c5bbd63c5eeea523d18904af790f6f197a02f547c066fa2d8d0544bb9f9547a6a67d653f3575953139c74ca915771963 + languageName: node + linkType: hard + "cacache@npm:^15.2.0": version: 15.3.0 resolution: "cacache@npm:15.3.0" @@ -1553,6 +1624,13 @@ languageName: node linkType: hard +"convert-source-map@npm:^2.0.0": + version: 2.0.0 + resolution: "convert-source-map@npm:2.0.0" + checksum: 10c0/8f2f7a27a1a011cc6cc88cc4da2d7d0cfa5ee0369508baae3d98c260bb3ac520691464e5bbe4ae7cdf09860c1d69ecc6f70c63c6e7c7f7e3f18ec08484dc7d9b + languageName: node + linkType: hard + "cookie-parser@npm:^1.4.7": version: 1.4.7 resolution: "cookie-parser@npm:1.4.7" @@ -2116,6 +2194,7 @@ "@glint/core": "npm:^1.5.2" better-sqlite3: "npm:^12.2.0" body-parser: "npm:^2.2.0" + c8: "npm:^11.0.0" chai: "npm:^6.2.2" chai-as-promised: "npm:^8.0.1" compression: "npm:^1.8.1" @@ -2458,7 +2537,7 @@ languageName: node linkType: hard -"foreground-child@npm:^3.1.0, foreground-child@npm:^3.3.1": +"foreground-child@npm:^3.1.0, foreground-child@npm:^3.1.1, foreground-child@npm:^3.3.1": version: 3.3.1 resolution: "foreground-child@npm:3.3.1" dependencies: @@ -2726,7 +2805,7 @@ languageName: node linkType: hard -"glob@npm:^13.0.0": +"glob@npm:^13.0.0, glob@npm:^13.0.6": version: 13.0.6 resolution: "glob@npm:13.0.6" dependencies: @@ -2913,6 +2992,13 @@ languageName: node linkType: hard +"html-escaper@npm:^2.0.0": + version: 2.0.2 + resolution: "html-escaper@npm:2.0.2" + checksum: 10c0/208e8a12de1a6569edbb14544f4567e6ce8ecc30b9394fcaa4e7bb1e60c12a7c9a1ed27e31290817157e8626f3a4f29e76c8747030822eb84a6abb15c255f0a0 + languageName: node + linkType: hard + "http-cache-semantics@npm:^4.1.0, http-cache-semantics@npm:^4.1.1": version: 4.2.0 resolution: "http-cache-semantics@npm:4.2.0" @@ -3296,6 +3382,34 @@ languageName: node linkType: hard +"istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0": + version: 3.2.2 + resolution: "istanbul-lib-coverage@npm:3.2.2" + checksum: 10c0/6c7ff2106769e5f592ded1fb418f9f73b4411fd5a084387a5410538332b6567cd1763ff6b6cadca9b9eb2c443cce2f7ea7d7f1b8d315f9ce58539793b1e0922b + languageName: node + linkType: hard + +"istanbul-lib-report@npm:^3.0.0, istanbul-lib-report@npm:^3.0.1": + version: 3.0.1 + resolution: "istanbul-lib-report@npm:3.0.1" + dependencies: + istanbul-lib-coverage: "npm:^3.0.0" + make-dir: "npm:^4.0.0" + supports-color: "npm:^7.1.0" + checksum: 10c0/84323afb14392de8b6a5714bd7e9af845cfbd56cfe71ed276cda2f5f1201aea673c7111901227ee33e68e4364e288d73861eb2ed48f6679d1e69a43b6d9b3ba7 + languageName: node + linkType: hard + +"istanbul-reports@npm:^3.1.6": + version: 3.2.0 + resolution: "istanbul-reports@npm:3.2.0" + dependencies: + html-escaper: "npm:^2.0.0" + istanbul-lib-report: "npm:^3.0.0" + checksum: 10c0/d596317cfd9c22e1394f22a8d8ba0303d2074fe2e971887b32d870e4b33f8464b10f8ccbe6847808f7db485f084eba09e6c2ed706b3a978e4b52f07085b8f9bc + languageName: node + linkType: hard + "jackspeak@npm:^3.1.2": version: 3.4.3 resolution: "jackspeak@npm:3.4.3" @@ -3590,6 +3704,15 @@ languageName: node linkType: hard +"make-dir@npm:^4.0.0": + version: 4.0.0 + resolution: "make-dir@npm:4.0.0" + dependencies: + semver: "npm:^7.5.3" + checksum: 10c0/69b98a6c0b8e5c4fe9acb61608a9fbcfca1756d910f51e5dbe7a9e5cfb74fca9b8a0c8a0ffdf1294a740826c1ab4871d5bf3f62f72a3049e5eac6541ddffed68 + languageName: node + linkType: hard + "make-fetch-happen@npm:^15.0.0": version: 15.0.4 resolution: "make-fetch-happen@npm:15.0.4" @@ -6058,6 +6181,17 @@ languageName: node linkType: hard +"test-exclude@npm:^8.0.0": + version: 8.0.0 + resolution: "test-exclude@npm:8.0.0" + dependencies: + "@istanbuljs/schema": "npm:^0.1.2" + glob: "npm:^13.0.6" + minimatch: "npm:^10.2.2" + checksum: 10c0/f2b613cb5ddc05d1357892f5da965a6f7af42b19a6b2fc30c9b93cb74adf5059a3a9f29818adb75c96c1747b3934caac90a9058f73ce0640ea101de828a11600 + languageName: node + linkType: hard + "text-decoder@npm:^1.1.0": version: 1.2.3 resolution: "text-decoder@npm:1.2.3" @@ -6375,6 +6509,17 @@ languageName: node linkType: hard +"v8-to-istanbul@npm:^9.0.0": + version: 9.3.0 + resolution: "v8-to-istanbul@npm:9.3.0" + dependencies: + "@jridgewell/trace-mapping": "npm:^0.3.12" + "@types/istanbul-lib-coverage": "npm:^2.0.1" + convert-source-map: "npm:^2.0.0" + checksum: 10c0/968bcf1c7c88c04df1ffb463c179558a2ec17aa49e49376120504958239d9e9dad5281aa05f2a78542b8557f2be0b0b4c325710262f3b838b40d703d5ed30c23 + languageName: node + linkType: hard + "validator@npm:^13.15.15": version: 13.15.15 resolution: "validator@npm:13.15.15"