@divriots/jampack 0.1.3 → 0.1.4

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.
@@ -1,4 +1,4 @@
1
+ /// <reference types="node" resolution-mode="require"/>
1
2
  import sharp from 'sharp';
2
- import type { Result } from './types.js';
3
3
  export declare const compressImage: (data: Buffer, resize: sharp.ResizeOptions) => Promise<Buffer | undefined>;
4
- export declare function compress(dir: string, initResult: Result[]): Promise<void>;
4
+ export declare function compress(glob: string): Promise<void>;
package/dist/compress.js CHANGED
@@ -4,58 +4,21 @@ import { optimize as svgo } from "svgo";
4
4
  import { minify as htmlminifier } from 'html-minifier-terser';
5
5
  import { minify as csso } from "csso";
6
6
  import { formatBytes } from './utils.js';
7
- import { table } from 'table';
8
7
  import sharp from 'sharp';
9
8
  import swc from '@swc/core';
10
- let state;
11
- let compressedFiles = [];
12
- const beginProgress = (initResults) => {
13
- state = {
14
- total: {
15
- nbFiles: 0,
16
- nbFilesCompressed: 0,
17
- dataLenUncompressed: 0,
18
- dataLenCompressed: 0
19
- },
20
- detailsByExtension: {},
21
- };
22
- initResults.forEach(r => {
23
- addProgress(r);
24
- compressedFiles.push(r.file);
25
- });
26
- };
27
- const addProgress = (r) => {
28
- const isCompressed = r.compressedSize < r.originalSize ? 1 : 0;
29
- state.total.nbFiles++;
30
- state.total.nbFilesCompressed += isCompressed;
31
- state.total.dataLenUncompressed += r.originalSize;
32
- state.total.dataLenCompressed += r.compressedSize;
33
- const ext = path.extname(r.file);
34
- if (ext) {
35
- var summary = state.detailsByExtension[ext];
36
- if (!summary) {
37
- summary = {
38
- nbFiles: 0,
39
- nbFilesCompressed: 0,
40
- dataLenUncompressed: 0,
41
- dataLenCompressed: 0
42
- };
43
- state.detailsByExtension[ext] = summary;
44
- }
45
- summary.nbFiles++;
46
- summary.nbFilesCompressed += isCompressed;
47
- summary.dataLenUncompressed += r.originalSize;
48
- summary.dataLenCompressed += r.compressedSize;
49
- }
9
+ import globalState from './state.js';
10
+ import { globby } from 'globby';
11
+ const beginProgress = () => {
50
12
  };
51
- const printProgress = (r) => {
52
- addProgress(r);
53
- const msg = `${state.total.nbFiles} files | ${formatBytes(state.total.dataLenUncompressed)} → ${formatBytes(state.total.dataLenCompressed)}`;
54
- if (!process.stdout.cursorTo) {
55
- // In CI we don't have access to cursorTo
56
- console.log(msg);
13
+ const printProgress = () => {
14
+ const gain = globalState.summary.dataLenUncompressed - globalState.summary.dataLenCompressed;
15
+ const msg = `${globalState.summary.nbFiles} files | ${formatBytes(globalState.summary.dataLenUncompressed)} → ${formatBytes(globalState.summary.dataLenCompressed)} | -${formatBytes(gain)} `;
16
+ if (!process.stdout.clearLine || !process.stdout.cursorTo) {
17
+ // In CI we don't have access to clearLine or cursorTo
18
+ // Just don't log any progress
57
19
  }
58
20
  else {
21
+ process.stdout.clearLine(0);
59
22
  process.stdout.cursorTo(0);
60
23
  process.stdout.write(msg);
61
24
  }
@@ -63,27 +26,6 @@ const printProgress = (r) => {
63
26
  const endProgress = () => {
64
27
  process.stdout.write('\n');
65
28
  };
66
- const printDetails = () => {
67
- const dataTable = [['Extension', 'Files', 'Compressed', 'Original', 'Compressed', 'Gain']];
68
- const config = {
69
- columns: [
70
- { alignment: 'left' },
71
- { alignment: 'right' },
72
- { alignment: 'right' },
73
- { alignment: 'right' },
74
- { alignment: 'right' }
75
- ],
76
- };
77
- Object.entries(state.detailsByExtension).forEach(([ext, summary]) => {
78
- if (summary.dataLenCompressed < summary.dataLenUncompressed) {
79
- const row = [ext, summary.nbFiles, summary.nbFilesCompressed, formatBytes(summary.dataLenUncompressed), formatBytes(summary.dataLenCompressed), '-' + formatBytes(summary.dataLenUncompressed - summary.dataLenCompressed)];
80
- dataTable.push(row);
81
- }
82
- });
83
- const total = ['Total', state.total.nbFiles, state.total.nbFilesCompressed, formatBytes(state.total.dataLenUncompressed), formatBytes(state.total.dataLenCompressed), '-' + formatBytes(state.total.dataLenUncompressed - state.total.dataLenCompressed)];
84
- dataTable.push(total);
85
- console.log(table(dataTable, config));
86
- };
87
29
  const processFile = async (file, stats) => {
88
30
  const result = {
89
31
  file,
@@ -129,18 +71,21 @@ const processFile = async (file, stats) => {
129
71
  }
130
72
  catch (e) {
131
73
  // console error for the moment
74
+ console.error(`\n${file}`);
132
75
  console.error(e);
133
76
  }
134
77
  // Writedata
135
78
  if (writeData && writeData.length < result.originalSize) {
136
79
  result.compressedSize = writeData.length;
137
- await fs.writeFile(file, writeData);
80
+ if (!globalState.args.nowrite) {
81
+ await fs.writeFile(file, writeData);
82
+ }
138
83
  }
139
- printProgress(result);
140
- return result;
84
+ globalState.addFile(result);
85
+ printProgress();
141
86
  };
142
87
  export const compressImage = async (data, resize) => {
143
- const sharpFile = await sharp(data);
88
+ const sharpFile = await sharp(data, { animated: true });
144
89
  const meta = await sharpFile.metadata();
145
90
  switch (meta.format) {
146
91
  case 'svg':
@@ -155,7 +100,7 @@ export const compressImage = async (data, resize) => {
155
100
  case 'jpeg':
156
101
  case 'webp':
157
102
  case 'gif':
158
- return await sharpFile.resize(resize).toBuffer();
103
+ return await sharpFile.resize({ ...resize, fit: 'fill', withoutEnlargement: true }).toBuffer();
159
104
  }
160
105
  return undefined;
161
106
  };
@@ -163,26 +108,14 @@ const compressImageFile = async (file) => {
163
108
  const buffer = await fs.readFile(file);
164
109
  return compressImage(buffer, {});
165
110
  };
166
- const processDirectory = async (directoryPath) => {
167
- const filesInDirectory = await fs.readdir(directoryPath);
168
- const files = await Promise.all(filesInDirectory.map(async (file) => {
169
- const filePath = path.join(directoryPath, file);
170
- const stats = await fs.stat(filePath);
171
- if (stats.isDirectory()) {
172
- return processDirectory(filePath);
173
- }
174
- else {
175
- if (compressedFiles.includes(filePath)) {
176
- return [];
177
- }
178
- return [await processFile(filePath, stats)];
111
+ export async function compress(glob) {
112
+ beginProgress();
113
+ const paths = await globby(glob, { cwd: globalState.dir, absolute: true });
114
+ // "Parallel" processing
115
+ await Promise.all(paths.map(async (file) => {
116
+ if (!globalState.compressedFiles.has(file)) {
117
+ await processFile(file, await fs.stat(file));
179
118
  }
180
119
  }));
181
- return files.filter((file) => file.length).flat(1); // Remove empty dir and flat it all
182
- };
183
- export async function compress(dir, initResult) {
184
- beginProgress(initResult);
185
- await processDirectory(dir);
186
120
  endProgress();
187
- printDetails();
188
121
  }
package/dist/index.js CHANGED
@@ -2,6 +2,19 @@
2
2
  import { Command } from 'commander';
3
3
  import { compress } from './compress.js';
4
4
  import { optimize } from './optimize.js';
5
+ import kleur from 'kleur';
6
+ import globalState from './state.js';
7
+ import { table } from 'table';
8
+ import { formatBytes } from './utils.js';
9
+ const logo = ` __ __
10
+ |__|____ _____ ___________ ____ | | __
11
+ | \\__ \\ / \\\\____ \\__ \\ _/ ___\\| |/ /
12
+ | |/ __ \\| Y Y \\ |_> > __ \\\\ \\___| <
13
+ /\\__| (____ /__|_| / __(____ /\\___ >__|_ \\
14
+ \\______| \\/ \\/| | \\/ \\/ \\/
15
+ |__| by ‹div›RIOTS (c)2022
16
+ `;
17
+ console.log(logo);
5
18
  const program = new Command();
6
19
  program
7
20
  .name('jampack')
@@ -10,11 +23,44 @@ program
10
23
  program.command('pack', { isDefault: true })
11
24
  .description('todo')
12
25
  .argument('<dir>', 'Directory to pack')
13
- .action(async (str, options) => {
14
- let compressedResults = [];
15
- console.log(`PASS 1 - Optimizing...`);
16
- compressedResults = await optimize(str);
17
- console.log(`PASS 2 - Compressing...`);
18
- await compress(str, compressedResults);
26
+ .option('--nowrite', 'No write')
27
+ .option('--onlycomp', 'Only compress')
28
+ .option('--onlyoptim', 'Only optimize')
29
+ .action(async (dir, options) => {
30
+ globalState.dir = dir;
31
+ globalState.args = options;
32
+ if (!options.onlyoptim && !options.onlycomp) {
33
+ console.log(kleur.bgGreen(kleur.black(`\n PASS 1 - Compressing embeddables `)));
34
+ await compress("**/*.{css,svg,js}");
35
+ }
36
+ if (!options.onlycomp) {
37
+ console.log(kleur.bgGreen(kleur.black(`\n PASS 2 - Optimizing `)));
38
+ await optimize();
39
+ }
40
+ if (!options.onlyoptim) {
41
+ console.log(kleur.bgGreen(kleur.black(`\n PASS 3 - Compressing the rest`)));
42
+ await compress("**/**");
43
+ }
44
+ printDetails();
19
45
  });
20
46
  program.parse();
47
+ function printDetails() {
48
+ const dataTable = [['Extension', 'Compressed', 'Original', 'Compressed', 'Gain']];
49
+ const config = {
50
+ columns: [
51
+ { alignment: 'left' },
52
+ { alignment: 'right' },
53
+ { alignment: 'right' },
54
+ { alignment: 'right' }
55
+ ],
56
+ };
57
+ Object.entries(globalState.summaryByExtension).forEach(([ext, summary]) => {
58
+ if (summary.dataLenCompressed < summary.dataLenUncompressed) {
59
+ const row = [ext, `${summary.nbFilesCompressed} / ${summary.nbFiles}`, formatBytes(summary.dataLenUncompressed), formatBytes(summary.dataLenCompressed), '-' + formatBytes(summary.dataLenUncompressed - summary.dataLenCompressed)];
60
+ dataTable.push(row);
61
+ }
62
+ });
63
+ const total = ['Total', `${globalState.summary.nbFilesCompressed} / ${globalState.summary.nbFiles}`, formatBytes(globalState.summary.dataLenUncompressed), formatBytes(globalState.summary.dataLenCompressed), '-' + formatBytes(globalState.summary.dataLenUncompressed - globalState.summary.dataLenCompressed)];
64
+ dataTable.push(total);
65
+ console.log(table(dataTable, config));
66
+ }
@@ -0,0 +1,3 @@
1
+ export declare function info(message: string): void;
2
+ export declare function warn(message: string): void;
3
+ export declare function error(message: string): void;
package/dist/logger.js ADDED
@@ -0,0 +1,9 @@
1
+ export function info(message) {
2
+ console.info(message);
3
+ }
4
+ export function warn(message) {
5
+ console.warn(message);
6
+ }
7
+ export function error(message) {
8
+ console.error(message);
9
+ }
@@ -1,2 +1 @@
1
- import type { Result } from './types.js';
2
- export declare function optimize(dir: string): Promise<Result[]>;
1
+ export declare function optimize(): Promise<void>;
package/dist/optimize.js CHANGED
@@ -7,11 +7,11 @@ import sharp from "sharp";
7
7
  import options from './options.js';
8
8
  import { compressImage } from './compress.js';
9
9
  import svgToMiniDataURI from 'mini-svg-data-uri';
10
- const compressedImages = [];
11
- const compressedResults = [];
12
- async function analyse(dir, file) {
10
+ import globalState from './state.js';
11
+ import { exit } from 'process';
12
+ async function analyse(file) {
13
13
  console.log('Processing ' + file);
14
- const html = (await fs.readFile(path.join(dir, file))).toString();
14
+ const html = (await fs.readFile(path.join(globalState.dir, file))).toString();
15
15
  const $ = cheerio.load(html, {});
16
16
  const imgs = $('img');
17
17
  const imgsArray = [];
@@ -21,138 +21,178 @@ async function analyse(dir, file) {
21
21
  // Process images sequentially
22
22
  await imgsArray.reduce(async (previousPromise, imgElement) => {
23
23
  await previousPromise;
24
- return processImage(dir, file, $, imgElement);
24
+ return processImage(file, $, imgElement);
25
25
  }, Promise.resolve());
26
- await fs.writeFile(path.join(dir, file), $.html());
27
- }
28
- async function processImage(dir, file, $, imgElement) {
29
- const img = $(imgElement);
30
- /*
31
- * Attribute 'alt'
32
- */
33
- const attrib_alt = img.attr('alt');
34
- if (attrib_alt === undefined) {
35
- console.warn('<img> has no alt attribute - adding an empty but you should fix it');
36
- img.attr('alt', "");
37
- }
38
- /*
39
- * Attribute 'src'
40
- */
41
- const attrib_src = img.attr('src');
42
- console.log(`- Image ${attrib_src}`);
43
- if (!attrib_src) {
44
- console.warn('<img> has no src attribute');
45
- return;
46
- }
47
- if (attrib_src.startsWith('data:')) {
48
- // Data URI image
49
- // TODO: try to compress it
50
- return;
51
- }
52
- if (!isLocal(attrib_src)) {
53
- // Image not local, don't touch it
54
- return;
26
+ if (!globalState.args.nowrite) {
27
+ await fs.writeFile(path.join(globalState.dir, file), $.html());
55
28
  }
56
- /*
57
- * Attribute 'loading'
58
- */
59
- const attr_loading = img.attr('loading');
60
- switch (attr_loading) {
61
- case undefined:
62
- // Go lazy by default
63
- img.attr('loading', 'lazy');
64
- break;
65
- case 'eager':
66
- img.removeAttr('loading');
67
- break;
68
- case 'lazy':
69
- // Don't touch it
70
- break;
71
- default:
72
- console.warn(`Invalid loading attribute ${attr_loading}`);
73
- }
74
- /*
75
- * Attribute 'decoding'
76
- */
77
- img.attr('decoding', 'async');
78
- /*
79
- * Loading image
80
- */
81
- const absoluteImgPath = translateSrc(dir, path.dirname(file), attrib_src);
82
- // file exists?
29
+ }
30
+ async function processImage(file, $, imgElement) {
83
31
  try {
84
- const stats = await fs.stat(absoluteImgPath);
85
- }
86
- catch (e) {
87
- console.error(`Missing img ${absoluteImgPath}`);
88
- return;
89
- }
90
- const sharpFile = sharp(absoluteImgPath);
91
- const meta = await sharpFile.metadata();
92
- const originalData = await fs.readFile(absoluteImgPath);
93
- /*
94
- * Embed small images
95
- *
96
- * Note: This check is done pre-compression so more opportunities could
97
- * be done if done post compression.
98
- */
99
- let isEmbed = false;
100
- if (originalData.length <= options.image.embed_size) {
101
- let datauri = undefined;
102
- switch (meta.format) {
103
- case 'svg':
104
- const compressedData = await compressImage(originalData, {});
105
- const svgEmbed = (compressedData && compressedData.length < originalData.length) ? compressedData : originalData;
106
- datauri = svgToMiniDataURI(svgEmbed.toString());
32
+ const img = $(imgElement);
33
+ /*
34
+ * Attribute 'alt'
35
+ */
36
+ const attrib_alt = img.attr('alt');
37
+ if (attrib_alt === undefined) {
38
+ console.warn('<img> has no alt attribute - adding an empty but you should fix it');
39
+ img.attr('alt', "");
40
+ }
41
+ /*
42
+ * Attribute 'src'
43
+ */
44
+ const attrib_src = img.attr('src');
45
+ console.log(`- Image ${attrib_src}`);
46
+ if (!attrib_src) {
47
+ console.warn('<img> has no src attribute');
48
+ return;
49
+ }
50
+ if (attrib_src.startsWith('data:')) {
51
+ // Data URI image
52
+ // TODO: try to compress it
53
+ return;
54
+ }
55
+ if (!isLocal(attrib_src)) {
56
+ // Image not local, don't touch it
57
+ return;
58
+ }
59
+ /*
60
+ * Attribute 'loading'
61
+ */
62
+ const attr_loading = img.attr('loading');
63
+ switch (attr_loading) {
64
+ case undefined:
65
+ // Go lazy by default
66
+ img.attr('loading', 'lazy');
67
+ break;
68
+ case 'eager':
69
+ img.removeAttr('loading');
107
70
  break;
108
- case 'jpg':
109
- case 'jpeg':
110
- case 'png':
111
- case 'webp':
112
- case 'gif':
113
- // TODO
71
+ case 'lazy':
72
+ // Don't touch it
114
73
  break;
74
+ default:
75
+ console.warn(`Invalid loading attribute ${attr_loading}`);
115
76
  }
116
- if (datauri) {
117
- img.attr('src', datauri);
118
- isEmbed = true;
119
- img.removeAttr('loading');
120
- img.removeAttr('decoding');
77
+ /*
78
+ * Attribute 'decoding'
79
+ */
80
+ img.attr('decoding', 'async');
81
+ /*
82
+ * Loading image
83
+ */
84
+ const absoluteImgPath = translateSrc(globalState.dir, path.dirname(file), attrib_src);
85
+ // file exists?
86
+ try {
87
+ const stats = await fs.stat(absoluteImgPath);
88
+ }
89
+ catch (e) {
90
+ console.error(`Missing img ${absoluteImgPath}`);
91
+ return;
92
+ }
93
+ const sharpFile = sharp(absoluteImgPath);
94
+ const meta = await sharpFile.metadata();
95
+ const originalData = await fs.readFile(absoluteImgPath);
96
+ /*
97
+ * Embed small images
98
+ */
99
+ let isEmbed = false;
100
+ if (originalData.length <= options.image.embed_size) {
101
+ let datauri = undefined;
102
+ switch (meta.format) {
103
+ case 'svg':
104
+ const compressedData = await compressImage(originalData, {});
105
+ const svgEmbed = (compressedData && compressedData.length < originalData.length) ? compressedData : originalData;
106
+ datauri = svgToMiniDataURI(svgEmbed.toString());
107
+ break;
108
+ case 'jpg':
109
+ case 'jpeg':
110
+ case 'png':
111
+ case 'webp':
112
+ case 'gif':
113
+ // TODO
114
+ break;
115
+ }
116
+ if (datauri) {
117
+ isEmbed = true;
118
+ img.attr('src', datauri);
119
+ img.removeAttr('loading');
120
+ img.removeAttr('decoding');
121
+ }
122
+ }
123
+ if (isEmbed) {
124
+ // Image is embed, no need for more processing
125
+ return;
126
+ }
127
+ /*
128
+ * Attribute 'width' & 'height'
129
+ */
130
+ const [w, h] = setImageSize(img, meta);
131
+ if (w < 0 || h < 0) {
132
+ console.warn(`Unexpected error in image size calculation - some optimizations can't be done`);
133
+ return;
134
+ }
135
+ /*
136
+ * Compress image
137
+ */
138
+ if (!globalState.compressedFiles.has(absoluteImgPath)) {
139
+ // Image not already compressed before
140
+ const result = {
141
+ file: absoluteImgPath,
142
+ originalSize: originalData.length,
143
+ compressedSize: originalData.length
144
+ };
145
+ const newImage = await compressImage(originalData, { width: w, height: h });
146
+ if (newImage && newImage.length < originalData.length) {
147
+ if (!globalState.args.nowrite) {
148
+ fs.writeFile(absoluteImgPath, newImage);
149
+ }
150
+ result.compressedSize = newImage.length;
151
+ }
152
+ globalState.addFile(result);
153
+ }
154
+ const attr_srcset = img.attr('srcset');
155
+ if (attr_srcset) {
156
+ // If srcset is set, don't touch it.
157
+ // Just compress files
158
+ // TODO
159
+ }
160
+ else {
161
+ // Generate image set
162
+ const ext = path.extname(attrib_src);
163
+ const fullbasename = attrib_src.slice(0, -(ext.length));
164
+ const imageSrc = (addition) => `${fullbasename}${addition}${ext}`;
165
+ // Start from original image
166
+ let new_srcset = '';
167
+ // Start reduction
168
+ const step = 300; //px
169
+ const ratio = w / h;
170
+ let valueW = w - step;
171
+ let valueH = Math.trunc(valueW / ratio);
172
+ while (valueW > options.image.srcset_min_width) {
173
+ const src = imageSrc(`@${valueW}w`);
174
+ const absoluteFilename = translateSrc(globalState.dir, path.dirname(file), src);
175
+ const compressedData = await compressImage(originalData, { width: valueW, height: valueH });
176
+ if (compressedData && !globalState.args.nowrite) {
177
+ fs.writeFile(absoluteFilename, compressedData);
178
+ }
179
+ // Add file to list avoid recompression
180
+ globalState.compressedFiles.add(absoluteFilename);
181
+ new_srcset += `, ${src} ${valueW}w`;
182
+ // reduce size
183
+ valueW -= step;
184
+ valueH = Math.trunc(valueW / ratio);
185
+ }
186
+ if (new_srcset) {
187
+ img.attr('srcset', `${attrib_src} ${w}w` + new_srcset);
188
+ }
121
189
  }
122
190
  }
123
- if (isEmbed) {
124
- // Image is embed, no need for more processing
125
- return;
126
- }
127
- /*
128
- * Attribute 'width' & 'height'
129
- */
130
- const [w, h] = setImageSize(img, meta);
131
- if (w < 0 || h < 0) {
132
- console.warn(`Unexpected error in image size calculation - some optimizations can't be done`);
133
- return;
134
- }
135
- /*
136
- * Compress image
137
- */
138
- if (compressedImages.includes(absoluteImgPath)) {
139
- // Image already compressed. Skip.
140
- return;
141
- }
142
- const fileWidth = meta.width;
143
- const fileHeight = meta.height;
144
- const newImage = await compressImage(originalData, { width: w, height: h });
145
- if (newImage && newImage.length < originalData.length) {
146
- fs.writeFile(absoluteImgPath, newImage);
147
- compressedImages.push(absoluteImgPath);
148
- compressedResults.push({ file: absoluteImgPath, originalSize: originalData.length, compressedSize: newImage.length });
149
- }
150
- const attr_srcset = img.attr('srcset');
151
- if (attr_srcset) {
152
- // If srcset is set, don't touch it
153
- }
154
- else {
155
- // Generate image set
191
+ catch (e) {
192
+ console.error('Error while processing image');
193
+ console.error(e);
194
+ // exit here until we cover all the issues
195
+ exit(1);
156
196
  }
157
197
  }
158
198
  function setImageSize(img, meta) {
@@ -169,7 +209,7 @@ function setImageSize(img, meta) {
169
209
  }
170
210
  if (height !== undefined) {
171
211
  if (!isNumeric(height)) {
172
- console.warn(`Invalid width attribute "${height}" - overriding`);
212
+ console.warn(`Invalid height attribute "${height}" - overriding`);
173
213
  height = undefined;
174
214
  }
175
215
  }
@@ -214,12 +254,11 @@ function setImageSize(img, meta) {
214
254
  // Something when wrong
215
255
  throw new Error('Unexpected issue when resolving image sizes');
216
256
  }
217
- export async function optimize(dir) {
218
- const paths = await globby('**/*.{htm,html}', { cwd: dir });
257
+ export async function optimize() {
258
+ const paths = await globby('**/*.{htm,html}', { cwd: globalState.dir });
219
259
  // Sequential async
220
260
  await paths.reduce(async (previousPromise, item) => {
221
261
  await previousPromise;
222
- return analyse(dir, item);
262
+ return analyse(item);
223
263
  }, Promise.resolve());
224
- return compressedResults;
225
264
  }
package/dist/options.js CHANGED
@@ -1,7 +1,7 @@
1
1
  const default_options = {
2
2
  image: {
3
- embed_size: 800,
4
- srcset_min_width: 640 * 2,
3
+ embed_size: 0,
4
+ srcset_min_width: 400,
5
5
  srcset_max_width: 5120
6
6
  }
7
7
  };
@@ -0,0 +1,25 @@
1
+ export declare type Args = {
2
+ nowrite?: boolean;
3
+ };
4
+ export declare type Result = {
5
+ file: string;
6
+ originalSize: number;
7
+ compressedSize: number;
8
+ };
9
+ export declare type Summary = {
10
+ nbFiles: number;
11
+ nbFilesCompressed: number;
12
+ dataLenUncompressed: number;
13
+ dataLenCompressed: number;
14
+ };
15
+ export declare class GlobalState {
16
+ dir: string;
17
+ args: Args;
18
+ compressedFiles: Set<string>;
19
+ compressedFilesResult: Result[];
20
+ summary: Summary;
21
+ summaryByExtension: Record<string, Summary>;
22
+ addFile(r: Result): void;
23
+ }
24
+ declare const state: GlobalState;
25
+ export default state;
package/dist/state.js ADDED
@@ -0,0 +1,45 @@
1
+ import path from "path";
2
+ export class GlobalState {
3
+ constructor() {
4
+ this.dir = 'dist';
5
+ this.args = {};
6
+ this.compressedFiles = new Set();
7
+ this.compressedFilesResult = [];
8
+ this.summary = {
9
+ nbFiles: 0,
10
+ nbFilesCompressed: 0,
11
+ dataLenCompressed: 0,
12
+ dataLenUncompressed: 0
13
+ };
14
+ this.summaryByExtension = {};
15
+ }
16
+ addFile(r) {
17
+ const isCompressed = r.compressedSize < r.originalSize ? 1 : 0;
18
+ this.compressedFiles.add(r.file);
19
+ this.compressedFilesResult.push(r);
20
+ this.summary.nbFiles++;
21
+ state.summary.nbFilesCompressed += isCompressed;
22
+ state.summary.dataLenUncompressed += r.originalSize;
23
+ state.summary.dataLenCompressed += r.compressedSize;
24
+ const ext = path.extname(r.file);
25
+ if (ext) {
26
+ let summary = this.summaryByExtension[ext];
27
+ if (!summary) {
28
+ summary = {
29
+ nbFiles: 0,
30
+ nbFilesCompressed: 0,
31
+ dataLenUncompressed: 0,
32
+ dataLenCompressed: 0
33
+ };
34
+ this.summaryByExtension[ext] = summary;
35
+ }
36
+ summary.nbFiles++;
37
+ summary.nbFilesCompressed += isCompressed;
38
+ summary.dataLenUncompressed += r.originalSize;
39
+ summary.dataLenCompressed += r.compressedSize;
40
+ }
41
+ }
42
+ ;
43
+ }
44
+ const state = new GlobalState();
45
+ export default state;
package/dist/utils.js CHANGED
@@ -7,7 +7,7 @@ export function formatBytes(bytes, decimals = 2) {
7
7
  const dm = decimals < 0 ? 0 : decimals;
8
8
  const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
9
9
  const i = Math.floor(Math.log(bytes) / Math.log(k));
10
- return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
10
+ return `${(bytes / Math.pow(k, i)).toFixed(dm)} ${sizes[i]}`;
11
11
  }
12
12
  export function isLocal(src) {
13
13
  const u = url.parse(src);
@@ -18,7 +18,7 @@ export function translateSrc(projectRoot, htmlRelativePath, src) {
18
18
  throw new Error('Source should be local');
19
19
  }
20
20
  const srcAbsolutePath = path.join(projectRoot, src.startsWith('/') ? '' : htmlRelativePath, src);
21
- return srcAbsolutePath;
21
+ return path.resolve(srcAbsolutePath);
22
22
  }
23
23
  export function isNumeric(value) {
24
24
  return /^\d+$/.test(value);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@divriots/jampack",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Packer for static websites",
5
5
  "author": "Georges Gomes @georges-gomes",
6
6
  "bin": {
@@ -24,11 +24,13 @@
24
24
  "@types/sharp": "^0.31.0",
25
25
  "@types/svgo": "^2.6.4",
26
26
  "@types/table": "^6.3.2",
27
+ "chalk": "^5.0.1",
27
28
  "cheerio": "0.22.0",
28
29
  "commander": "^9.4.0",
29
30
  "csso": "^5.0.5",
30
31
  "globby": "^13.1.2",
31
32
  "html-minifier-terser": "^7.0.0",
33
+ "kleur": "^4.1.5",
32
34
  "mini-svg-data-uri": "^1.4.4",
33
35
  "sharp": "^0.31.0",
34
36
  "svgo": "^2.8.0",
package/dist/types.d.ts DELETED
@@ -1,5 +0,0 @@
1
- export declare type Result = {
2
- file: string;
3
- originalSize: number;
4
- compressedSize: number;
5
- };
package/dist/types.js DELETED
@@ -1 +0,0 @@
1
- export {};