vanilla-jet 1.5.5 → 1.6.1
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.
- package/CHANGELOG.md +36 -0
- package/README.md +81 -91
- package/framework/router.js +11 -1
- package/framework/server.js +1 -0
- package/gulpfile.js +4 -2
- package/package.json +1 -6
- package/scripts/compile_html.js +48 -1
- package/scripts/generate_sw.js +2 -1
- package/test/router.test.js +12 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,42 @@ All notable project changes are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format follows a structure inspired by Keep a Changelog and semantic versioning.
|
|
6
6
|
|
|
7
|
+
## [1.6.1] - 2026-06-29
|
|
8
|
+
|
|
9
|
+
### Security
|
|
10
|
+
|
|
11
|
+
- **Removed unused dependencies that carried known vulnerabilities:** `jsrsasign` (multiple high/critical
|
|
12
|
+
crypto advisories), `jwt-simple`, `blueimp-md5`, `js-beautify`, and `nodemon`. None were used by the
|
|
13
|
+
framework; this drops a large vulnerability + install-size footprint for consumers.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **`settings.profile.static_cache_max_age`** (seconds, default `0`): sets `Cache-Control: public, max-age=N`
|
|
18
|
+
for NON-versioned static assets (images, fonts, animation JSON…), so they are reused across references
|
|
19
|
+
and reloads instead of revalidating every time. Versioned (`?v=`) assets stay `immutable`; `0` keeps the
|
|
20
|
+
previous `no-cache` behavior. Pairs with the service worker for clients without it (e.g. WebViews).
|
|
21
|
+
|
|
22
|
+
## [1.6.0] - 2026-06-29
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- **Template externalization (opt-in):** `settings.profile.externalize_templates`. `compile_html.js`
|
|
27
|
+
moves `<script type="text/template">` blocks out of the page into a cacheable `public/scripts/templates.js`
|
|
28
|
+
(loaded `defer` before the app bundle, so views still find their templates in the DOM at boot). Shrinks
|
|
29
|
+
the initial HTML dramatically; the templates file is brotli + immutable + service-worker cached. The SW
|
|
30
|
+
precache now includes `templates.js`.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- **Watch keeps precompressed assets fresh:** `compressBr` now runs in the LESS/JS watch series, so `.gz`/`.br`
|
|
35
|
+
no longer go stale on incremental dev rebuilds.
|
|
36
|
+
|
|
37
|
+
### Notes
|
|
38
|
+
|
|
39
|
+
- Recommended: enable caching features (`enable_service_worker`, `externalize_templates`, precompression,
|
|
40
|
+
immutable) in `qa`/`production`; keep `enable_service_worker` **off in development` so a cache-first SW does
|
|
41
|
+
not serve stale assets during rapid rebuilds.
|
|
42
|
+
|
|
7
43
|
## [1.5.5] - 2026-06-28
|
|
8
44
|
|
|
9
45
|
### Changed
|
package/README.md
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
# VanillaJet
|
|
2
2
|
|
|
3
|
-
Node.js framework for building SPA applications
|
|
3
|
+
Node.js framework for building SPA applications: a Gulp build pipeline (JS/CSS/HTML), a lightweight
|
|
4
|
+
HTTP/HTTPS server, an internal router, and template/resource utilities — with first-class, opt-in
|
|
5
|
+
performance features (Brotli, immutable caching, a generated service worker, deferred scripts, and
|
|
6
|
+
template externalization).
|
|
4
7
|
|
|
5
8
|

|
|
6
9
|
|
|
7
10
|
## Current version
|
|
8
11
|
|
|
9
|
-
- Version: `1.
|
|
10
|
-
- Changelog:
|
|
11
|
-
-
|
|
12
|
+
- Version: `1.6.0`
|
|
13
|
+
- Changelog: [`CHANGELOG.md`](./CHANGELOG.md)
|
|
14
|
+
- **Full project docs (architecture, runtime, build, deployment, perf): [`master.md`](./master.md)**
|
|
15
|
+
- Roadmap: [`ROADMAP_INTEGRAL.md`](./ROADMAP_INTEGRAL.md)
|
|
12
16
|
|
|
13
17
|
## Requirements
|
|
14
18
|
|
|
15
|
-
- Node.js `>=
|
|
16
|
-
- npm `>=8`
|
|
19
|
+
- Node.js `>= 18` (tested on 24)
|
|
20
|
+
- npm `>= 8`
|
|
17
21
|
|
|
18
22
|
## Installation
|
|
19
23
|
|
|
@@ -21,124 +25,110 @@ Node.js framework for building SPA applications with a JS/CSS/HTML build pipelin
|
|
|
21
25
|
npm install vanilla-jet
|
|
22
26
|
```
|
|
23
27
|
|
|
24
|
-
If you are working in this local repository:
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
npm install
|
|
28
|
-
```
|
|
29
|
-
|
|
30
28
|
## Quick start
|
|
31
29
|
|
|
32
|
-
### 1) Export the server from your project
|
|
33
|
-
|
|
34
30
|
```js
|
|
31
|
+
// index.js
|
|
35
32
|
const { Server } = require('vanilla-jet');
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
### 2) Define endpoints (classes)
|
|
39
|
-
|
|
40
|
-
Each endpoint should expose a `name` and register routes with the router in the constructor.
|
|
33
|
+
const Config = require('./config');
|
|
41
34
|
|
|
42
|
-
```js
|
|
43
35
|
class AppEndpoint {
|
|
44
36
|
constructor(router) {
|
|
45
37
|
this.name = 'AppEndpoint';
|
|
46
|
-
router.
|
|
38
|
+
router.setDefaultRoute('home'); // maps "/"
|
|
39
|
+
router.addRoute('get', '/home', 'AppEndpoint.home');
|
|
47
40
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
response.respond();
|
|
41
|
+
home(request, response) {
|
|
42
|
+
response.render(request, 'home.html'); // streams public/pages/home.html
|
|
43
|
+
return true; // <- mark the request as handled
|
|
52
44
|
}
|
|
53
45
|
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### 3) Start the server
|
|
57
|
-
|
|
58
|
-
```js
|
|
59
|
-
const { Server } = require('vanilla-jet');
|
|
60
|
-
const Config = require('./config');
|
|
61
46
|
|
|
62
47
|
new Server(Config, [AppEndpoint]).start();
|
|
63
48
|
```
|
|
64
49
|
|
|
65
|
-
##
|
|
50
|
+
## Configuration (`config.js`)
|
|
66
51
|
|
|
67
|
-
|
|
52
|
+
Two shapes are supported (both resolved automatically):
|
|
68
53
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
54
|
+
```js
|
|
55
|
+
// Legacy (keyed by active profile name, selected with `--p qa`)
|
|
56
|
+
module.exports = {
|
|
57
|
+
profile: process.argv... , // 'development' | 'qa' | 'production'
|
|
58
|
+
settings: {
|
|
59
|
+
development: { port: 1234, api_url: '...' },
|
|
60
|
+
qa: { port: 443, api_url: '...' },
|
|
61
|
+
production: { port: 443, api_url: '...' },
|
|
62
|
+
shared: { site_name: 'My App', environment: 'qa', sentry: {...} },
|
|
63
|
+
security: { pass_salt: '...', token_salt: '...' }
|
|
64
|
+
}
|
|
65
|
+
};
|
|
75
66
|
|
|
76
|
-
|
|
67
|
+
// Nested (single profile)
|
|
68
|
+
module.exports = { settings: { profile: { port: 8080, api_url: '...' }, shared: {...}, security: {...} } };
|
|
69
|
+
```
|
|
77
70
|
|
|
78
|
-
|
|
79
|
-
- `npx vanilla-jet dev`
|
|
80
|
-
- `npx vanilla-jet build`
|
|
71
|
+
### Profile options (all optional)
|
|
81
72
|
|
|
82
|
-
|
|
73
|
+
| Option | Default | What it does |
|
|
74
|
+
|---|---|---|
|
|
75
|
+
| `port` | `8080` | Listen port. `process.env.PORT` wins (Cloud Run/Heroku). |
|
|
76
|
+
| `enable_precompressed_negotiation` | `false` | Serve `.br` → `.gz` → original via `Accept-Encoding`. |
|
|
77
|
+
| `enable_service_worker` | `false` | Generate + serve a cache-first service worker. **Recommended: on in prod/qa, off in dev.** |
|
|
78
|
+
| `service_worker` | — | `{ cache_prefix, on_demand_prefixes, precache, precache_exclude }`. Precache is auto-derived from `vanillaJet.package.json`. |
|
|
79
|
+
| `defer_scripts` | `false` | Add `defer` to non-async scripts so they don't block parsing. |
|
|
80
|
+
| `externalize_templates` | `false` | Move `<script type="text/template">` blocks out of the page into a cacheable `public/scripts/templates.js`. |
|
|
81
|
+
| `request_timeout_ms` / `headers_timeout_ms` / `keep_alive_timeout_ms` | `30000` / `35000` / `5000` | Defensive server timeouts. |
|
|
82
|
+
| `https_server` / `self_managed_certs` | `false` | HTTP/2 with self-managed `key`/`cert`. |
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
## Commands
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
- `assets/templates/**/*.html`
|
|
88
|
-
- `assets/scripts/**/*.js`
|
|
89
|
-
- `assets/styles/less/admin.less`
|
|
90
|
-
- `public/` (compiled output)
|
|
91
|
-
- `config.js`
|
|
92
|
-
- `vanillaJet.package.json`
|
|
86
|
+
CLI (`bin.js`): `npx vanilla-jet setup | dev | build | build:qa | build:staging | build:prod`
|
|
93
87
|
|
|
94
|
-
|
|
88
|
+
From this repo: `npm run dev` · `npm run build:prod` · `npm test` · `npm run benchmark:static`
|
|
95
89
|
|
|
96
|
-
|
|
90
|
+
## Expected consumer structure
|
|
97
91
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
92
|
+
```
|
|
93
|
+
assets/pages/home.html · assets/templates/**/*.html · assets/scripts/**/*.js · assets/styles/less/admin.less
|
|
94
|
+
config.js · vanillaJet.package.json · public/ (build output)
|
|
95
|
+
```
|
|
102
96
|
|
|
103
|
-
##
|
|
97
|
+
## Build pipeline (Gulp)
|
|
104
98
|
|
|
105
|
-
|
|
99
|
+
- Minifies + concatenates JS → `public/scripts/vanilla.min.js`
|
|
100
|
+
- Compiles LESS → `public/styles/app.min.css`
|
|
101
|
+
- Compiles templates → `public/pages/home.html` (+ optional `templates.js`)
|
|
102
|
+
- Precompresses every `.js`/`.css`/`.html` to `.gz` + `.br`
|
|
103
|
+
- Generates the service worker (when enabled)
|
|
106
104
|
|
|
107
|
-
|
|
108
|
-
module.exports = {
|
|
109
|
-
settings: {
|
|
110
|
-
profile: {
|
|
111
|
-
// Enables priority: .br -> .gz -> original file
|
|
112
|
-
enable_precompressed_negotiation: true
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
};
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
Behavior details:
|
|
105
|
+
## Performance features (opt-in)
|
|
119
106
|
|
|
120
|
-
-
|
|
121
|
-
-
|
|
122
|
-
-
|
|
123
|
-
|
|
107
|
+
- **Brotli + gzip** precompression with `Accept-Encoding` negotiation and safe fallback.
|
|
108
|
+
- **Immutable caching**: fingerprinted assets (`?v=size-mtime`) are served `Cache-Control: public,
|
|
109
|
+
max-age=31536000, immutable`; HTML and unversioned assets stay `no-cache`. Big win for clients
|
|
110
|
+
without the service worker (e.g. native WebViews).
|
|
111
|
+
- **Service worker** (cache-first), precache auto-derived from `vanillaJet.package.json`, content-pinned
|
|
112
|
+
cache name, `ignoreSearch` for fingerprinted URLs, and an inline registration helper
|
|
113
|
+
(`dipper.includeServiceWorker()`, web-only with a `window.__VJ_DISABLE_SW__` opt-out for WebViews).
|
|
114
|
+
- **`defer` scripts** and **template externalization** to shrink the render-blocking critical path.
|
|
124
115
|
|
|
125
|
-
|
|
116
|
+
See [`master.md`](./master.md) §12–§17 and [`docs/benchmark-static.md`](./docs/benchmark-static.md).
|
|
126
117
|
|
|
127
|
-
|
|
118
|
+
## Testing
|
|
128
119
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
120
|
+
```bash
|
|
121
|
+
npm test # node --test (router, dipper, config, static serving, service worker)
|
|
122
|
+
npm run benchmark:static # reproducible static-serving benchmark (cold/warm)
|
|
123
|
+
```
|
|
133
124
|
|
|
134
|
-
|
|
125
|
+
## Deployment
|
|
135
126
|
|
|
136
|
-
|
|
127
|
+
Templates (nginx + Docker) in [`docs/deployment/`](./docs/deployment/). Honors `process.env.PORT`, so
|
|
128
|
+
PaaS runtimes (Cloud Run, Heroku) work without config changes. Enable caching features in prod/qa
|
|
129
|
+
profiles; keep them off in `development` for fresh iteration.
|
|
137
130
|
|
|
138
|
-
##
|
|
131
|
+
## More docs
|
|
139
132
|
|
|
140
|
-
-
|
|
141
|
-
-
|
|
142
|
-
- Version history: [`CHANGELOG.md`](./CHANGELOG.md)
|
|
143
|
-
- Roadmap and improvements: `ROADMAP_INTEGRAL.md`
|
|
144
|
-
- Deployment templates (nginx + docker): `docs/deployment/`
|
|
133
|
+
- **[`master.md`](./master.md)** — full architecture, runtime flow, perf playbook, upgrade notes.
|
|
134
|
+
- [`docs/router.md`](./docs/router.md) · [`CHANGELOG.md`](./CHANGELOG.md) · [`ROADMAP_INTEGRAL.md`](./ROADMAP_INTEGRAL.md)
|
package/framework/router.js
CHANGED
|
@@ -46,6 +46,10 @@ class Router {
|
|
|
46
46
|
this.compressionFiles = [ 'vanilla.min.js', 'app.min.css' ];
|
|
47
47
|
this.enablePrecompressedNegotiation = Boolean(server?.options?.enable_precompressed_negotiation);
|
|
48
48
|
this.enableServiceWorker = Boolean(server?.options?.enable_service_worker);
|
|
49
|
+
// Cache-Control max-age (seconds) for NON-versioned static assets (images, fonts,
|
|
50
|
+
// animation JSON…). Lets the browser reuse them across references/reloads instead of
|
|
51
|
+
// revalidating each time. Versioned (?v=) assets stay immutable; 0 keeps no-cache.
|
|
52
|
+
this.staticCacheMaxAge = Number(server?.options?.static_cache_max_age) || 0;
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
routeToRegExp(route) {
|
|
@@ -284,6 +288,7 @@ class Router {
|
|
|
284
288
|
}
|
|
285
289
|
|
|
286
290
|
buildStaticHeaders(extHeader, candidates, contentEncoding, metadata, isImmutable) {
|
|
291
|
+
let obj = this;
|
|
287
292
|
let staticHeaders = Object.assign({}, extHeader);
|
|
288
293
|
if (contentEncoding) {
|
|
289
294
|
staticHeaders['Content-Encoding'] = contentEncoding;
|
|
@@ -300,8 +305,13 @@ class Router {
|
|
|
300
305
|
// This is the big win for clients without the service worker (e.g. native WebViews),
|
|
301
306
|
// which otherwise revalidate every asset on every load.
|
|
302
307
|
staticHeaders['Cache-Control'] = 'public, max-age=31536000, immutable';
|
|
308
|
+
} else if (obj.staticCacheMaxAge > 0) {
|
|
309
|
+
// Non-versioned assets (images, fonts, animation JSON…): cache for a while so they
|
|
310
|
+
// aren't re-fetched on every reference/reload. ETag/Last-Modified still allow a cheap
|
|
311
|
+
// 304 after expiry. Pick this when assets change rarely (e.g. a few days/weeks).
|
|
312
|
+
staticHeaders['Cache-Control'] = `public, max-age=${obj.staticCacheMaxAge}`;
|
|
303
313
|
} else {
|
|
304
|
-
//
|
|
314
|
+
// Default: force revalidation to keep clients fresh without a hard reload.
|
|
305
315
|
staticHeaders['Cache-Control'] = 'no-cache, must-revalidate';
|
|
306
316
|
}
|
|
307
317
|
return staticHeaders;
|
package/framework/server.js
CHANGED
package/gulpfile.js
CHANGED
|
@@ -142,7 +142,8 @@ function watchFiles(cb) {
|
|
|
142
142
|
buildLess,
|
|
143
143
|
compressCss,
|
|
144
144
|
compileTemplates,
|
|
145
|
-
generateServiceWorker
|
|
145
|
+
generateServiceWorker,
|
|
146
|
+
compressBr
|
|
146
147
|
));
|
|
147
148
|
|
|
148
149
|
// Watch HTML files
|
|
@@ -159,7 +160,8 @@ function watchFiles(cb) {
|
|
|
159
160
|
cleanMinified,
|
|
160
161
|
compressJs,
|
|
161
162
|
compileTemplates,
|
|
162
|
-
generateServiceWorker
|
|
163
|
+
generateServiceWorker,
|
|
164
|
+
compressBr
|
|
163
165
|
));
|
|
164
166
|
|
|
165
167
|
cb();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vanilla-jet",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.1",
|
|
4
4
|
"description": "VannilaJet framework",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -30,14 +30,9 @@
|
|
|
30
30
|
},
|
|
31
31
|
"homepage": "https://github.com/nalancer08/VanillaJet#readme",
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"blueimp-md5": "2.19.0",
|
|
34
33
|
"chalk": "4.1.2",
|
|
35
34
|
"html-minifier-terser": "7.2.0",
|
|
36
|
-
"js-beautify": "1.15.4",
|
|
37
|
-
"jsrsasign": "11.1.0",
|
|
38
|
-
"jwt-simple": "0.5.6",
|
|
39
35
|
"minimist": "1.2.8",
|
|
40
|
-
"nodemon": "3.1.10",
|
|
41
36
|
"nunjucks": "3.2.4",
|
|
42
37
|
"underscore": ">= 1.12.x",
|
|
43
38
|
"del": "^6.0.0",
|
package/scripts/compile_html.js
CHANGED
|
@@ -184,7 +184,7 @@ function replaceInclude(lines, originalLine, templateCompiled) {
|
|
|
184
184
|
// -- Step 4
|
|
185
185
|
async function createHTMLFile(content, filePath) {
|
|
186
186
|
const { minify } = require('html-minifier-terser');
|
|
187
|
-
|
|
187
|
+
let minified = await minify(content, {
|
|
188
188
|
collapseWhitespace: true,
|
|
189
189
|
collapseInlineTagWhitespace: true,
|
|
190
190
|
removeComments: true,
|
|
@@ -195,6 +195,14 @@ async function createHTMLFile(content, filePath) {
|
|
|
195
195
|
minifyJS: true
|
|
196
196
|
});
|
|
197
197
|
|
|
198
|
+
// -- Externalize <script type="text/template"> blocks into public/scripts/templates.js
|
|
199
|
+
// (opt-in via settings.profile.externalize_templates). The page shrinks to ~the shell;
|
|
200
|
+
// templates load from a separate cacheable file (brotli + SW + immutable) BEFORE the app
|
|
201
|
+
// bundle (defer + document order), so views still find their templates in the DOM at boot.
|
|
202
|
+
if (opts.externalize_templates) {
|
|
203
|
+
minified = externalizeTemplates(minified);
|
|
204
|
+
}
|
|
205
|
+
|
|
198
206
|
const publicPath = path.join(processCwd(), '/public/pages');
|
|
199
207
|
fs.mkdirSync(publicPath, { recursive: true });
|
|
200
208
|
const absolutePath = path.join(publicPath, filePath);
|
|
@@ -210,6 +218,45 @@ async function createHTMLFile(content, filePath) {
|
|
|
210
218
|
console.log(chalk.green(`Created gzipped version at: ${absolutePath}.gz`));
|
|
211
219
|
}
|
|
212
220
|
|
|
221
|
+
// -- Move all <script type="text/template"> blocks out of the page into
|
|
222
|
+
// public/scripts/templates.js (a tiny injector that adds them to the DOM). Returns the
|
|
223
|
+
// page HTML with those blocks replaced by a single deferred <script> tag (placed where the
|
|
224
|
+
// first block was — before the app bundle, so it runs first by document order).
|
|
225
|
+
function externalizeTemplates(html) {
|
|
226
|
+
const templateRegex = /<script\b[^>]*\btype\s*=\s*["']text\/template["'][^>]*>[\s\S]*?<\/script>/gi;
|
|
227
|
+
const blocks = html.match(templateRegex) || [];
|
|
228
|
+
if (!blocks.length) {
|
|
229
|
+
return html;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const scriptsDir = path.join(processCwd(), 'public', 'scripts');
|
|
233
|
+
fs.mkdirSync(scriptsDir, { recursive: true });
|
|
234
|
+
|
|
235
|
+
const payload = blocks.join('\n');
|
|
236
|
+
// External file → a literal </script> inside the payload is harmless (no inline HTML parser).
|
|
237
|
+
const injector =
|
|
238
|
+
'(function(){var c=document.createElement("div");c.style.display="none";' +
|
|
239
|
+
'c.setAttribute("data-vj-templates","");c.innerHTML=' + JSON.stringify(payload) + ';' +
|
|
240
|
+
'document.body.insertBefore(c,document.body.firstChild);})();';
|
|
241
|
+
|
|
242
|
+
const templatesPath = path.join(scriptsDir, 'templates.js');
|
|
243
|
+
fs.writeFileSync(templatesPath, injector, 'utf8');
|
|
244
|
+
fs.writeFileSync(templatesPath + '.gz', zlib.gzipSync(injector, { level: 9 }));
|
|
245
|
+
|
|
246
|
+
const stats = fs.statSync(templatesPath);
|
|
247
|
+
const version = `${stats.size}-${Math.floor(stats.mtimeMs)}`;
|
|
248
|
+
const tag = `<script defer src="/public/scripts/templates.js?v=${version}"></script>`;
|
|
249
|
+
|
|
250
|
+
let inserted = false;
|
|
251
|
+
const result = html.replace(templateRegex, () => {
|
|
252
|
+
if (!inserted) { inserted = true; return tag; }
|
|
253
|
+
return '';
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
console.log(chalk.green(`VanillaJet - externalized ${blocks.length} templates to public/scripts/templates.js`));
|
|
257
|
+
return result;
|
|
258
|
+
}
|
|
259
|
+
|
|
213
260
|
// -- Helpers
|
|
214
261
|
function cleanALine(line) {
|
|
215
262
|
line = line.replaceAll(' ', '');
|
package/scripts/generate_sw.js
CHANGED
|
@@ -15,7 +15,8 @@ const TEMPLATE_PATH = path.join(__dirname, '..', 'framework', 'sw.template.js');
|
|
|
15
15
|
const CORE_PRECACHE = [
|
|
16
16
|
'/public/styles/app.min.css',
|
|
17
17
|
'/public/scripts/vanilla.min.js',
|
|
18
|
-
'/public/scripts/core/vanillaJet.min.js'
|
|
18
|
+
'/public/scripts/core/vanillaJet.min.js',
|
|
19
|
+
'/public/scripts/templates.js'
|
|
19
20
|
];
|
|
20
21
|
|
|
21
22
|
const DEFAULT_ON_DEMAND_PREFIXES = ['/public/animations/', '/public/images/'];
|
package/test/router.test.js
CHANGED
|
@@ -48,6 +48,18 @@ test('isProtectedFile: blocks framework/external/node_modules and top-level file
|
|
|
48
48
|
assert.equal(router.isProtectedFile('/public/scripts/vanilla.min.js'), false);
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
+
test('buildStaticHeaders: immutable for ?v=, max-age when configured, else no-cache', () => {
|
|
52
|
+
const meta = { size: 10, etag: 'W/"x"', lastModified: 'Mon, 01 Jan 2024 00:00:00 GMT' };
|
|
53
|
+
const plain = makeRouter();
|
|
54
|
+
assert.match(plain.buildStaticHeaders({}, [], '', meta, true)['Cache-Control'], /immutable/);
|
|
55
|
+
assert.match(plain.buildStaticHeaders({}, [], '', meta, false)['Cache-Control'], /no-cache/);
|
|
56
|
+
|
|
57
|
+
const cached = new Router({ options: { static_cache_max_age: 3600 } });
|
|
58
|
+
assert.match(cached.buildStaticHeaders({}, [], '', meta, false)['Cache-Control'], /max-age=3600/);
|
|
59
|
+
// Versioned still wins over max-age.
|
|
60
|
+
assert.match(cached.buildStaticHeaders({}, [], '', meta, true)['Cache-Control'], /immutable/);
|
|
61
|
+
});
|
|
62
|
+
|
|
51
63
|
test('mimes: serves common web fonts and icons', () => {
|
|
52
64
|
const router = makeRouter();
|
|
53
65
|
assert.equal(router.mimes['woff2'], 'font/woff2');
|