@e-mc/compress 0.12.9 → 0.13.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 +10 -7
- package/index.js +164 -108
- package/package.json +3 -3
- package/worker/plugin-image.js +1 -5
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @e-mc/compress
|
|
2
2
|
|
|
3
|
-
* NodeJS 18
|
|
3
|
+
* NodeJS 18.20.5 LTS
|
|
4
4
|
* ES2022
|
|
5
5
|
|
|
6
6
|
## General Usage
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
## Interface
|
|
11
11
|
|
|
12
|
-
* [View Source](https://www.unpkg.com/@e-mc/types@0.
|
|
12
|
+
* [View Source](https://www.unpkg.com/@e-mc/types@0.13.1/lib/index.d.ts)
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
import type { IModule, ModuleConstructor } from "./index";
|
|
@@ -58,7 +58,9 @@ interface CompressConstructor extends ModuleConstructor {
|
|
|
58
58
|
## Settings
|
|
59
59
|
|
|
60
60
|
```typescript
|
|
61
|
-
import type {
|
|
61
|
+
import type { CacheDirAction } from "./settings";
|
|
62
|
+
|
|
63
|
+
import type { BrotliOptions, ZlibOptions } from "node:zlib";
|
|
62
64
|
import type { Options as ZopfliOptions } from "node-zopfli";
|
|
63
65
|
|
|
64
66
|
interface CompressModule {
|
|
@@ -67,7 +69,8 @@ interface CompressModule {
|
|
|
67
69
|
zopfli?: ZopfliOptions;
|
|
68
70
|
settings?: {
|
|
69
71
|
broadcast_id?: string | string[];
|
|
70
|
-
cache?: boolean;
|
|
72
|
+
cache?: boolean | CacheDirAction & { font?: string | number | boolean; image?: string | number | boolean; };
|
|
73
|
+
/** @deprecated cache.expires */
|
|
71
74
|
cache_expires?: number | string;
|
|
72
75
|
gzip_level?: number;
|
|
73
76
|
brotli_quality?: number;
|
|
@@ -120,9 +123,9 @@ instance.tryImage("/tmp/image.png", "/path/output/compressed.png", options)
|
|
|
120
123
|
|
|
121
124
|
## References
|
|
122
125
|
|
|
123
|
-
- https://www.unpkg.com/@e-mc/types@0.
|
|
124
|
-
- https://www.unpkg.com/@e-mc/types@0.
|
|
125
|
-
- https://www.unpkg.com/@e-mc/types@0.
|
|
126
|
+
- https://www.unpkg.com/@e-mc/types@0.13.1/lib/squared.d.ts
|
|
127
|
+
- https://www.unpkg.com/@e-mc/types@0.13.1/lib/compress.d.ts
|
|
128
|
+
- https://www.unpkg.com/@e-mc/types@0.13.1/lib/settings.d.ts
|
|
126
129
|
|
|
127
130
|
* https://www.npmjs.com/package/@types/node
|
|
128
131
|
|
package/index.js
CHANGED
|
@@ -12,13 +12,15 @@ function createWorker(filename) {
|
|
|
12
12
|
return core_1.WorkerChannel.create(path.join(__dirname, 'worker', filename), 'EMC_COMPRESS');
|
|
13
13
|
}
|
|
14
14
|
const SUPPORTED_NODE21 = (0, types_1.supported)(21);
|
|
15
|
-
const CACHE_IMAGE =
|
|
15
|
+
const CACHE_IMAGE = Object.create(null);
|
|
16
16
|
const CACHE_FONT = Object.create(null);
|
|
17
|
-
const CACHE_FONTFROM =
|
|
18
|
-
const CACHE_FONTTO =
|
|
19
|
-
const
|
|
17
|
+
const CACHE_FONTFROM = Object.create(null);
|
|
18
|
+
const CACHE_FONTTO = Object.create(null);
|
|
19
|
+
const CACHE_TEMP = {
|
|
20
|
+
font: undefined,
|
|
21
|
+
image: undefined
|
|
22
|
+
};
|
|
20
23
|
let SINGLETON_INSTANCE;
|
|
21
|
-
let TEMP_DIR = '';
|
|
22
24
|
const WORKER = new core_1.WorkerGroup(parseInt(process.env.EMC_COMPRESS_WORKER_GROUP_MAX || '0'));
|
|
23
25
|
WORKER
|
|
24
26
|
.add('otf', createWorker('sfnt2woff.js'))
|
|
@@ -28,61 +30,6 @@ WORKER
|
|
|
28
30
|
.add('image', createWorker('plugin-image.js'))
|
|
29
31
|
.add('gz', createWorker('system-gzip.js'))
|
|
30
32
|
.add('br', createWorker('system-brotli.js'));
|
|
31
|
-
function setCacheData(instance, index) {
|
|
32
|
-
if (CACHE_INIT[index]) {
|
|
33
|
-
return true;
|
|
34
|
-
}
|
|
35
|
-
TEMP_DIR ||= instance.getTempDir({ moduleDir: true, createDir: true, increment: 5 });
|
|
36
|
-
const settings = instance.settings;
|
|
37
|
-
const expires = (0, types_1.parseExpires)(settings.cache_expires || 0);
|
|
38
|
-
if (TEMP_DIR) {
|
|
39
|
-
if (expires === 0) {
|
|
40
|
-
if (CACHE_INIT.every(value => !value)) {
|
|
41
|
-
core_1.Module.removeDir(TEMP_DIR, true);
|
|
42
|
-
}
|
|
43
|
-
settings.cache_expires = 0;
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
const current = Date.now();
|
|
47
|
-
(function recurse(paths) {
|
|
48
|
-
const srcDir = path.join(TEMP_DIR, ...paths);
|
|
49
|
-
try {
|
|
50
|
-
fs.readdirSync(srcDir, { withFileTypes: true }).forEach(item => {
|
|
51
|
-
const filename = item.name;
|
|
52
|
-
if (item.isFile()) {
|
|
53
|
-
const pathname = path.join(srcDir, filename);
|
|
54
|
-
if (paths.length === 2) {
|
|
55
|
-
try {
|
|
56
|
-
const stat = fs.lstatSync(pathname);
|
|
57
|
-
if (stat.atimeMs + expires > current) {
|
|
58
|
-
if (index === 0) {
|
|
59
|
-
CACHE_FONT[paths.concat(filename).join('_')] = [pathname, stat.ctime];
|
|
60
|
-
CACHE_FONTFROM[filename] = paths[0];
|
|
61
|
-
CACHE_FONTTO[filename] = paths[1];
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
((CACHE_IMAGE[paths[0]] ||= {})[paths[1]] ||= {})[filename] = stat.ctime;
|
|
65
|
-
}
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
catch {
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
fs.unlink(pathname, () => { });
|
|
73
|
-
}
|
|
74
|
-
else if (item.isDirectory()) {
|
|
75
|
-
recurse(paths.concat(filename));
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
catch {
|
|
80
|
-
}
|
|
81
|
-
})([]);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return CACHE_INIT[index] = true;
|
|
85
|
-
}
|
|
86
33
|
function getOutputSize(startLength, data, worker) {
|
|
87
34
|
if (startLength === 0 || !data) {
|
|
88
35
|
return worker ? ' (worker)' : '';
|
|
@@ -90,9 +37,28 @@ function getOutputSize(startLength, data, worker) {
|
|
|
90
37
|
const offset = Buffer.byteLength(data) - startLength;
|
|
91
38
|
return ` (${(worker ? 'worker: ' : '') + (offset > 0 ? '+' : '') + (0, types_1.formatSize)(offset)})`;
|
|
92
39
|
}
|
|
40
|
+
function applyBrotliMode(params, value) {
|
|
41
|
+
if (value) {
|
|
42
|
+
if (/\b(?:text\/|javascript|css|json5?|(?:ht|x|ya|to)ml)\b/.test(value)) {
|
|
43
|
+
params[zlib.constants.BROTLI_PARAM_MODE] = zlib.constants.BROTLI_MODE_TEXT;
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (value.includes('font/')) {
|
|
47
|
+
params[zlib.constants.BROTLI_PARAM_MODE] = zlib.constants.BROTLI_MODE_FONT;
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
params[zlib.constants.BROTLI_PARAM_MODE] ??= zlib.constants.BROTLI_MODE_GENERIC;
|
|
52
|
+
}
|
|
53
|
+
function applyZlibOptions(base, options, ...params) {
|
|
54
|
+
for (const attr of ['flush', 'finishFlush', 'maxOutputLength', 'info'].concat(params)) {
|
|
55
|
+
if (attr in options) {
|
|
56
|
+
base[attr] = options[attr];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
93
60
|
const sanitizePath = (value) => value.replace(/[\\/]/g, '_');
|
|
94
61
|
const getWorkerTimeout = (options, value) => core_1.WorkerGroup.checkTimeout(typeof options.worker === 'number' && options.worker > 0 ? options.worker : value, true);
|
|
95
|
-
const applyBrotliMode = (params, value) => params[zlib.constants.BROTLI_PARAM_MODE] = value.includes('text/') ? zlib.constants.BROTLI_MODE_TEXT : value.includes('font/') ? zlib.constants.BROTLI_MODE_FONT : zlib.constants.BROTLI_MODE_GENERIC;
|
|
96
62
|
class Compress extends core_1.Module {
|
|
97
63
|
module;
|
|
98
64
|
static [kCompress] = true;
|
|
@@ -171,7 +137,7 @@ class Compress extends core_1.Module {
|
|
|
171
137
|
throw (0, types_1.errorValue)("Operation not permitted", file.toString());
|
|
172
138
|
}
|
|
173
139
|
catch (err) {
|
|
174
|
-
if (!options || options.throwsPermission &&
|
|
140
|
+
if (!options || options.throwsPermission && (0, types_1.isErrorCode)(err, 'EACCES') || options.throwsDoesNotExist && (0, types_1.isErrorCode)(err, 'ENOENT')) {
|
|
175
141
|
throw err;
|
|
176
142
|
}
|
|
177
143
|
}
|
|
@@ -198,8 +164,7 @@ class Compress extends core_1.Module {
|
|
|
198
164
|
}
|
|
199
165
|
level = undefined;
|
|
200
166
|
}
|
|
201
|
-
|
|
202
|
-
gzip = (0, types_1.isPlainObject)(gzip) ? { ...gzip } : {};
|
|
167
|
+
const gzip = { ...this.module.gzip };
|
|
203
168
|
if (typeof level === 'number') {
|
|
204
169
|
gzip.level = level;
|
|
205
170
|
}
|
|
@@ -212,18 +177,22 @@ class Compress extends core_1.Module {
|
|
|
212
177
|
else {
|
|
213
178
|
gzip.chunkSize ??= this.chunkSize;
|
|
214
179
|
}
|
|
180
|
+
if (options) {
|
|
181
|
+
applyZlibOptions(gzip, options, 'memLevel', 'strategy', 'windowBits');
|
|
182
|
+
}
|
|
215
183
|
return this.getReadable(file, options).pipe(zlib.createGzip(gzip));
|
|
216
184
|
}
|
|
217
185
|
createBrotliCompress(file, options) {
|
|
218
|
-
let level, chunkSize, mimeType;
|
|
186
|
+
let level, chunkSize, params, mimeType;
|
|
219
187
|
if (options) {
|
|
220
|
-
({ level, chunkSize, mimeType } = options);
|
|
188
|
+
({ level, chunkSize, params, mimeType } = options);
|
|
221
189
|
}
|
|
222
|
-
|
|
190
|
+
params ||= {};
|
|
191
|
+
let brotli = this.module.brotli;
|
|
223
192
|
if ((0, types_1.isPlainObject)(brotli)) {
|
|
224
193
|
if ((0, types_1.isPlainObject)(brotli.params)) {
|
|
225
194
|
brotli = (0, types_1.cloneObject)(brotli, true);
|
|
226
|
-
params = brotli.params;
|
|
195
|
+
params = Object.assign(brotli.params, params);
|
|
227
196
|
}
|
|
228
197
|
else {
|
|
229
198
|
brotli = { ...brotli, params };
|
|
@@ -232,23 +201,26 @@ class Compress extends core_1.Module {
|
|
|
232
201
|
else {
|
|
233
202
|
brotli = { params };
|
|
234
203
|
}
|
|
235
|
-
applyBrotliMode(params, mimeType
|
|
204
|
+
applyBrotliMode(params, mimeType);
|
|
236
205
|
try {
|
|
237
206
|
params[zlib.constants.BROTLI_PARAM_SIZE_HINT] = typeof file === 'string' ? fs.statSync(file).size : Buffer.byteLength(file);
|
|
238
207
|
}
|
|
239
208
|
catch {
|
|
240
209
|
}
|
|
210
|
+
if (typeof level === 'number') {
|
|
211
|
+
brotli.params[zlib.constants.BROTLI_PARAM_QUALITY] = level;
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
brotli.params[zlib.constants.BROTLI_PARAM_QUALITY] ??= this.level.br;
|
|
215
|
+
}
|
|
241
216
|
if (!isNaN(chunkSize = (0, types_1.alignSize)(chunkSize, 1))) {
|
|
242
217
|
brotli.chunkSize = chunkSize;
|
|
243
218
|
}
|
|
244
219
|
else {
|
|
245
220
|
brotli.chunkSize ??= this.chunkSize;
|
|
246
221
|
}
|
|
247
|
-
if (
|
|
248
|
-
|
|
249
|
-
}
|
|
250
|
-
else {
|
|
251
|
-
params[zlib.constants.BROTLI_PARAM_QUALITY] ??= this.level.br;
|
|
222
|
+
if (options) {
|
|
223
|
+
applyZlibOptions(brotli, options);
|
|
252
224
|
}
|
|
253
225
|
return this.getReadable(file, options).pipe(zlib.createBrotliCompress(brotli));
|
|
254
226
|
}
|
|
@@ -295,10 +267,9 @@ class Compress extends core_1.Module {
|
|
|
295
267
|
if (!(0, types_1.isString)(format)) {
|
|
296
268
|
return Promise.reject((0, types_1.errorValue)("Missing option \"format\"", output || filename));
|
|
297
269
|
}
|
|
298
|
-
const cache = this.settings.cache ? !!(hash && (hash = core_1.Module.asHash(hash)) || Buffer.isBuffer(file) && (hash = core_1.Module.asHash(file))) : false;
|
|
299
270
|
format = format.toLowerCase();
|
|
300
271
|
return new Promise((resolve, reject) => {
|
|
301
|
-
let timer = null, worker = null, startLength = 0, closed = false;
|
|
272
|
+
let timer = null, worker = null, tempDir = null, startLength = 0, closed = false;
|
|
302
273
|
const endProcess = (err, data = null, ext, result, fromCache) => {
|
|
303
274
|
if (closed) {
|
|
304
275
|
return;
|
|
@@ -311,6 +282,19 @@ class Compress extends core_1.Module {
|
|
|
311
282
|
reject(err);
|
|
312
283
|
return;
|
|
313
284
|
}
|
|
285
|
+
if (typeof ext === 'boolean') {
|
|
286
|
+
fromCache = ext;
|
|
287
|
+
ext = null;
|
|
288
|
+
result = null;
|
|
289
|
+
}
|
|
290
|
+
else if (typeof result === 'boolean') {
|
|
291
|
+
fromCache = result;
|
|
292
|
+
result = null;
|
|
293
|
+
}
|
|
294
|
+
if ((0, types_1.isString)(data)) {
|
|
295
|
+
result = data;
|
|
296
|
+
data = null;
|
|
297
|
+
}
|
|
314
298
|
if (!fromCache) {
|
|
315
299
|
const status = (0, types_1.isString)(result) ? path.basename(result) : filename || "Completed";
|
|
316
300
|
this.writeTimeProcess(ext || format, status + getOutputSize(startLength, data, !!worker), startTime, { type: 8, sessionId: options.sessionId, broadcastId: options.broadcastId });
|
|
@@ -353,10 +337,10 @@ class Compress extends core_1.Module {
|
|
|
353
337
|
else {
|
|
354
338
|
endProcess(null, data, ext);
|
|
355
339
|
}
|
|
356
|
-
if (
|
|
340
|
+
if (tempDir) {
|
|
357
341
|
const pathname = path.join(from, ext);
|
|
358
342
|
let tempFont;
|
|
359
|
-
if (
|
|
343
|
+
if (core_1.Module.createDir(tempFont = path.join(tempDir, pathname))) {
|
|
360
344
|
tempFont = path.join(tempFont, hash);
|
|
361
345
|
}
|
|
362
346
|
else {
|
|
@@ -371,8 +355,23 @@ class Compress extends core_1.Module {
|
|
|
371
355
|
}
|
|
372
356
|
};
|
|
373
357
|
const hasFont = () => {
|
|
374
|
-
|
|
375
|
-
if (
|
|
358
|
+
tempDir = this.#getCacheDir('font');
|
|
359
|
+
if (!tempDir) {
|
|
360
|
+
hash = undefined;
|
|
361
|
+
return false;
|
|
362
|
+
}
|
|
363
|
+
if (hash) {
|
|
364
|
+
hash = core_1.Module.asHash(hash);
|
|
365
|
+
}
|
|
366
|
+
else if (Buffer.isBuffer(file)) {
|
|
367
|
+
hash = core_1.Module.asHash(file);
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
const from = CACHE_FONTFROM[hash];
|
|
373
|
+
const to = CACHE_FONTTO[hash];
|
|
374
|
+
if (from && to) {
|
|
376
375
|
const cacheKey = from + `_${to}_` + hash;
|
|
377
376
|
const tempFont = CACHE_FONT[cacheKey];
|
|
378
377
|
if (tempFont) {
|
|
@@ -385,7 +384,7 @@ class Compress extends core_1.Module {
|
|
|
385
384
|
endProcess(null, data, to, pathname, true);
|
|
386
385
|
}
|
|
387
386
|
else {
|
|
388
|
-
endProcess(null, data, to,
|
|
387
|
+
endProcess(null, data, to, true);
|
|
389
388
|
}
|
|
390
389
|
this.formatMessage(8, from, [pathname ? path.basename(pathname) : "Completed" + ` -> font/${to}`, 'cache'], tempFont[1].toLocaleString(), { ...core_1.Module.LOG_STYLE_NOTICE, hintBold: true, sessionId: options.sessionId, broadcastId: options.broadcastId });
|
|
391
390
|
return true;
|
|
@@ -424,13 +423,10 @@ class Compress extends core_1.Module {
|
|
|
424
423
|
}
|
|
425
424
|
else {
|
|
426
425
|
workerOptions.params = { [zlib.constants.BROTLI_PARAM_QUALITY]: options.level ?? this.level.br };
|
|
427
|
-
applyBrotliMode(workerOptions.params, options.mimeType
|
|
426
|
+
applyBrotliMode(workerOptions.params, options.mimeType);
|
|
428
427
|
}
|
|
429
428
|
const endWorker = (result) => {
|
|
430
|
-
if (
|
|
431
|
-
endProcess(null, null, format, result);
|
|
432
|
-
}
|
|
433
|
-
else if (result) {
|
|
429
|
+
if (result) {
|
|
434
430
|
endProcess(null, result, format);
|
|
435
431
|
}
|
|
436
432
|
else {
|
|
@@ -456,7 +452,7 @@ class Compress extends core_1.Module {
|
|
|
456
452
|
}
|
|
457
453
|
transform
|
|
458
454
|
.on('finish', () => {
|
|
459
|
-
endProcess(null, chunks
|
|
455
|
+
endProcess(null, chunks ? Buffer.concat(chunks) : output, format);
|
|
460
456
|
})
|
|
461
457
|
.on('error', (err) => {
|
|
462
458
|
transform.destroy();
|
|
@@ -491,7 +487,7 @@ class Compress extends core_1.Module {
|
|
|
491
487
|
.then(font => {
|
|
492
488
|
switch (font?.mime) {
|
|
493
489
|
case "font/woff":
|
|
494
|
-
if (
|
|
490
|
+
if (hash) {
|
|
495
491
|
CACHE_FONTFROM[hash] = 'woff';
|
|
496
492
|
}
|
|
497
493
|
if (this.hasPermission('worker', options) && (worker = WORKER.get('woff').sendBuffer(data, true, checkResult, 'woff'))) {
|
|
@@ -503,7 +499,7 @@ class Compress extends core_1.Module {
|
|
|
503
499
|
}
|
|
504
500
|
break;
|
|
505
501
|
case "font/woff2":
|
|
506
|
-
if (
|
|
502
|
+
if (hash) {
|
|
507
503
|
CACHE_FONTFROM[hash] = 'woff2';
|
|
508
504
|
}
|
|
509
505
|
if (this.hasPermission('worker', options) && (worker = WORKER.get('woff2').sendBuffer(data, shared, checkResult, 'woff2'))) {
|
|
@@ -511,9 +507,7 @@ class Compress extends core_1.Module {
|
|
|
511
507
|
}
|
|
512
508
|
else {
|
|
513
509
|
startProcess(false);
|
|
514
|
-
void wawoff2.decompress(data).then(woff =>
|
|
515
|
-
checkResult(woff, 'woff2');
|
|
516
|
-
});
|
|
510
|
+
void wawoff2.decompress(data).then(woff => checkResult(woff, 'woff2'));
|
|
517
511
|
}
|
|
518
512
|
break;
|
|
519
513
|
default:
|
|
@@ -549,7 +543,7 @@ class Compress extends core_1.Module {
|
|
|
549
543
|
.then(font => {
|
|
550
544
|
switch (font?.mime) {
|
|
551
545
|
case "font/ttf":
|
|
552
|
-
if (
|
|
546
|
+
if (hash) {
|
|
553
547
|
CACHE_FONTFROM[hash] = 'ttf';
|
|
554
548
|
}
|
|
555
549
|
if (this.hasPermission('worker', options) && (worker = WORKER.get('ttf').sendBuffer(data, shared, checkResult, 'ttf', "font/woff2"))) {
|
|
@@ -557,13 +551,11 @@ class Compress extends core_1.Module {
|
|
|
557
551
|
}
|
|
558
552
|
else {
|
|
559
553
|
startProcess(false);
|
|
560
|
-
void wawoff2.compress(data).then(result =>
|
|
561
|
-
checkResult(result, 'ttf', "font/woff2");
|
|
562
|
-
});
|
|
554
|
+
void wawoff2.compress(data).then(result => checkResult(result, 'ttf', "font/woff2"));
|
|
563
555
|
}
|
|
564
556
|
break;
|
|
565
557
|
case "font/otf":
|
|
566
|
-
if (
|
|
558
|
+
if (hash) {
|
|
567
559
|
CACHE_FONTFROM[hash] = 'otf';
|
|
568
560
|
}
|
|
569
561
|
if (this.hasPermission('worker', options) && (worker = WORKER.get('otf').sendBuffer(data, shared, checkResult, 'otf', "font/woff"))) {
|
|
@@ -591,12 +583,7 @@ class Compress extends core_1.Module {
|
|
|
591
583
|
if (compressor.toString().startsWith('async')) {
|
|
592
584
|
compressor.call(this, data, output, options)
|
|
593
585
|
.then(result => {
|
|
594
|
-
|
|
595
|
-
endProcess(null, null, format, result);
|
|
596
|
-
}
|
|
597
|
-
else {
|
|
598
|
-
endProcess(null, result, format);
|
|
599
|
-
}
|
|
586
|
+
endProcess(null, result, format);
|
|
600
587
|
})
|
|
601
588
|
.catch(endProcess);
|
|
602
589
|
}
|
|
@@ -662,7 +649,7 @@ class Compress extends core_1.Module {
|
|
|
662
649
|
}
|
|
663
650
|
const startLength = Buffer.byteLength(data);
|
|
664
651
|
return new Promise(async (resolve, reject) => {
|
|
665
|
-
let timer = null, hash, cacheKey, closed = false;
|
|
652
|
+
let timer = null, tempDir = null, hash, cacheKey, closed = false;
|
|
666
653
|
const failed = (err) => {
|
|
667
654
|
if (timer) {
|
|
668
655
|
clearTimeout(timer);
|
|
@@ -683,8 +670,8 @@ class Compress extends core_1.Module {
|
|
|
683
670
|
else {
|
|
684
671
|
this.writeTimeProcess(ext, status + getOutputSize(startLength, result, worker), startTime, { type: 8, sessionId: options.sessionId, broadcastId: options.broadcastId });
|
|
685
672
|
}
|
|
686
|
-
if (!ctime && hash
|
|
687
|
-
const pathname = path.join(
|
|
673
|
+
if (!ctime && hash) {
|
|
674
|
+
const pathname = path.join(tempDir, sanitizePath(plugin), hash);
|
|
688
675
|
if (core_1.Module.createDir(pathname)) {
|
|
689
676
|
fs.writeFile(path.join(pathname, cacheKey), result, error => {
|
|
690
677
|
if (!error) {
|
|
@@ -711,7 +698,7 @@ class Compress extends core_1.Module {
|
|
|
711
698
|
complete(null, result, worker, ctime);
|
|
712
699
|
}
|
|
713
700
|
};
|
|
714
|
-
if (
|
|
701
|
+
if (tempDir = this.#getCacheDir('image')) {
|
|
715
702
|
let stored;
|
|
716
703
|
try {
|
|
717
704
|
hash = core_1.Module.asHash(data);
|
|
@@ -719,7 +706,7 @@ class Compress extends core_1.Module {
|
|
|
719
706
|
cacheKey = plugin + (options.options ? ':' + core_1.Module.asHash(core_1.Module.asString(options.options)) : '') + (options.metadata ? ':' + core_1.Module.asHash(core_1.Module.asString(options.metadata)) : '');
|
|
720
707
|
const ctime = stored?.[cacheKey];
|
|
721
708
|
if (ctime) {
|
|
722
|
-
success(fs.readFileSync(path.join(
|
|
709
|
+
success(fs.readFileSync(path.join(tempDir, sanitizePath(plugin), hash, cacheKey)), false, ctime);
|
|
723
710
|
return;
|
|
724
711
|
}
|
|
725
712
|
}
|
|
@@ -786,6 +773,75 @@ class Compress extends core_1.Module {
|
|
|
786
773
|
}
|
|
787
774
|
return false;
|
|
788
775
|
}
|
|
776
|
+
#getCacheDir(type) {
|
|
777
|
+
let tempDir = CACHE_TEMP[type];
|
|
778
|
+
if (tempDir !== undefined) {
|
|
779
|
+
return tempDir;
|
|
780
|
+
}
|
|
781
|
+
const { cache, cache_expires = 0 } = this.settings;
|
|
782
|
+
let expires;
|
|
783
|
+
if ((0, types_1.isPlainObject)(cache)) {
|
|
784
|
+
const value = cache[type];
|
|
785
|
+
if (!cache.enabled || value === false) {
|
|
786
|
+
return CACHE_TEMP[type] = null;
|
|
787
|
+
}
|
|
788
|
+
expires = value !== undefined ? value === true ? 0 : value : cache.expires;
|
|
789
|
+
if (cache.dir && core_1.Module.createDir(tempDir = path.resolve(cache.dir, this.moduleName, type))) {
|
|
790
|
+
this.addLog(5, 'Cache directory: ' + tempDir);
|
|
791
|
+
}
|
|
792
|
+
else {
|
|
793
|
+
tempDir = undefined;
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
else if (cache !== true) {
|
|
797
|
+
return CACHE_TEMP[type] = null;
|
|
798
|
+
}
|
|
799
|
+
expires = (0, types_1.parseExpires)(expires ?? cache_expires);
|
|
800
|
+
tempDir ||= this.getTempDir({ pathname: type, moduleDir: true, createDir: true }) || (0, types_1.getTempDir)(true, this.moduleName, type);
|
|
801
|
+
CACHE_TEMP[type] = tempDir;
|
|
802
|
+
if (expires === 0) {
|
|
803
|
+
core_1.Module.removeDir(tempDir, true);
|
|
804
|
+
}
|
|
805
|
+
else {
|
|
806
|
+
const current = Date.now();
|
|
807
|
+
(function recurse(paths) {
|
|
808
|
+
try {
|
|
809
|
+
const srcDir = path.join(tempDir, ...paths);
|
|
810
|
+
fs.readdirSync(srcDir, { withFileTypes: true }).forEach(item => {
|
|
811
|
+
const filename = item.name;
|
|
812
|
+
if (item.isFile()) {
|
|
813
|
+
const target = path.join(srcDir, filename);
|
|
814
|
+
if (paths.length === 2) {
|
|
815
|
+
try {
|
|
816
|
+
const stat = fs.lstatSync(target);
|
|
817
|
+
if (stat.atimeMs + expires > current) {
|
|
818
|
+
if (type === 'font') {
|
|
819
|
+
CACHE_FONT[paths.concat(filename).join('_')] = [target, stat.ctime];
|
|
820
|
+
CACHE_FONTFROM[filename] = paths[0];
|
|
821
|
+
CACHE_FONTTO[filename] = paths[1];
|
|
822
|
+
}
|
|
823
|
+
else {
|
|
824
|
+
((CACHE_IMAGE[paths[0]] ||= {})[paths[1]] ||= {})[filename] = stat.ctime;
|
|
825
|
+
}
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
catch {
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
fs.unlink(target, () => { });
|
|
833
|
+
}
|
|
834
|
+
else if (item.isDirectory()) {
|
|
835
|
+
recurse(paths.concat(filename));
|
|
836
|
+
}
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
catch {
|
|
840
|
+
}
|
|
841
|
+
})([]);
|
|
842
|
+
}
|
|
843
|
+
return tempDir;
|
|
844
|
+
}
|
|
789
845
|
set chunkSize(value) {
|
|
790
846
|
this.#chunkSize = !isNaN(value = (0, types_1.alignSize)(value, 1)) ? value : undefined;
|
|
791
847
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e-mc/compress",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.1",
|
|
4
4
|
"description": "Compress constructor for E-mc.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"license": "BSD-3-Clause",
|
|
23
23
|
"homepage": "https://github.com/anpham6/e-mc#readme",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@e-mc/core": "0.
|
|
26
|
-
"@e-mc/types": "0.
|
|
25
|
+
"@e-mc/core": "0.13.1",
|
|
26
|
+
"@e-mc/types": "0.13.1",
|
|
27
27
|
"wawoff2": "^2.0.1",
|
|
28
28
|
"woff2sfnt-sfnt2woff": "^1.0.0"
|
|
29
29
|
}
|
package/worker/plugin-image.js
CHANGED
|
@@ -13,7 +13,7 @@ node_worker_threads_1.parentPort.on('message', async (value) => {
|
|
|
13
13
|
catch {
|
|
14
14
|
transform = require(plugin);
|
|
15
15
|
}
|
|
16
|
-
transform(options, metadata)(index_1.asBuffer(data))
|
|
16
|
+
void transform(options, metadata)(index_1.asBuffer(data))
|
|
17
17
|
.then(result => {
|
|
18
18
|
try {
|
|
19
19
|
PORT.postMessage(result, [result.buffer]);
|
|
@@ -21,10 +21,6 @@ node_worker_threads_1.parentPort.on('message', async (value) => {
|
|
|
21
21
|
catch {
|
|
22
22
|
PORT.postMessage(result);
|
|
23
23
|
}
|
|
24
|
-
})
|
|
25
|
-
.catch((err) => {
|
|
26
|
-
console.error(err);
|
|
27
|
-
PORT.postMessage(null);
|
|
28
24
|
});
|
|
29
25
|
}
|
|
30
26
|
catch (err) {
|