@divriots/jampack 0.22.1 → 0.23.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/README.md +73 -6
- package/dist/compressors/css.d.ts +2 -0
- package/dist/compressors/css.js +11 -2
- package/dist/compressors/html.js +2 -1
- package/dist/config-default.js +6 -2
- package/dist/config-types.d.ts +5 -0
- package/dist/index.js +4 -1
- package/dist/optimize.js +31 -8
- package/package.json +14 -13
package/README.md
CHANGED
|
@@ -94,6 +94,74 @@ becomes responsive with multiple formats including AVIF:
|
|
|
94
94
|
</picture>
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
+
[Read more](/features/optimize-images)
|
|
98
|
+
|
|
99
|
+
### CDN images become responsive
|
|
100
|
+
|
|
101
|
+
```html
|
|
102
|
+
<img
|
|
103
|
+
src="https://images.unsplash.com/photo-1513002749550-c59d786b8e6c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
|
|
104
|
+
alt="Clouds in the sky by Taylor Van Riper"
|
|
105
|
+
width="2848"
|
|
106
|
+
height="4272"
|
|
107
|
+
/>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
becomes
|
|
111
|
+
|
|
112
|
+
```html
|
|
113
|
+
<img
|
|
114
|
+
src="https://images.unsplash.com/photo-1513002749550-c59d786b8e6c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
|
|
115
|
+
alt="Clouds in the sky by Taylor Van Riper"
|
|
116
|
+
width="2848"
|
|
117
|
+
height="4272"
|
|
118
|
+
loading="lazy"
|
|
119
|
+
decoding="async"
|
|
120
|
+
srcset="
|
|
121
|
+
https://images.unsplash.com/photo-1513002749550-c59d786b8e6c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&w=2848&fit=min&auto=format 2848w,
|
|
122
|
+
https://images.unsplash.com/photo-1513002749550-c59d786b8e6c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&w=2548&fit=min&auto=format 2548w,
|
|
123
|
+
https://images.unsplash.com/photo-1513002749550-c59d786b8e6c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&w=2248&fit=min&auto=format 2248w,
|
|
124
|
+
https://images.unsplash.com/photo-1513002749550-c59d786b8e6c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&w=1948&fit=min&auto=format 1948w,
|
|
125
|
+
https://images.unsplash.com/photo-1513002749550-c59d786b8e6c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&w=1648&fit=min&auto=format 1648w,
|
|
126
|
+
https://images.unsplash.com/photo-1513002749550-c59d786b8e6c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&w=1348&fit=min&auto=format 1348w,
|
|
127
|
+
https://images.unsplash.com/photo-1513002749550-c59d786b8e6c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&w=1048&fit=min&auto=format 1048w
|
|
128
|
+
"
|
|
129
|
+
sizes="100vw"
|
|
130
|
+
/>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
[Read more](/features/optimize-images-cdn)
|
|
134
|
+
|
|
135
|
+
### External images can be downloaded and optimized
|
|
136
|
+
|
|
137
|
+
```html
|
|
138
|
+
<img
|
|
139
|
+
src="https://images.unsplash.com/photo-1513002749550-c59d786b8e6c?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=jpg&fit=crop&w=1287&q=80"
|
|
140
|
+
alt="Clouds in the sky by Taylor Van Riper"
|
|
141
|
+
/>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
becomes
|
|
145
|
+
|
|
146
|
+
```html
|
|
147
|
+
<img
|
|
148
|
+
src="_jampack/ab99b9d280ce4cf7cfc810b59f3a7739.jpg.webp"
|
|
149
|
+
alt="Clouds in the sky by Taylor Van Riper"
|
|
150
|
+
loading="lazy"
|
|
151
|
+
decoding="async"
|
|
152
|
+
width="1287"
|
|
153
|
+
height="1931"
|
|
154
|
+
srcset="
|
|
155
|
+
_jampack/ab99b9d280ce4cf7cfc810b59f3a7739.jpg.webp 1287w,
|
|
156
|
+
_jampack/ab99b9d280ce4cf7cfc810b59f3a7739@987w.webp 987w,
|
|
157
|
+
_jampack/ab99b9d280ce4cf7cfc810b59f3a7739@687w.webp 687w
|
|
158
|
+
"
|
|
159
|
+
sizes="100vw"
|
|
160
|
+
/>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
[Read more](/features/optimize-images-external)
|
|
164
|
+
|
|
97
165
|
### Above & below-the-fold
|
|
98
166
|
|
|
99
167
|
`jampack` optimizes assets above-the-fold ⬆️.
|
|
@@ -106,21 +174,21 @@ Lazy-load assets below-the-fold ⬇️.
|
|
|
106
174
|
|
|
107
175
|
- Images and Iframes are lazy loaded.
|
|
108
176
|
|
|
109
|
-
|
|
177
|
+
[Read more](https://jampack.divriots.com/features/optimize-above-the-fold/)
|
|
110
178
|
|
|
111
179
|
## Inline critical CSS
|
|
112
180
|
|
|
113
181
|
Avoid [FOUC](https://en.wikipedia.org/wiki/Flash_of_unstyled_content) while stylesheets are downloaded and parsed.
|
|
114
182
|
`jampack` will inline critical CSS and lazy-load the rest of CSS.
|
|
115
183
|
|
|
116
|
-
|
|
184
|
+
[Read more](https://jampack.divriots.com/features/inline-critical-css/)
|
|
117
185
|
|
|
118
186
|
## Prefetch links
|
|
119
187
|
|
|
120
188
|
Speedup the future page navigations by prefetching the links on the page.
|
|
121
189
|
Thanks to [quicklink](https://github.com/GoogleChromeLabs/quicklink), this can be done dynamically as links enter the viewport.
|
|
122
190
|
|
|
123
|
-
|
|
191
|
+
[Read more](https://jampack.divriots.com/features/prefetch-links/)
|
|
124
192
|
|
|
125
193
|
### All assets are compressed
|
|
126
194
|
|
|
@@ -137,9 +205,8 @@ In a 2nd PASS, `jampack` compresses all untouched assets and keep the same name
|
|
|
137
205
|
| `.webp` | [`sharp`](https://sharp.pixelplumbing.com/) |
|
|
138
206
|
| `.avif` | [`sharp`](https://sharp.pixelplumbing.com/) |
|
|
139
207
|
|
|
140
|
-
### And more!
|
|
208
|
+
### [And a lot more!](https://jampack.divriots.com/)
|
|
141
209
|
|
|
142
|
-
See [Documentation](https://jampack.divriots.com/) for all feature list and examples.
|
|
143
210
|
|
|
144
211
|
## Quick use
|
|
145
212
|
|
|
@@ -163,7 +230,7 @@ For more options see [CLI options](https://jampack.divriots.com/cli-options/).
|
|
|
163
230
|
- [bayjs.org](https://bayjs.org/)
|
|
164
231
|
- [qwind.pages.dev](https://qwind.pages.dev/)
|
|
165
232
|
- [Bloycey's Blog](https://bloycey.blog/)
|
|
166
|
-
- [
|
|
233
|
+
- [gxanshu.in](https://gxanshu.in/)
|
|
167
234
|
|
|
168
235
|
> Add yours here
|
|
169
236
|
|
package/dist/compressors/css.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import browserslist from 'browserslist';
|
|
2
|
+
import { browserslistToTargets, transform as lightcss, transformStyleAttribute as lightcssStyleAttribute, } from 'lightningcss';
|
|
3
|
+
let targets = browserslistToTargets(browserslist('defaults'));
|
|
2
4
|
export async function compressCSS(originalCode, type) {
|
|
3
5
|
// Compress with lightningcss
|
|
4
6
|
let lightCSSData = undefined;
|
|
@@ -7,12 +9,16 @@ export async function compressCSS(originalCode, type) {
|
|
|
7
9
|
code: originalCode,
|
|
8
10
|
minify: true,
|
|
9
11
|
sourceMap: false,
|
|
12
|
+
targets,
|
|
10
13
|
};
|
|
11
14
|
if (type === 'inline') {
|
|
12
15
|
lightCSSData = lightcssStyleAttribute(options).code;
|
|
13
16
|
}
|
|
14
17
|
else {
|
|
15
|
-
lightCSSData = lightcss({
|
|
18
|
+
lightCSSData = lightcss({
|
|
19
|
+
filename: 'style.css',
|
|
20
|
+
...options,
|
|
21
|
+
}).code;
|
|
16
22
|
}
|
|
17
23
|
}
|
|
18
24
|
catch (e) {
|
|
@@ -26,3 +32,6 @@ export async function compressCSS(originalCode, type) {
|
|
|
26
32
|
}
|
|
27
33
|
return resultBuffer || originalCode;
|
|
28
34
|
}
|
|
35
|
+
export function loadConfig(config) {
|
|
36
|
+
targets = browserslistToTargets(browserslist(config.css.browserslist || config.general.browserslist));
|
|
37
|
+
}
|
package/dist/compressors/html.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { minify } from 'html-minifier-terser';
|
|
2
2
|
import { compressCSS } from './css.js';
|
|
3
3
|
import { compressJS } from './js.js';
|
|
4
|
+
import config from '../config.js';
|
|
4
5
|
async function minifyJSinHTML(originalCode) {
|
|
5
6
|
const newCode = await compressJS(originalCode);
|
|
6
7
|
if (newCode && newCode.length < originalCode.length)
|
|
@@ -22,7 +23,7 @@ export async function compressHTML(originalCode) {
|
|
|
22
23
|
minifyCSS: minifyCSSinHTML,
|
|
23
24
|
minifyJS: minifyJSinHTML,
|
|
24
25
|
sortClassName: true,
|
|
25
|
-
sortAttributes:
|
|
26
|
+
sortAttributes: config.html.sort_attributes,
|
|
26
27
|
});
|
|
27
28
|
if (newhtmlData)
|
|
28
29
|
return Buffer.from(newhtmlData, 'utf-8');
|
package/dist/config-default.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
const default_options = {
|
|
2
|
+
general: {
|
|
3
|
+
browserslist: 'defaults', // defaults = '> 0.5%, last 2 versions, Firefox ESR, not dead'
|
|
4
|
+
},
|
|
2
5
|
html: {
|
|
3
6
|
add_css_reset_as: 'inline',
|
|
7
|
+
sort_attributes: false,
|
|
4
8
|
},
|
|
5
9
|
css: {
|
|
6
10
|
inline_critical_css: false,
|
|
@@ -10,8 +14,8 @@ const default_options = {
|
|
|
10
14
|
},
|
|
11
15
|
image: {
|
|
12
16
|
embed_size: 1500,
|
|
13
|
-
srcset_min_width: 390 * 2,
|
|
14
|
-
srcset_max_width: 1920 * 2,
|
|
17
|
+
srcset_min_width: 390 * 2, // HiDPI phone
|
|
18
|
+
srcset_max_width: 1920 * 2, // 4K
|
|
15
19
|
max_width: 99999,
|
|
16
20
|
external: {
|
|
17
21
|
process: 'off',
|
package/dist/config-types.d.ts
CHANGED
|
@@ -4,14 +4,19 @@ export type WebpOptions = {
|
|
|
4
4
|
quality: number;
|
|
5
5
|
};
|
|
6
6
|
export type Options = {
|
|
7
|
+
general: {
|
|
8
|
+
browserslist: string;
|
|
9
|
+
};
|
|
7
10
|
html: {
|
|
8
11
|
add_css_reset_as: 'inline' | 'off';
|
|
12
|
+
sort_attributes: boolean;
|
|
9
13
|
};
|
|
10
14
|
js: {
|
|
11
15
|
compressor: 'esbuild' | 'swc';
|
|
12
16
|
};
|
|
13
17
|
css: {
|
|
14
18
|
inline_critical_css: boolean;
|
|
19
|
+
browserslist?: string;
|
|
15
20
|
};
|
|
16
21
|
image: {
|
|
17
22
|
embed_size: number;
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { optimize } from './optimize.js';
|
|
|
5
5
|
import $state from './state.js';
|
|
6
6
|
import { table } from 'table';
|
|
7
7
|
import { formatBytes } from './utils.js';
|
|
8
|
-
import { fast, loadConfig } from './config.js';
|
|
8
|
+
import config, { fast, loadConfig } from './config.js';
|
|
9
9
|
import { printTitle } from './logger.js';
|
|
10
10
|
import { exit } from 'process';
|
|
11
11
|
import kleur from 'kleur';
|
|
@@ -13,6 +13,7 @@ import { cleanCache } from './cache.js';
|
|
|
13
13
|
import { VERSION } from './packagejson.js';
|
|
14
14
|
import { mkdirSync } from 'fs';
|
|
15
15
|
import { join } from 'path';
|
|
16
|
+
import { loadConfig as loadConfigCSS } from './compressors/css.js';
|
|
16
17
|
const logo = ` __ __
|
|
17
18
|
|__|____ _____ ___________ ____ | | __
|
|
18
19
|
| \\__ \\ / \\\\____ \\__ \\ _/ ___\\| |/ /
|
|
@@ -67,6 +68,8 @@ program
|
|
|
67
68
|
console.error('Failed to create `_jampack` folder.');
|
|
68
69
|
exit(1);
|
|
69
70
|
}
|
|
71
|
+
// Inject config into modules
|
|
72
|
+
loadConfigCSS(config);
|
|
70
73
|
if (!options.onlycomp) {
|
|
71
74
|
printTitle('PASS 1 - Optimizing');
|
|
72
75
|
console.time('Done');
|
package/dist/optimize.js
CHANGED
|
@@ -26,9 +26,10 @@ function getIntAttr(img, attr) {
|
|
|
26
26
|
return parsed;
|
|
27
27
|
}
|
|
28
28
|
async function analyse(file) {
|
|
29
|
-
var _a;
|
|
30
29
|
console.log('▶ ' + file);
|
|
31
30
|
const html = (await fs.readFile(path.join($state.dir, file))).toString();
|
|
31
|
+
if (!html.includes('<html'))
|
|
32
|
+
return;
|
|
32
33
|
const $ = cheerio.load(html, { sourceCodeLocationInfo: true });
|
|
33
34
|
const theFold = getTheFold($);
|
|
34
35
|
const imgs = $('img');
|
|
@@ -100,22 +101,44 @@ async function analyse(file) {
|
|
|
100
101
|
//
|
|
101
102
|
let prependToHead = '';
|
|
102
103
|
let appendToHead = '';
|
|
104
|
+
const heads = $('head'); // always exists because doc loaded with isDocument=true (default)
|
|
105
|
+
const charsetElements$ = heads.find('meta[charset]');
|
|
106
|
+
const wasCharsetFirst = !charsetElements$.prev().length;
|
|
103
107
|
if (config.html.add_css_reset_as === 'inline') {
|
|
104
108
|
prependToHead += `<style>:where(img){height:auto;}</style>`;
|
|
105
109
|
}
|
|
106
110
|
if (prependToHead || appendToHead) {
|
|
107
|
-
let heads = $('head');
|
|
108
|
-
if (heads.length === 0) {
|
|
109
|
-
// head tag doesn't exist
|
|
110
|
-
(_a = $('html')) === null || _a === void 0 ? void 0 : _a.prepend(`<head></head>`);
|
|
111
|
-
}
|
|
112
|
-
heads = $('head');
|
|
113
|
-
// head tag exist
|
|
114
111
|
if (prependToHead)
|
|
115
112
|
heads.prepend(prependToHead);
|
|
116
113
|
if (appendToHead)
|
|
117
114
|
heads.append(appendToHead);
|
|
118
115
|
}
|
|
116
|
+
switch (charsetElements$.length) {
|
|
117
|
+
case 0:
|
|
118
|
+
$state.reportIssue(file, {
|
|
119
|
+
type: 'fix',
|
|
120
|
+
msg: 'Adding missing <meta charset="utf-8"> to the top of the <head>',
|
|
121
|
+
});
|
|
122
|
+
heads.prepend('<meta charset="utf-8">');
|
|
123
|
+
break;
|
|
124
|
+
case 1:
|
|
125
|
+
if (!wasCharsetFirst) {
|
|
126
|
+
$state.reportIssue(file, {
|
|
127
|
+
type: 'perf',
|
|
128
|
+
msg: 'Moving <meta charset> to the top of the <head>',
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
if (!wasCharsetFirst || prependToHead)
|
|
132
|
+
heads.prepend(charsetElements$);
|
|
133
|
+
break;
|
|
134
|
+
default:
|
|
135
|
+
$state.reportIssue(file, {
|
|
136
|
+
type: 'fix',
|
|
137
|
+
msg: 'Multiple <meta charset> found in the <head>: taking only the first one and deleting the others',
|
|
138
|
+
});
|
|
139
|
+
charsetElements$.remove();
|
|
140
|
+
heads.prepend(charsetElements$.first());
|
|
141
|
+
}
|
|
119
142
|
// Add to <body>
|
|
120
143
|
//
|
|
121
144
|
let appendToBody = '';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@divriots/jampack",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.1",
|
|
4
4
|
"cache-version": {
|
|
5
5
|
"img": "v1",
|
|
6
6
|
"img-ext": "v1"
|
|
@@ -28,34 +28,35 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@divriots/cheerio": "1.0.0-rc.12",
|
|
30
30
|
"@proload/core": "^0.3.3",
|
|
31
|
-
"@swc/core": "^1.3.
|
|
31
|
+
"@swc/core": "^1.3.100",
|
|
32
32
|
"add": "^2.0.6",
|
|
33
|
+
"browserslist": "^4.22.2",
|
|
33
34
|
"commander": "^10.0.1",
|
|
34
35
|
"critters": "^0.0.20",
|
|
35
36
|
"deepmerge": "^4.3.1",
|
|
36
|
-
"esbuild": "^0.19.
|
|
37
|
-
"file-type": "^18.
|
|
37
|
+
"esbuild": "^0.19.9",
|
|
38
|
+
"file-type": "^18.7.0",
|
|
38
39
|
"globby": "^13.2.2",
|
|
39
40
|
"hasha": "^5.2.2",
|
|
40
41
|
"html-minifier-terser": "^7.2.0",
|
|
41
42
|
"kleur": "^4.1.5",
|
|
42
|
-
"lightningcss": "^1.22.
|
|
43
|
+
"lightningcss": "^1.22.1",
|
|
43
44
|
"mini-svg-data-uri": "^1.4.4",
|
|
44
45
|
"ora": "^7.0.1",
|
|
45
46
|
"quicklink": "^2.3.0",
|
|
46
|
-
"sharp": "^0.
|
|
47
|
-
"svgo": "^3.0
|
|
47
|
+
"sharp": "^0.33.0",
|
|
48
|
+
"svgo": "^3.1.0",
|
|
48
49
|
"table": "^6.8.1",
|
|
49
|
-
"
|
|
50
|
-
"
|
|
50
|
+
"undici": "^5.24.0",
|
|
51
|
+
"unpic": "^3.16.0"
|
|
51
52
|
},
|
|
52
53
|
"devDependencies": {
|
|
53
|
-
"@types/html-minifier-terser": "^7.0.
|
|
54
|
-
"@types/node": "^20.
|
|
54
|
+
"@types/html-minifier-terser": "^7.0.2",
|
|
55
|
+
"@types/node": "^20.10.4",
|
|
55
56
|
"shx": "^0.3.3",
|
|
56
|
-
"ts-node": "^10.2
|
|
57
|
+
"ts-node": "^10.9.2",
|
|
57
58
|
"tslib": "^2.6.2",
|
|
58
|
-
"typescript": "^5.
|
|
59
|
+
"typescript": "^5.3.3"
|
|
59
60
|
},
|
|
60
61
|
"scripts": {
|
|
61
62
|
"watch": "pnpm build --watch",
|