@divriots/jampack 0.6.0 → 0.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/README.md CHANGED
@@ -69,6 +69,7 @@ See [the list of features](https://jampack.divriots.com).
69
69
  - [LWC.studio](https://lwc.studio)
70
70
  - [Components.studio](https://components.studio)
71
71
  - [keycloak.ch](https://keycloak.ch)
72
+ - [bayjs.org](https://bayjs.org/)
72
73
 
73
74
  > Add yours here
74
75
 
package/dist/cache.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
- import type { Image } from "./types.js";
2
+ import type { Image } from './compressors/images.js';
3
3
  declare function cleanCache(): Promise<void>;
4
4
  declare function computeCacheHash(buffer: Buffer, options?: any): string;
5
5
  declare function getFromCacheCompressImage(hash: string): Promise<Image | undefined>;
6
6
  declare function addToCacheCompressImage(hash: string, image: Image): Promise<void>;
7
- export { cleanCache, computeCacheHash, getFromCacheCompressImage, addToCacheCompressImage };
7
+ export { cleanCache, computeCacheHash, getFromCacheCompressImage, addToCacheCompressImage, };
package/dist/cache.js CHANGED
@@ -1,9 +1,9 @@
1
- import hasha from "hasha";
2
- import path from "path";
3
- import * as fs from "fs/promises";
1
+ import hasha from 'hasha';
2
+ import path from 'path';
3
+ import * as fs from 'fs/promises';
4
4
  import { VERSION } from './version.js';
5
5
  import $state from './state.js';
6
- const CACHE_FOLDER = ".jampack/cache";
6
+ const CACHE_FOLDER = '.jampack/cache';
7
7
  async function cleanCache() {
8
8
  try {
9
9
  await fs.rm(CACHE_FOLDER, { recursive: true });
@@ -18,7 +18,7 @@ function computeCacheHash(buffer, options) {
18
18
  }
19
19
  let hash = `${VERSION}/${hasha(buffer, { algorithm: 'sha256' })}`;
20
20
  if (options) {
21
- hash += "/" + hasha(JSON.stringify(options), { algorithm: 'md5' });
21
+ hash += '/' + hasha(JSON.stringify(options), { algorithm: 'md5' });
22
22
  }
23
23
  return hash;
24
24
  }
@@ -49,4 +49,4 @@ async function addToCacheCompressImage(hash, image) {
49
49
  await fs.writeFile(path.join(location, 'data'), image.data);
50
50
  await fs.writeFile(path.join(location, 'format'), JSON.stringify(image.format));
51
51
  }
52
- export { cleanCache, computeCacheHash, getFromCacheCompressImage, addToCacheCompressImage };
52
+ export { cleanCache, computeCacheHash, getFromCacheCompressImage, addToCacheCompressImage, };
@@ -1,7 +1 @@
1
- import sharp from 'sharp';
2
- import type { Image } from './types.js';
3
- export declare const compressImage: (data: Buffer, options: {
4
- resize?: sharp.ResizeOptions;
5
- toFormat?: 'webp' | 'pjpg' | 'avif' | 'unchanged';
6
- }) => Promise<Image | undefined>;
7
- export declare function compress(exclude: string): Promise<void>;
1
+ export declare function compressFolder(exclude: string): Promise<void>;
package/dist/compress.js CHANGED
@@ -1,27 +1,13 @@
1
1
  import * as fs from 'fs/promises';
2
2
  import * as path from 'path';
3
- import { optimize as svgo } from 'svgo';
4
- import { minify as htmlminifier } from 'html-minifier-terser';
5
- import { minify as csso } from 'csso';
6
- import { transform as lightcss } from 'lightningcss';
7
3
  import { formatBytes } from './utils.js';
8
- import sharp from 'sharp';
9
- import swc from '@swc/core';
10
4
  import $state from './state.js';
11
5
  import { globby } from 'globby';
12
- import config from './config.js';
13
6
  import ora from 'ora';
14
- import { getFromCacheCompressImage, addToCacheCompressImage, computeCacheHash, } from './cache.js';
15
- async function compressJS(code) {
16
- const newjsresult = await swc.minify(code, { compress: true, mangle: true });
17
- return newjsresult.code;
18
- }
19
- async function compressInlineJS(code) {
20
- const newCode = await compressJS(code);
21
- if (newCode && newCode.length < code.length)
22
- return newCode;
23
- return code;
24
- }
7
+ import { compressCSS } from './compressors/css.js';
8
+ import { compressJS } from './compressors/js.js';
9
+ import { compressHTML } from './compressors/html.js';
10
+ import { compressImage } from './compressors/images.js';
25
11
  const processFile = async (file, stats) => {
26
12
  let writeData = undefined;
27
13
  try {
@@ -33,7 +19,8 @@ const processFile = async (file, stats) => {
33
19
  case '.svg':
34
20
  case '.webp':
35
21
  case '.avif':
36
- const newImage = await compressImageFile(file);
22
+ const imgData = await fs.readFile(file);
23
+ const newImage = await compressImage(imgData, {});
37
24
  if ((newImage === null || newImage === void 0 ? void 0 : newImage.data) && newImage.data.length < stats.size) {
38
25
  writeData = newImage.data;
39
26
  }
@@ -41,44 +28,14 @@ const processFile = async (file, stats) => {
41
28
  case '.html':
42
29
  case '.htm':
43
30
  const htmldata = await fs.readFile(file);
44
- const newhtmlData = await htmlminifier(htmldata.toString(), {
45
- minifyCSS: true,
46
- minifyJS: compressInlineJS,
47
- sortClassName: true,
48
- sortAttributes: true,
49
- });
31
+ const newhtmlData = await compressHTML(htmldata);
50
32
  writeData = newhtmlData;
51
33
  break;
52
34
  case '.css':
53
35
  const cssdata = await fs.readFile(file);
54
- // Compress with csso
55
- const cssoCSSData = Buffer.from(await csso(cssdata.toString(), { comments: false }).css);
56
- // Compress with lightningcss
57
- let lightCSSData;
58
- try {
59
- lightCSSData = lightcss({
60
- filename: 'style.css',
61
- code: cssdata,
62
- minify: true,
63
- sourceMap: false,
64
- }).code;
65
- }
66
- catch (e) {
67
- // Error while processing with lightningcss
68
- // Ignore
69
- }
70
- // Pick the best
71
- if (cssoCSSData && lightCSSData) {
72
- writeData =
73
- cssoCSSData.length <= lightCSSData.length
74
- ? cssoCSSData
75
- : lightCSSData;
76
- }
77
- else if (cssoCSSData && !lightCSSData) {
78
- writeData = cssoCSSData;
79
- }
80
- else if (!cssoCSSData && lightCSSData) {
81
- writeData = lightCSSData;
36
+ const newCSS = await compressCSS(cssdata);
37
+ if (newCSS && newCSS.length < cssdata.length) {
38
+ writeData = newCSS;
82
39
  }
83
40
  break;
84
41
  case '.js':
@@ -110,122 +67,7 @@ const processFile = async (file, stats) => {
110
67
  $state.compressedFiles.add(file);
111
68
  $state.reportSummary(result);
112
69
  };
113
- function createWebpOptions(opt) {
114
- return {
115
- nearLossless: opt.mode === 'lossless',
116
- quality: opt.quality,
117
- effort: opt.effort,
118
- };
119
- }
120
- export const compressImage = async (data, options) => {
121
- var _a, _b;
122
- const cacheHash = computeCacheHash(data, options);
123
- const imageFromCache = await getFromCacheCompressImage(cacheHash);
124
- if (imageFromCache) {
125
- return imageFromCache;
126
- }
127
- // Load modifiable toFormat
128
- let toFormat = options.toFormat || 'unchanged';
129
- if (!config.image.compress)
130
- return undefined;
131
- let sharpFile = await sharp(data, { animated: true });
132
- const meta = await sharpFile.metadata();
133
- if (meta.pages && meta.pages > 1) {
134
- // Skip animated images for the moment.
135
- return undefined;
136
- }
137
- let outputFormat;
138
- // Special case for svg
139
- if (meta.format === 'svg') {
140
- const newData = svgo(data, {
141
- multipass: true,
142
- plugins: [
143
- {
144
- name: 'preset-default',
145
- params: {
146
- overrides: {
147
- removeViewBox: false,
148
- },
149
- },
150
- },
151
- ],
152
- });
153
- if (newData.error || newData.modernError) {
154
- console.log(`Error processing svg ${data}`);
155
- return undefined;
156
- }
157
- return { format: 'svg', data: Buffer.from(newData.data, 'utf8') };
158
- }
159
- // The bitmap images
160
- if (toFormat === 'unchanged') {
161
- switch (meta.format) {
162
- case 'png':
163
- sharpFile = sharpFile.png(config.image.png.options || {});
164
- outputFormat = 'png';
165
- break;
166
- case 'jpeg':
167
- case 'jpg':
168
- sharpFile = sharpFile.jpeg(config.image.jpeg.options || {});
169
- outputFormat = 'jpg';
170
- break;
171
- case 'webp':
172
- sharpFile = sharpFile.webp(createWebpOptions(config.image.webp.options_lossly) || {});
173
- outputFormat = 'webp';
174
- break;
175
- case 'avif':
176
- sharpFile = sharpFile.avif();
177
- outputFormat = 'avif';
178
- break;
179
- }
180
- }
181
- else {
182
- // To format
183
- switch (toFormat) {
184
- case 'pjpg':
185
- sharpFile = sharpFile.jpeg({ ...config.image.jpeg.options, progressive: true } || {});
186
- outputFormat = 'jpg';
187
- break;
188
- case 'webp':
189
- sharpFile = sharpFile.webp(createWebpOptions(meta.format === 'png'
190
- ? config.image.webp.options_lossless
191
- : config.image.webp.options_lossly));
192
- outputFormat = 'webp';
193
- break;
194
- case 'avif':
195
- sharpFile = sharpFile.avif({ effort: 6 });
196
- outputFormat = 'avif';
197
- break;
198
- }
199
- }
200
- // Unknow input format or output format
201
- // Can't do
202
- if (!outputFormat)
203
- return undefined;
204
- // If resize is requested
205
- if (((_a = options.resize) === null || _a === void 0 ? void 0 : _a.width) && ((_b = options.resize) === null || _b === void 0 ? void 0 : _b.height)) {
206
- sharpFile = sharpFile.resize({
207
- ...options.resize,
208
- fit: 'fill',
209
- withoutEnlargement: true,
210
- });
211
- }
212
- //
213
- // Output image processed
214
- //
215
- // Add to cache
216
- const outputImage = {
217
- format: outputFormat,
218
- data: await sharpFile.toBuffer(),
219
- };
220
- await addToCacheCompressImage(cacheHash, outputImage);
221
- // Go
222
- return outputImage;
223
- };
224
- const compressImageFile = async (file) => {
225
- const buffer = await fs.readFile(file);
226
- return compressImage(buffer, {});
227
- };
228
- export async function compress(exclude) {
70
+ export async function compressFolder(exclude) {
229
71
  const spinner = ora(getProgressText()).start();
230
72
  const globs = ['**/**'];
231
73
  if (exclude)
@@ -0,0 +1,2 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ export declare function compressCSS(originalCode: Buffer, type?: 'inline' | undefined): Promise<Buffer>;
@@ -0,0 +1,42 @@
1
+ import { minify as csso } from 'csso';
2
+ import { transform as lightcss, transformStyleAttribute as lightcssStyleAttribute, } from 'lightningcss';
3
+ export async function compressCSS(originalCode, type) {
4
+ // csso only support css files. No inline style
5
+ let cssoCSSData = undefined;
6
+ if (type !== 'inline') {
7
+ // Compress with csso
8
+ cssoCSSData = Buffer.from(await csso(originalCode.toString(), { comments: false }).css);
9
+ }
10
+ // Compress with lightningcss
11
+ let lightCSSData;
12
+ try {
13
+ const options = {
14
+ code: originalCode,
15
+ minify: true,
16
+ sourceMap: false,
17
+ };
18
+ if (type === 'inline') {
19
+ lightCSSData = lightcssStyleAttribute(options).code;
20
+ }
21
+ else {
22
+ lightCSSData = lightcss({ filename: 'style.css', ...options }).code;
23
+ }
24
+ }
25
+ catch (e) {
26
+ // Error while processing with lightningcss
27
+ // Ignore, we have csso as backup
28
+ }
29
+ let resultBuffer = undefined;
30
+ // Pick the best
31
+ if (cssoCSSData && lightCSSData) {
32
+ resultBuffer =
33
+ cssoCSSData.length <= lightCSSData.length ? cssoCSSData : lightCSSData;
34
+ }
35
+ else if (cssoCSSData && !lightCSSData) {
36
+ resultBuffer = cssoCSSData;
37
+ }
38
+ else if (!cssoCSSData && lightCSSData) {
39
+ resultBuffer = lightCSSData;
40
+ }
41
+ return resultBuffer || originalCode;
42
+ }
@@ -0,0 +1,2 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ export declare function compressHTML(originalCode: Buffer): Promise<Buffer>;
@@ -0,0 +1,27 @@
1
+ import { minify } from 'html-minifier-terser';
2
+ import { compressCSS } from './css.js';
3
+ import { compressJS } from './js.js';
4
+ async function minifyJSinHTML(originalCode) {
5
+ const newCode = await compressJS(originalCode);
6
+ if (newCode && newCode.length < originalCode.length)
7
+ return newCode;
8
+ return originalCode;
9
+ }
10
+ async function minifyCSSinHTML(originalCode, type) {
11
+ const originalBuffer = Buffer.from(originalCode);
12
+ const newCSS = await compressCSS(originalBuffer, type);
13
+ if (newCSS && newCSS.length < originalBuffer.length)
14
+ return newCSS.toString();
15
+ return originalCode;
16
+ }
17
+ export async function compressHTML(originalCode) {
18
+ const newhtmlData = await minify(originalCode.toString(), {
19
+ minifyCSS: minifyCSSinHTML,
20
+ minifyJS: minifyJSinHTML,
21
+ sortClassName: true,
22
+ sortAttributes: true,
23
+ });
24
+ if (newhtmlData)
25
+ return Buffer.from(newhtmlData, 'utf-8');
26
+ return originalCode;
27
+ }
@@ -0,0 +1,11 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ import sharp from 'sharp';
3
+ export type ImageFormat = 'webp' | 'svg' | 'jpg' | 'png' | 'avif' | undefined;
4
+ export type Image = {
5
+ format: ImageFormat;
6
+ data: Buffer;
7
+ };
8
+ export declare function compressImage(data: Buffer, options: {
9
+ resize?: sharp.ResizeOptions;
10
+ toFormat?: 'webp' | 'pjpg' | 'avif' | 'unchanged';
11
+ }): Promise<Image | undefined>;
@@ -0,0 +1,115 @@
1
+ import sharp from 'sharp';
2
+ import { optimize as svgo } from 'svgo';
3
+ import { getFromCacheCompressImage, addToCacheCompressImage, computeCacheHash, } from '../cache.js';
4
+ import config from '../config.js';
5
+ function createWebpOptions(opt) {
6
+ return {
7
+ nearLossless: opt.mode === 'lossless',
8
+ quality: opt.quality,
9
+ effort: opt.effort,
10
+ };
11
+ }
12
+ export async function compressImage(data, options) {
13
+ var _a, _b;
14
+ const cacheHash = computeCacheHash(data, options);
15
+ const imageFromCache = await getFromCacheCompressImage(cacheHash);
16
+ if (imageFromCache) {
17
+ return imageFromCache;
18
+ }
19
+ // Load modifiable toFormat
20
+ let toFormat = options.toFormat || 'unchanged';
21
+ if (!config.image.compress)
22
+ return undefined;
23
+ let sharpFile = await sharp(data, { animated: true });
24
+ const meta = await sharpFile.metadata();
25
+ if (meta.pages && meta.pages > 1) {
26
+ // Skip animated images for the moment.
27
+ return undefined;
28
+ }
29
+ let outputFormat;
30
+ // Special case for svg
31
+ if (meta.format === 'svg') {
32
+ const newData = svgo(data, {
33
+ multipass: true,
34
+ plugins: [
35
+ {
36
+ name: 'preset-default',
37
+ params: {
38
+ overrides: {
39
+ removeViewBox: false,
40
+ },
41
+ },
42
+ },
43
+ ],
44
+ });
45
+ if (newData.error || newData.modernError) {
46
+ console.log(`Error processing svg ${data}`);
47
+ return undefined;
48
+ }
49
+ return { format: 'svg', data: Buffer.from(newData.data, 'utf8') };
50
+ }
51
+ // The bitmap images
52
+ if (toFormat === 'unchanged') {
53
+ switch (meta.format) {
54
+ case 'png':
55
+ sharpFile = sharpFile.png(config.image.png.options || {});
56
+ outputFormat = 'png';
57
+ break;
58
+ case 'jpeg':
59
+ case 'jpg':
60
+ sharpFile = sharpFile.jpeg(config.image.jpeg.options || {});
61
+ outputFormat = 'jpg';
62
+ break;
63
+ case 'webp':
64
+ sharpFile = sharpFile.webp(createWebpOptions(config.image.webp.options_lossly) || {});
65
+ outputFormat = 'webp';
66
+ break;
67
+ case 'avif':
68
+ sharpFile = sharpFile.avif();
69
+ outputFormat = 'avif';
70
+ break;
71
+ }
72
+ }
73
+ else {
74
+ // To format
75
+ switch (toFormat) {
76
+ case 'pjpg':
77
+ sharpFile = sharpFile.jpeg({ ...config.image.jpeg.options, progressive: true } || {});
78
+ outputFormat = 'jpg';
79
+ break;
80
+ case 'webp':
81
+ sharpFile = sharpFile.webp(createWebpOptions(meta.format === 'png'
82
+ ? config.image.webp.options_lossless
83
+ : config.image.webp.options_lossly));
84
+ outputFormat = 'webp';
85
+ break;
86
+ case 'avif':
87
+ sharpFile = sharpFile.avif({ effort: 6 });
88
+ outputFormat = 'avif';
89
+ break;
90
+ }
91
+ }
92
+ // Unknow input format or output format
93
+ // Can't do
94
+ if (!outputFormat)
95
+ return undefined;
96
+ // If resize is requested
97
+ if (((_a = options.resize) === null || _a === void 0 ? void 0 : _a.width) && ((_b = options.resize) === null || _b === void 0 ? void 0 : _b.height)) {
98
+ sharpFile = sharpFile.resize({
99
+ ...options.resize,
100
+ fit: 'fill',
101
+ withoutEnlargement: true,
102
+ });
103
+ }
104
+ //
105
+ // Output image processed
106
+ //
107
+ // Add to cache
108
+ const outputImage = {
109
+ format: outputFormat,
110
+ data: await sharpFile.toBuffer(),
111
+ };
112
+ await addToCacheCompressImage(cacheHash, outputImage);
113
+ // Go
114
+ return outputImage;
115
+ }
@@ -0,0 +1 @@
1
+ export declare function compressJS(originalCode: string): Promise<string>;
@@ -0,0 +1,8 @@
1
+ import swc from '@swc/core';
2
+ export async function compressJS(originalCode) {
3
+ const newjsresult = await swc.minify(originalCode, {
4
+ compress: true,
5
+ mangle: true,
6
+ });
7
+ return newjsresult.code;
8
+ }
@@ -0,0 +1 @@
1
+ export declare function compressJS(originalCode: string): Promise<string>;
@@ -0,0 +1,8 @@
1
+ import swc from '@swc/core';
2
+ export async function compressJS(originalCode) {
3
+ const newjsresult = await swc.minify(originalCode, {
4
+ compress: true,
5
+ mangle: true,
6
+ });
7
+ return newjsresult.code;
8
+ }
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from 'commander';
3
- import { compress } from './compress.js';
3
+ import { compressFolder } from './compress.js';
4
4
  import { optimize } from './optimize.js';
5
5
  import $state from './state.js';
6
6
  import { table } from 'table';
@@ -21,7 +21,10 @@ const logo = ` __ __
21
21
  `;
22
22
  console.log(logo);
23
23
  const program = new Command();
24
- program.name('jampack').description('Static website Optimizer').version(VERSION);
24
+ program
25
+ .name('jampack')
26
+ .description('Static website Optimizer')
27
+ .version(VERSION);
25
28
  program
26
29
  .command('pack', { isDefault: true })
27
30
  .description('todo')
@@ -54,7 +57,7 @@ program
54
57
  if (!options.onlyoptim && !options.fast) {
55
58
  printTitle('PASS 2 - Compressing the rest');
56
59
  console.time('Done');
57
- await compress(options.exclude);
60
+ await compressFolder(options.exclude);
58
61
  console.timeEnd('Done');
59
62
  }
60
63
  printSummary();
package/dist/optimize.js CHANGED
@@ -4,7 +4,7 @@ import * as fs from 'fs/promises';
4
4
  import cheerio from 'cheerio';
5
5
  import { isNumeric } from './utils.js';
6
6
  import config from './config.js';
7
- import { compressImage } from './compress.js';
7
+ import { compressImage } from './compressors/images.js';
8
8
  import svgToMiniDataURI from 'mini-svg-data-uri';
9
9
  import $state from './state.js';
10
10
  import kleur from 'kleur';
@@ -307,7 +307,7 @@ async function setImageSize(htmlfile, img, image) {
307
307
  if (!isNumeric(width)) {
308
308
  $state.reportIssue(htmlfile, {
309
309
  type: 'warn',
310
- msg: `Invalid width attribute "${width}" format - overriding`,
310
+ msg: `Invalid width attribute format: "${width}" - overriding`,
311
311
  });
312
312
  width = undefined;
313
313
  }
@@ -316,7 +316,7 @@ async function setImageSize(htmlfile, img, image) {
316
316
  if (!isNumeric(height)) {
317
317
  $state.reportIssue(htmlfile, {
318
318
  type: 'warn',
319
- msg: `Invalid height attribute "${height}" format - overriding`,
319
+ msg: `Invalid height attribute format: "${height}" - overriding`,
320
320
  });
321
321
  height = undefined;
322
322
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@divriots/jampack",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "Packer for static websites",
5
5
  "author": "Georges Gomes @georges-gomes",
6
6
  "bin": {
@@ -25,7 +25,6 @@
25
25
  "@types/sharp": "^0.31.0",
26
26
  "@types/svgo": "^2.6.4",
27
27
  "@types/table": "^6.3.2",
28
- "chalk": "^5.1.2",
29
28
  "cheerio": "0.22.0",
30
29
  "commander": "^9.4.1",
31
30
  "csso": "^5.0.5",