source: Klonkt/test/asset-cache-busting.test.js@ 369aa60

main
Last change on this file since 369aa60 was 369aa60, checked in by Robin <roboburr@…>, 4 days ago

Cache-busting reikt nu ook tot wat de modules zelf ophalen (shaer-724)

De bootstrap hing al ?v= aan elke module die hij zelf laadt. Twee soorten
paden ontsnapten daaraan, en /assets wordt buiten ontwikkeling een jaar
gecachet:

een import BINNEN een module is relatief, en zo\x27n specifier erft de
query niet: ./lib.js naast post.js?v=63 wordt gewoon
/assets/js/mod/lib.js. Elf modules importeren lib.js zo, en juist dat
bestand is gedeeld -- een fout erin overleefde elke MOD_V-bump.

een vendorbestand dat een module zelf ophaalt. read.js deed het goed met
?v=VENDOR_V; lib.js (mijn eigen import van gisteren) en de twee
cropper-verwijzingen in post-edit deden het niet.

Een importmap in de head lost het eerste op zonder die elf imports aan te
raken: hij vertaalt de opgeloste URL naar zijn geversioneerde vorm. MOD_V
staat daarvoor nu als EJS-variabele bovenaan de shell, zodat de importmap
en de bootstrap niet twee nummers kunnen worden. VENDOR_V staat in lib.js
en wordt door read.js en post-edit gedeeld, om dezelfde reden.

Drie toetsen die de REGEL bewaken en niet deze ene plek: elke relatieve
import tussen modules heeft een ingang in de importmap, elk vendorpad
draagt een versie, en de twee nummers zijn er een. Tegenbewijs: haal de
ingang weg of de versie eraf en precies die toets valt.

Volle suite 1248 groen.

  • Property mode set to 100644
File size: 3.0 KB
Line 
1// Geen asset-URL zonder cache-buster (shaer-724).
2//
3// /assets wordt buiten ontwikkeling een JAAR gecachet. Een pad zonder `?v=`
4// blijft dus een jaar staan bij iedereen die het ooit ophaalde, en dan draait
5// een terugkerende bezoeker oude code tegen nieuwe templates -- onreproduceerbaar
6// per bezoeker, want het hangt af van wanneer hij hier voor het laatst was.
7//
8// De bootstrap hangt ?v= aan de modules die hij ZELF laadt. Twee soorten paden
9// ontsnappen daaraan, en allebei zijn ze een keer misgegaan:
10//
11// een import BINNEN een module is relatief, en een relatieve specifier erft
12// de query niet: `./lib.js` naast `post.js?v=63` wordt `/assets/js/mod/lib.js`.
13// Daar is de importmap in de shell voor.
14//
15// een vendorbestand dat een module zelf ophaalt (import, script- of
16// link-element). Die hoort ?v=${VENDOR_V} te dragen.
17//
18// Deze toets leest de bron, en dat is hier op zijn plaats: het gaat om de vorm
19// van een URL in de code, niet om gedrag dat je kunt aanroepen.
20import { test } from 'node:test';
21import assert from 'node:assert/strict';
22import fs from 'node:fs';
23import path from 'node:path';
24import { fileURLToPath } from 'node:url';
25
26const WORTEL = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
27const MOD_DIR = path.join(WORTEL, 'src', 'assets', 'js', 'mod');
28const SHELL = fs.readFileSync(path.join(WORTEL, 'src', 'views', 'shell.ejs'), 'utf8');
29
30const modules = fs.readdirSync(MOD_DIR).filter((n) => n.endsWith('.js'));
31const bron = (naam) => fs.readFileSync(path.join(MOD_DIR, naam), 'utf8');
32
33test('elke relatieve import tussen modules staat in de importmap', () => {
34 // De importmap is de enige plek waar zo\'n pad zijn versie kan krijgen, want
35 // de import zelf kan hem niet meedragen.
36 const ontbreekt = [];
37 for (const naam of modules) {
38 for (const m of bron(naam).matchAll(/from\s+'(\.\.?\/[^']+)'/g)) {
39 const doel = path.posix.normalize(path.posix.join('/assets/js/mod', m[1]));
40 if (!SHELL.includes(`"${doel}":`)) ontbreekt.push(`${naam} -> ${doel}`);
41 }
42 }
43 assert.deepEqual(ontbreekt, [],
44 'zonder ingang in de importmap wordt dit pad kaal opgehaald en een jaar bewaard');
45});
46
47test('elk vendorbestand dat een module ophaalt draagt een versie', () => {
48 const kaal = [];
49 for (const naam of modules) {
50 for (const m of bron(naam).matchAll(/['"`]\/assets\/vendor\/[^'"`]+['"`]/g)) {
51 if (!m[0].includes('?v=')) kaal.push(`${naam}: ${m[0]}`);
52 }
53 }
54 assert.deepEqual(kaal, [], 'voeg ?v=${VENDOR_V} toe, anders blijft de oude bibliotheek een jaar staan');
55});
56
57test('de importmap en de bootstrap delen een nummer', () => {
58 // Twee losse nummers lopen een keer uit elkaar, en dan verspringt de ene
59 // helft van de modules wel en de andere niet.
60 const uitEjs = SHELL.match(/const MOD_V = (\d+);/);
61 assert.ok(uitEjs, 'MOD_V hoort als EJS-variabele bovenaan de shell te staan');
62 assert.match(SHELL, /var MOD_V = <%= MOD_V %>;/, 'de bootstrap hoort dat nummer te gebruiken, niet een eigen kopie');
63 assert.match(SHELL, /\?v=<%= MOD_V %>/, 'en de importmap ook');
64});
Note: See TracBrowser for help on using the repository browser.