vanilla-jet 1.5.0 → 1.5.2
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 +26 -0
- package/framework/dipper.js +3 -1
- package/framework/server.js +1 -0
- package/gulpfile.js +9 -1
- package/package.json +1 -1
- package/scripts/compress_br.js +46 -0
- package/scripts/generate_sw.js +17 -12
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,32 @@ 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.5.2] - 2026-06-28
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **Brotli precompression** of build outputs (`scripts/compress_br.js` + Gulp `compressBr`): generates
|
|
12
|
+
`.br` for `vanilla.min.js`, `app.min.css` and `public/pages/home.html`. The server already negotiates
|
|
13
|
+
`.br -> .gz -> original` when `settings.profile.enable_precompressed_negotiation` is true and the client
|
|
14
|
+
sends `Accept-Encoding: br`. Additive and safe: clients that don't accept brotli keep getting gzip.
|
|
15
|
+
- **`settings.profile.defer_scripts`** (default `false`): when enabled, `dipper.includeScript()` adds
|
|
16
|
+
`defer` to non-async scripts so they don't block HTML parsing (document order preserved). Opt-in.
|
|
17
|
+
|
|
18
|
+
## [1.5.1] - 2026-06-28
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- **Service worker precache is now fully derived from `vanillaJet.package.json`.** `scripts/generate_sw.js`
|
|
23
|
+
reads the Dipper's full local registry (`coreDependencies` + `dependencies` + `styles` that resolve to
|
|
24
|
+
`/public/...`) instead of only the enqueued subset, so first-party assets like `coreLib/*` are precached
|
|
25
|
+
automatically. Consumers no longer need to hardcode a `service_worker.precache` list.
|
|
26
|
+
- Added `service_worker.precache_exclude` (opt-out by path) for declared assets you don't want cached.
|
|
27
|
+
`service_worker.precache` remains as an optional escape hatch for extras not declared in the package file.
|
|
28
|
+
|
|
29
|
+
### Compatibility notes
|
|
30
|
+
|
|
31
|
+
- Backward compatible: an explicit `service_worker.precache` still works (merged with the derived set).
|
|
32
|
+
|
|
7
33
|
## [1.5.0] - 2026-06-27
|
|
8
34
|
|
|
9
35
|
### Added
|
package/framework/dipper.js
CHANGED
|
@@ -307,7 +307,9 @@ Dipper.prototype.includeScript = function(script) {
|
|
|
307
307
|
//type = item['cdn'] ? "" : 'type=\"text/javascript\"',
|
|
308
308
|
resource = item['resource'],
|
|
309
309
|
isAsync = item['async'] ? ' async' : '',
|
|
310
|
-
|
|
310
|
+
// Honor a per-script defer flag, or the global settings.profile.defer_scripts
|
|
311
|
+
// (applied to non-async scripts so they don't block parsing; order preserved).
|
|
312
|
+
defer = (item['defer'] || (obj.options && obj.options.defer_scripts && !item['async'])) ? ' defer' : '',
|
|
311
313
|
origin = item['origin'] != '' ? ' crossorigin=\"' + item['origin'] + '\"' : '',
|
|
312
314
|
integrity = item['integrity'] != '' ? ' integrity=\"' + item['integrity'] + '\"' : '';
|
|
313
315
|
|
package/framework/server.js
CHANGED
package/gulpfile.js
CHANGED
|
@@ -127,6 +127,12 @@ function generateServiceWorker() {
|
|
|
127
127
|
.pipe(shell([`node scripts/generate_sw.js ${buildEnv}`]));
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
// Brotli precompression of build outputs (served via Accept-Encoding negotiation)
|
|
131
|
+
function compressBr() {
|
|
132
|
+
return gulp.src('.')
|
|
133
|
+
.pipe(shell([`node scripts/compress_br.js`]));
|
|
134
|
+
}
|
|
135
|
+
|
|
130
136
|
// Watch task
|
|
131
137
|
function watchFiles(cb) {
|
|
132
138
|
livereload.listen();
|
|
@@ -168,7 +174,8 @@ const build = gulp.series(
|
|
|
168
174
|
buildLess,
|
|
169
175
|
compileTemplates,
|
|
170
176
|
gulp.parallel(compressJs, compressCss),
|
|
171
|
-
generateServiceWorker
|
|
177
|
+
generateServiceWorker,
|
|
178
|
+
compressBr
|
|
172
179
|
);
|
|
173
180
|
|
|
174
181
|
const dev = gulp.series(
|
|
@@ -186,6 +193,7 @@ exports.compressJs = compressJs;
|
|
|
186
193
|
exports.compressCss = compressCss;
|
|
187
194
|
exports.compileTemplates = compileTemplates;
|
|
188
195
|
exports.generateServiceWorker = generateServiceWorker;
|
|
196
|
+
exports.compressBr = compressBr;
|
|
189
197
|
exports.build = build;
|
|
190
198
|
exports.dev = dev;
|
|
191
199
|
exports.default = dev;
|
package/package.json
CHANGED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Brotli-precompresses the build outputs so the server can negotiate `.br`
|
|
2
|
+
// (smaller than gzip). Safe + additive: the framework only serves `.br` when the
|
|
3
|
+
// client sends `Accept-Encoding: br`; otherwise it falls back to `.gz`/original.
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const zlib = require('zlib');
|
|
8
|
+
|
|
9
|
+
function processCwd() {
|
|
10
|
+
return process.cwd()
|
|
11
|
+
.replace('/scripts', '')
|
|
12
|
+
.replace('/gulp', '')
|
|
13
|
+
.replace('/node_modules/vanilla-jet', '');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const root = processCwd();
|
|
17
|
+
|
|
18
|
+
// Same files the framework negotiates `.br` for (router static + response.render).
|
|
19
|
+
const TARGETS = [
|
|
20
|
+
'public/scripts/vanilla.min.js',
|
|
21
|
+
'public/styles/app.min.css',
|
|
22
|
+
'public/pages/home.html'
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
const BROTLI_OPTIONS = {
|
|
26
|
+
params: {
|
|
27
|
+
[zlib.constants.BROTLI_PARAM_QUALITY]: 11,
|
|
28
|
+
[zlib.constants.BROTLI_PARAM_SIZE_HINT]: 0
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
TARGETS.forEach((relativePath) => {
|
|
33
|
+
const filePath = path.join(root, relativePath);
|
|
34
|
+
try {
|
|
35
|
+
const stats = fs.statSync(filePath);
|
|
36
|
+
if (!stats.isFile()) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const input = fs.readFileSync(filePath);
|
|
40
|
+
const compressed = zlib.brotliCompressSync(input, BROTLI_OPTIONS);
|
|
41
|
+
fs.writeFileSync(filePath + '.br', compressed);
|
|
42
|
+
console.log(`VanillaJet - brotli: ${relativePath}.br (${input.length} -> ${compressed.length} B)`);
|
|
43
|
+
} catch (err) {
|
|
44
|
+
// File not present (feature not built yet) — skip silently.
|
|
45
|
+
}
|
|
46
|
+
});
|
package/scripts/generate_sw.js
CHANGED
|
@@ -63,9 +63,11 @@ function isLocalPublicPath(url) {
|
|
|
63
63
|
return typeof url === 'string' && url.startsWith('/public/') && !url.startsWith('//');
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
|
|
66
|
+
// Source of truth = vanillaJet.package.json. We hydrate the Dipper and read its full
|
|
67
|
+
// registry (coreDependencies + dependencies + styles), keeping every LOCAL resource.
|
|
68
|
+
// This way the precache list is derived from the declared deps, with no raw paths in
|
|
69
|
+
// the consumer config. Any failure falls back to core only.
|
|
70
|
+
function deriveLocalAssets(root, opts, shared) {
|
|
69
71
|
try {
|
|
70
72
|
const Dipper = require('../framework/dipper.js');
|
|
71
73
|
const Functions = require('../framework/functions.js');
|
|
@@ -73,16 +75,16 @@ function deriveEnqueuedAssets(root, opts, shared) {
|
|
|
73
75
|
Functions.hydrate(dipper);
|
|
74
76
|
|
|
75
77
|
const assets = [];
|
|
76
|
-
const collect = (registry
|
|
77
|
-
Object.keys(
|
|
78
|
+
const collect = (registry) => {
|
|
79
|
+
Object.keys(registry || {}).forEach((name) => {
|
|
78
80
|
const entry = registry[name];
|
|
79
81
|
if (entry && isLocalPublicPath(entry.resource)) {
|
|
80
82
|
assets.push(stripQuery(entry.resource));
|
|
81
83
|
}
|
|
82
84
|
});
|
|
83
85
|
};
|
|
84
|
-
collect(dipper.styles
|
|
85
|
-
collect(dipper.scripts
|
|
86
|
+
collect(dipper.styles);
|
|
87
|
+
collect(dipper.scripts);
|
|
86
88
|
return assets;
|
|
87
89
|
} catch (err) {
|
|
88
90
|
return [];
|
|
@@ -90,15 +92,18 @@ function deriveEnqueuedAssets(root, opts, shared) {
|
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
function buildPrecacheList(root, opts, shared) {
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
95
|
+
const sw = opts.service_worker || {};
|
|
96
|
+
// `precache` = optional extras NOT declared in vanillaJet.package.json.
|
|
97
|
+
const configured = Array.isArray(sw.precache) ? sw.precache : [];
|
|
98
|
+
// `precache_exclude` = opt-out for declared-but-don't-cache assets (heavy/rare).
|
|
99
|
+
const exclude = (Array.isArray(sw.precache_exclude) ? sw.precache_exclude : []).map(stripQuery);
|
|
96
100
|
|
|
97
101
|
const candidates = CORE_PRECACHE
|
|
98
|
-
.concat(
|
|
102
|
+
.concat(deriveLocalAssets(root, opts, shared))
|
|
99
103
|
.concat(configured)
|
|
100
104
|
.map(stripQuery)
|
|
101
|
-
.filter(isLocalPublicPath)
|
|
105
|
+
.filter(isLocalPublicPath)
|
|
106
|
+
.filter((assetPath) => !exclude.includes(assetPath));
|
|
102
107
|
|
|
103
108
|
const seen = new Set();
|
|
104
109
|
const precache = [];
|