@e-mc/compress 0.13.10 → 0.14.0
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 +4 -10
- package/index.js +160 -120
- package/package.json +3 -3
- package/worker/plugin-image.js +8 -7
- package/worker/sfnt2woff.js +4 -3
- package/worker/system-brotli.js +9 -8
- package/worker/system-gzip.js +9 -8
- package/worker/system-zstd.js +41 -0
- package/worker/wawoff2-compress.js +6 -5
- package/worker/wawoff2-decompress.js +6 -5
- package/worker/woff2sfnt.js +4 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @e-mc/compress
|
|
2
2
|
|
|
3
|
-
* NodeJS
|
|
3
|
+
* NodeJS 20 (Minimum 18)
|
|
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.14.0/lib/index.d.ts)
|
|
13
13
|
|
|
14
14
|
```typescript
|
|
15
15
|
import type { IModule, ModuleConstructor } from "./index";
|
|
@@ -61,13 +61,10 @@ interface CompressConstructor extends ModuleConstructor {
|
|
|
61
61
|
import type { CacheDirAction } from "./settings";
|
|
62
62
|
|
|
63
63
|
import type { BrotliOptions, ZlibOptions } from "node:zlib";
|
|
64
|
-
import type { Options as ZopfliOptions } from "node-zopfli";
|
|
65
64
|
|
|
66
65
|
interface CompressModule {
|
|
67
66
|
gzip?: ZlibOptions;
|
|
68
67
|
brotli?: BrotliOptions;
|
|
69
|
-
/** @deprecated */
|
|
70
|
-
zopfli?: ZopfliOptions;
|
|
71
68
|
settings?: {
|
|
72
69
|
broadcast_id?: string | string[];
|
|
73
70
|
cache?: boolean | CacheDirAction & { font?: string | number | boolean; image?: string | number | boolean; };
|
|
@@ -75,8 +72,6 @@ interface CompressModule {
|
|
|
75
72
|
cache_expires?: number | string;
|
|
76
73
|
gzip_level?: number;
|
|
77
74
|
brotli_quality?: number;
|
|
78
|
-
/** @deprecated */
|
|
79
|
-
zopfli_iterations?: number;
|
|
80
75
|
chunk_size?: number | string;
|
|
81
76
|
};
|
|
82
77
|
}
|
|
@@ -125,11 +120,10 @@ instance.tryImage("/tmp/image.png", "/path/output/compressed.png", options)
|
|
|
125
120
|
|
|
126
121
|
## References
|
|
127
122
|
|
|
128
|
-
- https://www.unpkg.com/@e-mc/types@0.
|
|
129
|
-
- https://www.unpkg.com/@e-mc/types@0.
|
|
123
|
+
- https://www.unpkg.com/@e-mc/types@0.14.0/lib/compress.d.ts
|
|
124
|
+
- https://www.unpkg.com/@e-mc/types@0.14.0/lib/settings.d.ts
|
|
130
125
|
|
|
131
126
|
* https://www.npmjs.com/package/@types/node
|
|
132
|
-
* https://www.npmjs.com/package/@types/node-zopfli
|
|
133
127
|
|
|
134
128
|
## LICENSE
|
|
135
129
|
|
package/index.js
CHANGED
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const stream = require('node:stream');
|
|
6
|
+
const zlib = require('node:zlib');
|
|
7
|
+
const { compress, decompress } = require('wawoff2');
|
|
8
|
+
const { IMPORT_MAP, alignSize, asExt, cloneObject, errorMessage, errorValue, formatSize, getTempDir, importESM, isErrorCode, isObject, isPlainObject, isString, parseExpires, renameExt, supported } = require('@e-mc/types');
|
|
9
|
+
const { Module, WorkerChannel, WorkerGroup } = require('@e-mc/core');
|
|
9
10
|
const { toSfnt, toWoff } = require('woff2sfnt-sfnt2woff');
|
|
10
11
|
const kCompress = Symbol.for('compress:constructor');
|
|
11
12
|
function createWorker(filename) {
|
|
12
|
-
return
|
|
13
|
+
return WorkerChannel.create(path.join(__dirname, 'worker', filename), 'EMC_COMPRESS');
|
|
13
14
|
}
|
|
14
|
-
const SUPPORTED_NODE21 =
|
|
15
|
+
const SUPPORTED_NODE21 = supported(21);
|
|
16
|
+
const SUPPORTED_ZSTD = supported(23, 8) || supported(22, 15, true);
|
|
15
17
|
const CACHE_IMAGE = Object.create(null);
|
|
16
18
|
const CACHE_FONT = new Map();
|
|
17
19
|
const CACHE_FONTFROM = Object.create(null);
|
|
18
20
|
const CACHE_FONTTO = Object.create(null);
|
|
19
21
|
const CACHE_TEMP = { font: undefined, image: undefined };
|
|
20
22
|
let SINGLETON_INSTANCE;
|
|
21
|
-
const WORKER = new
|
|
23
|
+
const WORKER = new WorkerGroup(parseInt(process.env.EMC_COMPRESS_WORKER_GROUP_MAX || '0'));
|
|
22
24
|
WORKER
|
|
23
25
|
.add('otf', createWorker('sfnt2woff.js'))
|
|
24
26
|
.add('woff', createWorker('woff2sfnt.js'))
|
|
@@ -26,13 +28,25 @@ WORKER
|
|
|
26
28
|
.add('ttf', createWorker('wawoff2-compress.js'))
|
|
27
29
|
.add('image', createWorker('plugin-image.js'))
|
|
28
30
|
.add('gz', createWorker('system-gzip.js'))
|
|
29
|
-
.add('br', createWorker('system-brotli.js'))
|
|
31
|
+
.add('br', createWorker('system-brotli.js'))
|
|
32
|
+
.add('zst', createWorker('system-zstd.js'));
|
|
30
33
|
function getOutputSize(startLength, data, worker) {
|
|
31
34
|
if (startLength === 0 || !data) {
|
|
32
35
|
return worker ? ' (worker)' : '';
|
|
33
36
|
}
|
|
34
37
|
const offset = Buffer.byteLength(data) - startLength;
|
|
35
|
-
return ` (${(worker ? 'worker: ' : '') + (offset > 0 ? '+' : '') +
|
|
38
|
+
return ` (${(worker ? 'worker: ' : '') + (offset > 0 ? '+' : '') + formatSize(offset)})`;
|
|
39
|
+
}
|
|
40
|
+
function applySettings(options, params) {
|
|
41
|
+
if (isPlainObject(options)) {
|
|
42
|
+
if (isPlainObject(options.params)) {
|
|
43
|
+
options = cloneObject(options, true);
|
|
44
|
+
Object.assign(options.params, params);
|
|
45
|
+
return options;
|
|
46
|
+
}
|
|
47
|
+
return { ...options, params };
|
|
48
|
+
}
|
|
49
|
+
return { params };
|
|
36
50
|
}
|
|
37
51
|
function applyBrotliMode(params, value) {
|
|
38
52
|
if (value) {
|
|
@@ -55,8 +69,8 @@ function applyZlibOptions(base, options, ...params) {
|
|
|
55
69
|
}
|
|
56
70
|
}
|
|
57
71
|
const sanitizePath = (value) => value.replace(/[\\/]/g, '_');
|
|
58
|
-
const getWorkerTimeout = (options, value) =>
|
|
59
|
-
class Compress extends
|
|
72
|
+
const getWorkerTimeout = (options, value) => WorkerGroup.checkTimeout(typeof options.worker === 'number' && options.worker > 0 ? options.worker : value, true);
|
|
73
|
+
class Compress extends Module {
|
|
60
74
|
module;
|
|
61
75
|
static [kCompress] = true;
|
|
62
76
|
static singleton() {
|
|
@@ -64,9 +78,12 @@ class Compress extends core_1.Module {
|
|
|
64
78
|
SINGLETON_INSTANCE = new Compress();
|
|
65
79
|
Object.defineProperty(SINGLETON_INSTANCE, "_logEnabled", { value: false, enumerable: true, writable: false });
|
|
66
80
|
Object.defineProperty(SINGLETON_INSTANCE, "_logFlushed", { value: true, enumerable: true, writable: false });
|
|
67
|
-
Object.defineProperty(SINGLETON_INSTANCE, "host", {
|
|
81
|
+
Object.defineProperty(SINGLETON_INSTANCE, "host", {
|
|
82
|
+
set(value) { },
|
|
83
|
+
get() {
|
|
68
84
|
return null;
|
|
69
|
-
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
70
87
|
}
|
|
71
88
|
return SINGLETON_INSTANCE;
|
|
72
89
|
}
|
|
@@ -76,7 +93,7 @@ class Compress extends core_1.Module {
|
|
|
76
93
|
level = {
|
|
77
94
|
gz: 9,
|
|
78
95
|
br: 11,
|
|
79
|
-
|
|
96
|
+
zst: 3
|
|
80
97
|
};
|
|
81
98
|
compressors = {};
|
|
82
99
|
_moduleName = 'compress';
|
|
@@ -86,15 +103,15 @@ class Compress extends core_1.Module {
|
|
|
86
103
|
this.module = module;
|
|
87
104
|
}
|
|
88
105
|
init(...args) {
|
|
89
|
-
let { gzip_level, brotli_quality,
|
|
106
|
+
let { gzip_level, brotli_quality, zstd_compression_level, chunk_size } = isPlainObject(args[0]) && args[0].settings || this.settings;
|
|
90
107
|
if (gzip_level !== undefined && (gzip_level = Math.floor(+gzip_level)) >= -1 && gzip_level <= 9) {
|
|
91
108
|
this.level.gz = Math.floor(gzip_level);
|
|
92
109
|
}
|
|
93
110
|
if (brotli_quality !== undefined && (brotli_quality = Math.floor(+brotli_quality)) >= 0 && brotli_quality <= 11) {
|
|
94
111
|
this.level.br = brotli_quality;
|
|
95
112
|
}
|
|
96
|
-
if (
|
|
97
|
-
this.level.
|
|
113
|
+
if (zstd_compression_level !== undefined && (zstd_compression_level = Math.floor(+zstd_compression_level)) >= 1 && zstd_compression_level <= 9) {
|
|
114
|
+
this.level.zstd = zstd_compression_level;
|
|
98
115
|
}
|
|
99
116
|
if (chunk_size !== undefined) {
|
|
100
117
|
this.chunkSize = chunk_size;
|
|
@@ -108,7 +125,7 @@ class Compress extends core_1.Module {
|
|
|
108
125
|
}
|
|
109
126
|
}
|
|
110
127
|
getLevel(value, fallback) {
|
|
111
|
-
const result = this.level[value = value.toLowerCase()] ?? this.level[value =
|
|
128
|
+
const result = this.level[value = value.toLowerCase()] ?? this.level[value = asExt(value)];
|
|
112
129
|
if (!isNaN(result)) {
|
|
113
130
|
return result;
|
|
114
131
|
}
|
|
@@ -120,6 +137,8 @@ class Compress extends core_1.Module {
|
|
|
120
137
|
return zlib.constants.Z_DEFAULT_LEVEL;
|
|
121
138
|
case 'br':
|
|
122
139
|
return zlib.constants.BROTLI_DEFAULT_QUALITY;
|
|
140
|
+
case 'zst':
|
|
141
|
+
return zlib.constants.ZSTD_CLEVEL_DEFAULT;
|
|
123
142
|
}
|
|
124
143
|
}
|
|
125
144
|
getReadable(file, options) {
|
|
@@ -131,44 +150,28 @@ class Compress extends core_1.Module {
|
|
|
131
150
|
return fs.createReadStream(file);
|
|
132
151
|
}
|
|
133
152
|
options = undefined;
|
|
134
|
-
throw
|
|
153
|
+
throw errorValue("Operation not permitted", file.toString());
|
|
135
154
|
}
|
|
136
155
|
catch (err) {
|
|
137
|
-
if (!options || options.throwsPermission &&
|
|
156
|
+
if (!options || options.throwsPermission && isErrorCode(err, 'EACCES') || options.throwsDoesNotExist && isErrorCode(err, 'ENOENT')) {
|
|
138
157
|
throw err;
|
|
139
158
|
}
|
|
140
159
|
}
|
|
141
160
|
return stream.Readable.from(Buffer.alloc(0));
|
|
142
161
|
}
|
|
143
162
|
createGzip(file, options) {
|
|
144
|
-
let
|
|
163
|
+
let level, chunkSize;
|
|
145
164
|
if (options) {
|
|
146
|
-
({
|
|
147
|
-
}
|
|
148
|
-
if (algorithm === 'zopfli') {
|
|
149
|
-
try {
|
|
150
|
-
const lib = require('node-zopfli');
|
|
151
|
-
const opts = (0, types_1.isPlainObject)(this.module.zopfli) ? { ...this.module.zopfli } : {};
|
|
152
|
-
if (typeof level === 'number') {
|
|
153
|
-
opts.numiterations = level;
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
opts.numiterations ??= this.level.zopfli;
|
|
157
|
-
}
|
|
158
|
-
return this.getReadable(file, options).pipe(lib.createGzip(opts));
|
|
159
|
-
}
|
|
160
|
-
catch {
|
|
161
|
-
}
|
|
162
|
-
level = undefined;
|
|
165
|
+
({ level, chunkSize } = options);
|
|
163
166
|
}
|
|
164
167
|
const gzip = { ...this.module.gzip };
|
|
165
168
|
if (typeof level === 'number') {
|
|
166
169
|
gzip.level = level;
|
|
167
170
|
}
|
|
168
|
-
else {
|
|
171
|
+
else if (typeof this.level.gz === 'number') {
|
|
169
172
|
gzip.level ??= this.level.gz;
|
|
170
173
|
}
|
|
171
|
-
if (!isNaN(chunkSize =
|
|
174
|
+
if (!isNaN(chunkSize = alignSize(chunkSize, 1))) {
|
|
172
175
|
gzip.chunkSize = chunkSize;
|
|
173
176
|
}
|
|
174
177
|
else {
|
|
@@ -184,20 +187,7 @@ class Compress extends core_1.Module {
|
|
|
184
187
|
if (options) {
|
|
185
188
|
({ level, chunkSize, params, mimeType } = options);
|
|
186
189
|
}
|
|
187
|
-
params ||= {};
|
|
188
|
-
let brotli = this.module.brotli;
|
|
189
|
-
if ((0, types_1.isPlainObject)(brotli)) {
|
|
190
|
-
if ((0, types_1.isPlainObject)(brotli.params)) {
|
|
191
|
-
brotli = (0, types_1.cloneObject)(brotli, true);
|
|
192
|
-
params = Object.assign(brotli.params, params);
|
|
193
|
-
}
|
|
194
|
-
else {
|
|
195
|
-
brotli = { ...brotli, params };
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
brotli = { params };
|
|
200
|
-
}
|
|
190
|
+
const brotli = applySettings(this.module.brotli, params ||= {});
|
|
201
191
|
applyBrotliMode(params, mimeType);
|
|
202
192
|
try {
|
|
203
193
|
params[zlib.constants.BROTLI_PARAM_SIZE_HINT] = typeof file === 'string' ? fs.statSync(file).size : Buffer.byteLength(file);
|
|
@@ -205,12 +195,12 @@ class Compress extends core_1.Module {
|
|
|
205
195
|
catch {
|
|
206
196
|
}
|
|
207
197
|
if (typeof level === 'number') {
|
|
208
|
-
|
|
198
|
+
params[zlib.constants.BROTLI_PARAM_QUALITY] = level;
|
|
209
199
|
}
|
|
210
|
-
else {
|
|
211
|
-
|
|
200
|
+
else if (typeof this.level.br === 'number') {
|
|
201
|
+
params[zlib.constants.BROTLI_PARAM_QUALITY] ??= this.level.br;
|
|
212
202
|
}
|
|
213
|
-
if (!isNaN(chunkSize =
|
|
203
|
+
if (!isNaN(chunkSize = alignSize(chunkSize, 1))) {
|
|
214
204
|
brotli.chunkSize = chunkSize;
|
|
215
205
|
}
|
|
216
206
|
else {
|
|
@@ -248,21 +238,21 @@ class Compress extends core_1.Module {
|
|
|
248
238
|
});
|
|
249
239
|
}
|
|
250
240
|
async tryFile(file, output, options) {
|
|
251
|
-
if (
|
|
241
|
+
if (isObject(output)) {
|
|
252
242
|
options = output;
|
|
253
243
|
output = '';
|
|
254
244
|
}
|
|
255
|
-
if (!
|
|
245
|
+
if (!isString(output)) {
|
|
256
246
|
output = typeof file === 'string' ? file : '';
|
|
257
247
|
}
|
|
258
248
|
if (output && !this.canWrite(output, { ownPermissionOnly: true })) {
|
|
259
|
-
return Promise.reject(
|
|
249
|
+
return Promise.reject(errorValue("Operation not permitted", output));
|
|
260
250
|
}
|
|
261
251
|
options ||= {};
|
|
262
252
|
const { filename, startTime = process.hrtime.bigint(), timeout = 0 } = options;
|
|
263
253
|
let format = options.format, hash = options.etag;
|
|
264
|
-
if (!
|
|
265
|
-
return Promise.reject(
|
|
254
|
+
if (!isString(format)) {
|
|
255
|
+
return Promise.reject(errorValue("Missing option \"format\"", output || filename));
|
|
266
256
|
}
|
|
267
257
|
format = format.toLowerCase();
|
|
268
258
|
return new Promise((resolve, reject) => {
|
|
@@ -288,12 +278,12 @@ class Compress extends core_1.Module {
|
|
|
288
278
|
fromCache = result;
|
|
289
279
|
result = null;
|
|
290
280
|
}
|
|
291
|
-
if (
|
|
281
|
+
if (isString(data)) {
|
|
292
282
|
result = data;
|
|
293
283
|
data = null;
|
|
294
284
|
}
|
|
295
285
|
if (!fromCache) {
|
|
296
|
-
const status =
|
|
286
|
+
const status = isString(result) ? path.basename(result) : filename || "Completed";
|
|
297
287
|
this.writeTimeProcess(ext || format, status + getOutputSize(startLength, data, !!worker), startTime, { type: 8, sessionId: options.sessionId, broadcastId: options.broadcastId });
|
|
298
288
|
}
|
|
299
289
|
if (result) {
|
|
@@ -310,10 +300,10 @@ class Compress extends core_1.Module {
|
|
|
310
300
|
if (worker) {
|
|
311
301
|
void worker.terminate();
|
|
312
302
|
}
|
|
313
|
-
endProcess(
|
|
303
|
+
endProcess(errorValue(worker ? "Worker did not finish" : "Timeout was exceeded", format));
|
|
314
304
|
}, worker ? getWorkerTimeout(options, timeout) : timeout);
|
|
315
305
|
}
|
|
316
|
-
this.formatMessage(8, format, [compressing ? 'Compressing file...' : 'Decompressing file...', filename || (output ? path.basename(output) : '')],
|
|
306
|
+
this.formatMessage(8, format, [compressing ? 'Compressing file...' : 'Decompressing file...', filename || (output ? path.basename(output) : '')], isString(file) ? file : '', { titleColor: 'magenta', sessionId: options.sessionId, broadcastId: options.broadcastId });
|
|
317
307
|
};
|
|
318
308
|
try {
|
|
319
309
|
const writeFont = (data, ext, from) => {
|
|
@@ -321,7 +311,7 @@ class Compress extends core_1.Module {
|
|
|
321
311
|
return;
|
|
322
312
|
}
|
|
323
313
|
if (output) {
|
|
324
|
-
const pathname =
|
|
314
|
+
const pathname = renameExt(output, ext);
|
|
325
315
|
fs.writeFile(pathname, data, err => {
|
|
326
316
|
if (!err) {
|
|
327
317
|
endProcess(null, data, ext, pathname);
|
|
@@ -337,7 +327,7 @@ class Compress extends core_1.Module {
|
|
|
337
327
|
if (tempDir && hash) {
|
|
338
328
|
const pathname = path.join(from, ext);
|
|
339
329
|
let tempFont;
|
|
340
|
-
if (
|
|
330
|
+
if (Module.createDir(tempFont = path.join(tempDir, pathname))) {
|
|
341
331
|
tempFont = path.join(tempFont, hash);
|
|
342
332
|
}
|
|
343
333
|
else {
|
|
@@ -358,10 +348,10 @@ class Compress extends core_1.Module {
|
|
|
358
348
|
return false;
|
|
359
349
|
}
|
|
360
350
|
if (hash) {
|
|
361
|
-
hash =
|
|
351
|
+
hash = Module.asHash(hash);
|
|
362
352
|
}
|
|
363
353
|
else if (Buffer.isBuffer(file)) {
|
|
364
|
-
hash =
|
|
354
|
+
hash = Module.asHash(file);
|
|
365
355
|
}
|
|
366
356
|
else {
|
|
367
357
|
return false;
|
|
@@ -372,18 +362,18 @@ class Compress extends core_1.Module {
|
|
|
372
362
|
const cacheKey = from + `_${to}_` + hash;
|
|
373
363
|
const tempFont = CACHE_FONT.get(cacheKey);
|
|
374
364
|
if (tempFont) {
|
|
375
|
-
if (
|
|
365
|
+
if (Module.isPath(tempFont[0])) {
|
|
376
366
|
try {
|
|
377
367
|
const data = fs.readFileSync(tempFont[0]);
|
|
378
368
|
let pathname;
|
|
379
369
|
if (output) {
|
|
380
|
-
fs.writeFileSync(pathname =
|
|
370
|
+
fs.writeFileSync(pathname = renameExt(output, to), data);
|
|
381
371
|
endProcess(null, data, to, pathname, true);
|
|
382
372
|
}
|
|
383
373
|
else {
|
|
384
374
|
endProcess(null, data, to, true);
|
|
385
375
|
}
|
|
386
|
-
this.formatMessage(8, from, [pathname ? path.basename(pathname) : "Completed" + ` -> font/${to}`, 'cache'], tempFont[1].toLocaleString(), { ...
|
|
376
|
+
this.formatMessage(8, from, [pathname ? path.basename(pathname) : "Completed" + ` -> font/${to}`, 'cache'], tempFont[1].toLocaleString(), { ...Module.LOG_STYLE_NOTICE, hintBold: true, sessionId: options.sessionId, broadcastId: options.broadcastId });
|
|
387
377
|
return true;
|
|
388
378
|
}
|
|
389
379
|
catch {
|
|
@@ -395,7 +385,7 @@ class Compress extends core_1.Module {
|
|
|
395
385
|
}
|
|
396
386
|
};
|
|
397
387
|
const errorResponse = (font, message = "Unsupported MIME") => {
|
|
398
|
-
endProcess(
|
|
388
|
+
endProcess(errorValue(message, (font?.mime || "Unknown") + ': ' + (output || filename || "Unknown")));
|
|
399
389
|
};
|
|
400
390
|
const shared = Buffer.isBuffer(file);
|
|
401
391
|
let data;
|
|
@@ -406,28 +396,38 @@ class Compress extends core_1.Module {
|
|
|
406
396
|
data = fs.readFileSync(file);
|
|
407
397
|
}
|
|
408
398
|
else {
|
|
409
|
-
reject(
|
|
399
|
+
reject(errorValue("Operation not permitted", file));
|
|
410
400
|
return;
|
|
411
401
|
}
|
|
412
402
|
startLength = Buffer.byteLength(data);
|
|
413
403
|
switch (format) {
|
|
404
|
+
case 'zst':
|
|
405
|
+
if (!SUPPORTED_ZSTD) {
|
|
406
|
+
endProcess(errorMessage(format, "Not implemented by runtime application", '22.15.0'));
|
|
407
|
+
break;
|
|
408
|
+
}
|
|
414
409
|
case 'gz':
|
|
415
410
|
case 'br': {
|
|
416
411
|
if (this.hasPermission('worker', options)) {
|
|
417
412
|
const workerOptions = { chunkSize: options.chunkSize ?? this.chunkSize };
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
413
|
+
switch (format) {
|
|
414
|
+
case 'br':
|
|
415
|
+
workerOptions.params = { [zlib.constants.BROTLI_PARAM_QUALITY]: options.level ?? this.level.br };
|
|
416
|
+
applyBrotliMode(workerOptions.params, options.mimeType);
|
|
417
|
+
break;
|
|
418
|
+
case 'zst':
|
|
419
|
+
workerOptions.params = { [zlib.constants.ZSTD_c_compressionLevel]: options.level ?? this.level.zst };
|
|
420
|
+
break;
|
|
421
|
+
default:
|
|
422
|
+
workerOptions.level = options.level ?? this.level.gz;
|
|
423
|
+
break;
|
|
424
424
|
}
|
|
425
425
|
const endWorker = (result) => {
|
|
426
426
|
if (result) {
|
|
427
427
|
endProcess(null, result, format);
|
|
428
428
|
}
|
|
429
429
|
else {
|
|
430
|
-
endProcess(
|
|
430
|
+
endProcess(errorValue("Worker did not finish", output));
|
|
431
431
|
}
|
|
432
432
|
};
|
|
433
433
|
if (worker = WORKER.get(format).sendObject({ data, options: workerOptions, output }, shared || SUPPORTED_NODE21 ? [] : [data.buffer], endWorker)) {
|
|
@@ -438,11 +438,21 @@ class Compress extends core_1.Module {
|
|
|
438
438
|
startProcess(true);
|
|
439
439
|
let transform, chunks;
|
|
440
440
|
if (output) {
|
|
441
|
-
|
|
441
|
+
if (format === 'zst') {
|
|
442
|
+
transform = this.#createWriteStreamAsZstd(data, output, options);
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
transform = this[format === 'gz' ? 'createWriteStreamAsGzip' : 'createWriteStreamAsBrotli'](data, output, options);
|
|
446
|
+
}
|
|
442
447
|
}
|
|
443
448
|
else {
|
|
444
449
|
chunks = [];
|
|
445
|
-
|
|
450
|
+
if (format === 'zst') {
|
|
451
|
+
transform = this.#createZstdCompress(data, options);
|
|
452
|
+
}
|
|
453
|
+
else {
|
|
454
|
+
transform = this[format === 'gz' ? 'createGzip' : 'createBrotliCompress'](data, options);
|
|
455
|
+
}
|
|
446
456
|
transform.on('data', chunk => {
|
|
447
457
|
chunks.push(chunk);
|
|
448
458
|
});
|
|
@@ -464,7 +474,7 @@ class Compress extends core_1.Module {
|
|
|
464
474
|
}
|
|
465
475
|
const checkResult = (result, from) => {
|
|
466
476
|
if (result) {
|
|
467
|
-
void
|
|
477
|
+
void Module.resolveMime(result).then(font => {
|
|
468
478
|
switch (font?.mime) {
|
|
469
479
|
case "font/ttf":
|
|
470
480
|
case "font/otf":
|
|
@@ -480,7 +490,7 @@ class Compress extends core_1.Module {
|
|
|
480
490
|
errorResponse(null, "Worker did not finish");
|
|
481
491
|
}
|
|
482
492
|
};
|
|
483
|
-
void
|
|
493
|
+
void Module.resolveMime(data)
|
|
484
494
|
.then(font => {
|
|
485
495
|
switch (font?.mime) {
|
|
486
496
|
case "font/woff":
|
|
@@ -504,7 +514,7 @@ class Compress extends core_1.Module {
|
|
|
504
514
|
}
|
|
505
515
|
else {
|
|
506
516
|
startProcess(false);
|
|
507
|
-
void
|
|
517
|
+
void decompress(data).then(woff => checkResult(woff, 'woff2'));
|
|
508
518
|
}
|
|
509
519
|
break;
|
|
510
520
|
default:
|
|
@@ -522,7 +532,7 @@ class Compress extends core_1.Module {
|
|
|
522
532
|
}
|
|
523
533
|
const checkResult = (result, from, mimeType) => {
|
|
524
534
|
if (result) {
|
|
525
|
-
void
|
|
535
|
+
void Module.resolveMime(result).then(font => {
|
|
526
536
|
if (font?.mime === mimeType) {
|
|
527
537
|
writeFont(result, font.ext, from);
|
|
528
538
|
}
|
|
@@ -536,7 +546,7 @@ class Compress extends core_1.Module {
|
|
|
536
546
|
}
|
|
537
547
|
};
|
|
538
548
|
startProcess(true);
|
|
539
|
-
void
|
|
549
|
+
void Module.resolveMime(data)
|
|
540
550
|
.then(font => {
|
|
541
551
|
switch (font?.mime) {
|
|
542
552
|
case "font/ttf":
|
|
@@ -548,7 +558,7 @@ class Compress extends core_1.Module {
|
|
|
548
558
|
}
|
|
549
559
|
else {
|
|
550
560
|
startProcess(false);
|
|
551
|
-
void
|
|
561
|
+
void compress(data).then(result => checkResult(result, 'ttf', "font/woff2"));
|
|
552
562
|
}
|
|
553
563
|
break;
|
|
554
564
|
case "font/otf":
|
|
@@ -574,7 +584,7 @@ class Compress extends core_1.Module {
|
|
|
574
584
|
default: {
|
|
575
585
|
const compressor = this.compressors[format];
|
|
576
586
|
if (typeof compressor !== 'function') {
|
|
577
|
-
throw
|
|
587
|
+
throw errorValue("Missing compression plugin", format);
|
|
578
588
|
}
|
|
579
589
|
startProcess(true);
|
|
580
590
|
if (compressor.toString().startsWith('async')) {
|
|
@@ -597,7 +607,7 @@ class Compress extends core_1.Module {
|
|
|
597
607
|
});
|
|
598
608
|
}
|
|
599
609
|
async tryImage(file, output, options) {
|
|
600
|
-
if (
|
|
610
|
+
if (isObject(output)) {
|
|
601
611
|
options = output;
|
|
602
612
|
output = '';
|
|
603
613
|
}
|
|
@@ -605,22 +615,22 @@ class Compress extends core_1.Module {
|
|
|
605
615
|
options ||= {};
|
|
606
616
|
}
|
|
607
617
|
const { filename, startTime = process.hrtime.bigint(), timeout = 0 } = options;
|
|
608
|
-
if (!
|
|
618
|
+
if (!isString(output)) {
|
|
609
619
|
output = typeof file === 'string' ? file : '';
|
|
610
620
|
}
|
|
611
621
|
if (output && !this.canWrite(output, { ownPermissionOnly: true })) {
|
|
612
|
-
return Promise.reject(
|
|
622
|
+
return Promise.reject(errorValue("Operation not permitted", output));
|
|
613
623
|
}
|
|
614
624
|
let plugin = options.plugin;
|
|
615
|
-
if (
|
|
616
|
-
if (
|
|
617
|
-
plugin =
|
|
625
|
+
if (isString(plugin)) {
|
|
626
|
+
if (IMPORT_MAP[plugin]) {
|
|
627
|
+
plugin = IMPORT_MAP[plugin];
|
|
618
628
|
}
|
|
619
629
|
}
|
|
620
630
|
else {
|
|
621
|
-
return Promise.reject(
|
|
631
|
+
return Promise.reject(errorValue("Missing compression plugin", output));
|
|
622
632
|
}
|
|
623
|
-
const ext = output ?
|
|
633
|
+
const ext = output ? asExt(output) : options.format || "Unknown";
|
|
624
634
|
const getFormat = () => output ? path.basename(output) : ext;
|
|
625
635
|
let data, shared = false;
|
|
626
636
|
if (Buffer.isBuffer(file)) {
|
|
@@ -636,10 +646,10 @@ class Compress extends core_1.Module {
|
|
|
636
646
|
}
|
|
637
647
|
}
|
|
638
648
|
else {
|
|
639
|
-
return Promise.reject(
|
|
649
|
+
return Promise.reject(errorValue("Operation not permitted", file));
|
|
640
650
|
}
|
|
641
651
|
if (!options.mimeType) {
|
|
642
|
-
const out = await
|
|
652
|
+
const out = await Module.resolveMime(data);
|
|
643
653
|
if (out) {
|
|
644
654
|
options.mimeType = out.mime;
|
|
645
655
|
}
|
|
@@ -659,17 +669,17 @@ class Compress extends core_1.Module {
|
|
|
659
669
|
reject(err);
|
|
660
670
|
return;
|
|
661
671
|
}
|
|
662
|
-
const value = output ? path.basename(output) : filename ||
|
|
672
|
+
const value = output ? path.basename(output) : filename || isString(file) && path.basename(file);
|
|
663
673
|
const status = value ? plugin + ': ' + value : "Completed";
|
|
664
674
|
if (ctime) {
|
|
665
|
-
this.formatMessage(8, value ?
|
|
675
|
+
this.formatMessage(8, value ? asExt(value) : '', [status, 'cache'], ctime.toLocaleString(), { ...Module.LOG_STYLE_NOTICE, hintBold: true, sessionId: options.sessionId, broadcastId: options.broadcastId });
|
|
666
676
|
}
|
|
667
677
|
else {
|
|
668
678
|
this.writeTimeProcess(ext, status + getOutputSize(startLength, result, worker), startTime, { type: 8, sessionId: options.sessionId, broadcastId: options.broadcastId });
|
|
669
679
|
}
|
|
670
680
|
if (!ctime && hash) {
|
|
671
681
|
const pathname = path.join(tempDir, sanitizePath(plugin), hash);
|
|
672
|
-
if (
|
|
682
|
+
if (Module.createDir(pathname)) {
|
|
673
683
|
fs.writeFile(path.join(pathname, cacheKey), result, error => {
|
|
674
684
|
if (!error) {
|
|
675
685
|
((CACHE_IMAGE[plugin] ||= {})[hash] ||= {})[cacheKey] = new Date();
|
|
@@ -699,9 +709,9 @@ class Compress extends core_1.Module {
|
|
|
699
709
|
if (tempDir) {
|
|
700
710
|
let stored;
|
|
701
711
|
try {
|
|
702
|
-
hash =
|
|
712
|
+
hash = Module.asHash(data);
|
|
703
713
|
stored = (CACHE_IMAGE[plugin] ||= {})[hash];
|
|
704
|
-
cacheKey = plugin + (options.options ? ':' +
|
|
714
|
+
cacheKey = plugin + (options.options ? ':' + Module.asHash(Module.asString(options.options)) : '') + (options.metadata ? ':' + Module.asHash(Module.asString(options.metadata)) : '');
|
|
705
715
|
const ctime = stored?.[cacheKey];
|
|
706
716
|
if (ctime) {
|
|
707
717
|
success(fs.readFileSync(path.join(tempDir, sanitizePath(plugin), hash, cacheKey)), false, ctime);
|
|
@@ -723,7 +733,7 @@ class Compress extends core_1.Module {
|
|
|
723
733
|
success(result, !!worker);
|
|
724
734
|
}
|
|
725
735
|
else {
|
|
726
|
-
failed(
|
|
736
|
+
failed(errorMessage(plugin, "Unsupported MIME", getFormat()));
|
|
727
737
|
}
|
|
728
738
|
};
|
|
729
739
|
const startTimeout = (value, message) => {
|
|
@@ -732,7 +742,7 @@ class Compress extends core_1.Module {
|
|
|
732
742
|
if (worker) {
|
|
733
743
|
void worker.terminate();
|
|
734
744
|
}
|
|
735
|
-
failed(
|
|
745
|
+
failed(errorMessage(plugin, message, options.mimeType));
|
|
736
746
|
}, value);
|
|
737
747
|
}
|
|
738
748
|
};
|
|
@@ -751,7 +761,7 @@ class Compress extends core_1.Module {
|
|
|
751
761
|
}
|
|
752
762
|
let transform;
|
|
753
763
|
try {
|
|
754
|
-
transform = await
|
|
764
|
+
transform = await importESM(plugin, true);
|
|
755
765
|
}
|
|
756
766
|
catch {
|
|
757
767
|
transform = require(plugin);
|
|
@@ -767,10 +777,39 @@ class Compress extends core_1.Module {
|
|
|
767
777
|
}
|
|
768
778
|
hasPermission(type, options) {
|
|
769
779
|
if (super.hasPermission(type)) {
|
|
770
|
-
return type === 'worker' ?
|
|
780
|
+
return type === 'worker' ? WorkerChannel.hasPermission(options) : true;
|
|
771
781
|
}
|
|
772
782
|
return false;
|
|
773
783
|
}
|
|
784
|
+
#createZstdCompress(file, options) {
|
|
785
|
+
let level, chunkSize, params, strategy;
|
|
786
|
+
if (options) {
|
|
787
|
+
({ level, chunkSize, params, strategy } = options);
|
|
788
|
+
}
|
|
789
|
+
const zstd = applySettings(this.module.zstd, params ||= {});
|
|
790
|
+
if (typeof level === 'number') {
|
|
791
|
+
params[zlib.constants.ZSTD_c_compressionLevel] = level;
|
|
792
|
+
}
|
|
793
|
+
else if (typeof this.level.zst === 'number') {
|
|
794
|
+
params[zlib.constants.ZSTD_c_compressionLevel] ??= this.level.zst;
|
|
795
|
+
}
|
|
796
|
+
if (typeof strategy === 'number') {
|
|
797
|
+
params[zlib.constants.ZSTD_c_strategy] = strategy;
|
|
798
|
+
}
|
|
799
|
+
if (!isNaN(chunkSize = alignSize(chunkSize, 1))) {
|
|
800
|
+
zstd.chunkSize = chunkSize;
|
|
801
|
+
}
|
|
802
|
+
else {
|
|
803
|
+
zstd.chunkSize ??= this.chunkSize;
|
|
804
|
+
}
|
|
805
|
+
if (options) {
|
|
806
|
+
applyZlibOptions(zstd, options, 'memLevel', 'windowBits');
|
|
807
|
+
}
|
|
808
|
+
return this.getReadable(file, options).pipe(zlib.createZstdCompress(zstd));
|
|
809
|
+
}
|
|
810
|
+
#createWriteStreamAsZstd(file, output, options) {
|
|
811
|
+
return this.#createZstdCompress(file, options).pipe(fs.createWriteStream(output));
|
|
812
|
+
}
|
|
774
813
|
#getCacheDir(type) {
|
|
775
814
|
let tempDir = CACHE_TEMP[type];
|
|
776
815
|
if (tempDir !== undefined) {
|
|
@@ -778,13 +817,13 @@ class Compress extends core_1.Module {
|
|
|
778
817
|
}
|
|
779
818
|
const { cache, cache_expires = 0 } = this.settings;
|
|
780
819
|
let expires;
|
|
781
|
-
if (
|
|
820
|
+
if (isPlainObject(cache)) {
|
|
782
821
|
const value = cache[type];
|
|
783
822
|
if (!cache.enabled || value === false) {
|
|
784
823
|
return CACHE_TEMP[type] = null;
|
|
785
824
|
}
|
|
786
825
|
expires = value !== undefined ? value === true ? 0 : value : cache.expires;
|
|
787
|
-
if (cache.dir &&
|
|
826
|
+
if (cache.dir && Module.createDir(tempDir = path.resolve(cache.dir, this.moduleName, type))) {
|
|
788
827
|
this.addLog(5, 'Cache directory: ' + tempDir);
|
|
789
828
|
}
|
|
790
829
|
else {
|
|
@@ -794,11 +833,11 @@ class Compress extends core_1.Module {
|
|
|
794
833
|
else if (cache !== true) {
|
|
795
834
|
return CACHE_TEMP[type] = null;
|
|
796
835
|
}
|
|
797
|
-
expires =
|
|
798
|
-
tempDir ||= this.getTempDir({ pathname: type, moduleDir: true, createDir: true }) ||
|
|
836
|
+
expires = parseExpires(expires ?? cache_expires);
|
|
837
|
+
tempDir ||= this.getTempDir({ pathname: type, moduleDir: true, createDir: true }) || getTempDir(true, this.moduleName, type);
|
|
799
838
|
CACHE_TEMP[type] = tempDir;
|
|
800
839
|
if (expires === 0) {
|
|
801
|
-
|
|
840
|
+
Module.removeDir(tempDir, true);
|
|
802
841
|
}
|
|
803
842
|
else {
|
|
804
843
|
const current = Date.now();
|
|
@@ -841,7 +880,7 @@ class Compress extends core_1.Module {
|
|
|
841
880
|
return tempDir;
|
|
842
881
|
}
|
|
843
882
|
set chunkSize(value) {
|
|
844
|
-
this.#chunkSize = !isNaN(value =
|
|
883
|
+
this.#chunkSize = !isNaN(value = alignSize(value, 1)) ? value : undefined;
|
|
845
884
|
}
|
|
846
885
|
get chunkSize() {
|
|
847
886
|
return this.#chunkSize;
|
|
@@ -850,4 +889,5 @@ class Compress extends core_1.Module {
|
|
|
850
889
|
return this.module.settings ||= {};
|
|
851
890
|
}
|
|
852
891
|
}
|
|
892
|
+
|
|
853
893
|
module.exports = Compress;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e-mc/compress",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
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.14.0",
|
|
26
|
+
"@e-mc/types": "0.14.0",
|
|
27
27
|
"wawoff2": "^2.0.1",
|
|
28
28
|
"woff2sfnt-sfnt2woff": "^1.0.0"
|
|
29
29
|
}
|
package/worker/plugin-image.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
|
|
2
|
+
|
|
3
|
+
const { parentPort, workerData } = require('node:worker_threads');
|
|
4
|
+
const { importESM } = require('@e-mc/types');
|
|
5
|
+
const Compress = require('@e-mc/compress');
|
|
6
|
+
const PORT = workerData[0];
|
|
7
|
+
parentPort.on('message', async (value) => {
|
|
7
8
|
try {
|
|
8
9
|
const { plugin, data, options, metadata } = value;
|
|
9
10
|
let transform;
|
|
10
11
|
try {
|
|
11
|
-
transform = await
|
|
12
|
+
transform = await importESM(plugin, true);
|
|
12
13
|
}
|
|
13
14
|
catch {
|
|
14
15
|
transform = require(plugin);
|
|
15
16
|
}
|
|
16
|
-
void transform(options, metadata)(
|
|
17
|
+
void transform(options, metadata)(Compress.asBuffer(data))
|
|
17
18
|
.then(result => {
|
|
18
19
|
try {
|
|
19
20
|
PORT.postMessage(result, [result.buffer]);
|
package/worker/sfnt2woff.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
const { parentPort, workerData } = require('node:worker_threads');
|
|
3
4
|
const { toWoff } = require('woff2sfnt-sfnt2woff');
|
|
4
|
-
const PORT =
|
|
5
|
-
|
|
5
|
+
const PORT = workerData[0];
|
|
6
|
+
parentPort.on('message', (value) => {
|
|
6
7
|
let data = null;
|
|
7
8
|
try {
|
|
8
9
|
data = toWoff(value);
|
package/worker/system-brotli.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
2
|
+
|
|
3
|
+
const { parentPort, workerData } = require('node:worker_threads');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const stream = require('node:stream');
|
|
6
|
+
const zlib = require('node:zlib');
|
|
7
|
+
const Compress = require('@e-mc/compress');
|
|
8
|
+
const PORT = workerData[0];
|
|
9
|
+
parentPort.on('message', async (value) => {
|
|
9
10
|
try {
|
|
10
11
|
const { data, options, output } = value;
|
|
11
12
|
const chunks = [];
|
|
12
|
-
let transform = stream.Readable.from(
|
|
13
|
+
let transform = stream.Readable.from(Compress.asBuffer(data)).pipe(zlib.createBrotliCompress(options));
|
|
13
14
|
if (output) {
|
|
14
15
|
transform = transform.pipe(fs.createWriteStream(output));
|
|
15
16
|
}
|
package/worker/system-gzip.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
2
|
+
|
|
3
|
+
const { parentPort, workerData } = require('node:worker_threads');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const stream = require('node:stream');
|
|
6
|
+
const zlib = require('node:zlib');
|
|
7
|
+
const Compress = require('@e-mc/compress');
|
|
8
|
+
const PORT = workerData[0];
|
|
9
|
+
parentPort.on('message', async (value) => {
|
|
9
10
|
try {
|
|
10
11
|
const { data, options, output } = value;
|
|
11
12
|
const chunks = [];
|
|
12
|
-
let transform = stream.Readable.from(
|
|
13
|
+
let transform = stream.Readable.from(Compress.asBuffer(data)).pipe(zlib.createGzip(options));
|
|
13
14
|
if (output) {
|
|
14
15
|
transform = transform.pipe(fs.createWriteStream(output));
|
|
15
16
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { parentPort, workerData } = require('node:worker_threads');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const stream = require('node:stream');
|
|
6
|
+
const zlib = require('node:zlib');
|
|
7
|
+
const Compress = require('@e-mc/compress');
|
|
8
|
+
const PORT = workerData[0];
|
|
9
|
+
parentPort.on('message', async (value) => {
|
|
10
|
+
try {
|
|
11
|
+
const { data, options, output } = value;
|
|
12
|
+
const chunks = [];
|
|
13
|
+
let transform = stream.Readable.from(Compress.asBuffer(data)).pipe(zlib.createZstdCompress(options));
|
|
14
|
+
if (output) {
|
|
15
|
+
transform = transform.pipe(fs.createWriteStream(output));
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
transform.on('data', chunk => {
|
|
19
|
+
chunks.push(chunk);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
transform
|
|
23
|
+
.on('finish', () => {
|
|
24
|
+
if (chunks.length > 0) {
|
|
25
|
+
const result = Buffer.concat(chunks);
|
|
26
|
+
PORT.postMessage(result, [result.buffer]);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
PORT.postMessage(output || null);
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
.on('error', (err) => {
|
|
33
|
+
transform.destroy();
|
|
34
|
+
throw err;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
console.error(err);
|
|
39
|
+
PORT.postMessage(null);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
|
|
3
|
+
const { parentPort, workerData } = require('node:worker_threads');
|
|
4
|
+
const { compress } = require('wawoff2');
|
|
5
|
+
const PORT = workerData[0];
|
|
6
|
+
parentPort.on('message', (value) => {
|
|
7
|
+
compress(value)
|
|
7
8
|
.then(data => {
|
|
8
9
|
PORT.postMessage(data);
|
|
9
10
|
})
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
|
|
3
|
+
const { parentPort, workerData } = require('node:worker_threads');
|
|
4
|
+
const { decompress } = require('wawoff2');
|
|
5
|
+
const PORT = workerData[0];
|
|
6
|
+
parentPort.on('message', (value) => {
|
|
7
|
+
decompress(value)
|
|
7
8
|
.then(data => {
|
|
8
9
|
PORT.postMessage(data);
|
|
9
10
|
})
|
package/worker/woff2sfnt.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
const { parentPort, workerData } = require('node:worker_threads');
|
|
3
4
|
const { toSfnt } = require('woff2sfnt-sfnt2woff');
|
|
4
|
-
const PORT =
|
|
5
|
-
|
|
5
|
+
const PORT = workerData[0];
|
|
6
|
+
parentPort.on('message', (value) => {
|
|
6
7
|
let data = null;
|
|
7
8
|
try {
|
|
8
9
|
data = toSfnt(value);
|