@turntrout/subfont 1.6.0 → 1.7.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.
Files changed (39) hide show
  1. package/README.md +43 -43
  2. package/lib/FontTracerPool.d.ts +37 -0
  3. package/lib/FontTracerPool.d.ts.map +1 -0
  4. package/lib/FontTracerPool.js +212 -173
  5. package/lib/FontTracerPool.js.map +1 -0
  6. package/lib/HeadlessBrowser.js +11 -3
  7. package/lib/cli.d.ts +3 -0
  8. package/lib/cli.d.ts.map +1 -0
  9. package/lib/cli.js +15 -12
  10. package/lib/cli.js.map +1 -0
  11. package/lib/collectTextsByPage.js +425 -352
  12. package/lib/escapeJsStringLiteral.js +13 -0
  13. package/lib/extractVisibleText.js +6 -2
  14. package/lib/fontConverter.js +25 -0
  15. package/lib/fontConverterWorker.js +16 -0
  16. package/lib/fontFaceHelpers.js +16 -4
  17. package/lib/gatherStylesheetsWithPredicates.js +4 -5
  18. package/lib/normalizeFontPropertyValue.js +1 -1
  19. package/lib/sfntCache.js +10 -7
  20. package/lib/subfont.d.ts +33 -0
  21. package/lib/subfont.d.ts.map +1 -0
  22. package/lib/subfont.js +533 -591
  23. package/lib/subfont.js.map +1 -0
  24. package/lib/subsetFontWithGlyphs.d.ts +17 -0
  25. package/lib/subsetFontWithGlyphs.d.ts.map +1 -0
  26. package/lib/subsetFontWithGlyphs.js +231 -253
  27. package/lib/subsetFontWithGlyphs.js.map +1 -0
  28. package/lib/subsetFonts.d.ts +59 -0
  29. package/lib/subsetFonts.d.ts.map +1 -0
  30. package/lib/subsetFonts.js +921 -1180
  31. package/lib/subsetFonts.js.map +1 -0
  32. package/lib/subsetGeneration.d.ts +39 -0
  33. package/lib/subsetGeneration.d.ts.map +1 -0
  34. package/lib/subsetGeneration.js +294 -324
  35. package/lib/subsetGeneration.js.map +1 -0
  36. package/lib/unquote.js +9 -4
  37. package/lib/warnAboutMissingGlyphs.js +36 -25
  38. package/lib/wasmQueue.js +6 -2
  39. package/package.json +11 -3
package/README.md CHANGED
@@ -55,27 +55,27 @@ subfont path/to/index.html -i --cache
55
55
 
56
56
  ## Options
57
57
 
58
- | Flag | Default | Description |
59
- | -----------------: | :-----: | :----------------------------------------------------------- |
60
- | `-i, --in-place` | off | Modify files in-place |
61
- | `-o, --output` | | Output directory |
62
- | `--root` | | Path to web root (deduced from input files if not specified) |
63
- | `--canonical-root` | | URI root where the site will be deployed |
64
- | `-r, --recursive` | off | Crawl linked pages |
65
- | `--dynamic` | off | Trace with headless browser |
66
- | `--dry-run` | off | Preview without writing |
67
- | `--fallbacks` | on | Load the full original font for characters not in the subset |
68
- | `--font-display` | `swap` | `auto`/`block`/`swap`/`fallback`/`optional` |
69
- | `--text` | | Extra characters for every subset |
70
- | `--cache [dir]` | off | Cache subset results to disk between runs |
71
- | `--concurrency N` | | Max worker threads (capped by available memory, ~50 MB each) |
72
- | `--chrome-flags` | | Custom Chrome flags for `--dynamic` |
73
- | `--source-maps` | off | Preserve CSS source maps (slower) |
74
- | `--strict` | off | Exit non-zero if any warnings are emitted |
75
- | `-s, --silent` | off | Suppress all console output |
76
- | `-d, --debug` | off | Verbose timing and font glyph detection info |
77
- | `--relative-urls` | off | Emit relative URLs instead of root-relative |
78
- | `--inline-css` | off | Inline the subset @font-face CSS into HTML |
58
+ | Flag | Default | Description |
59
+ | -----------------: | :-----: | :------------------------------------------------------------------------------------ |
60
+ | `-i, --in-place` | off | Modify files in-place |
61
+ | `-o, --output` | | Output directory |
62
+ | `--root` | | Path to web root (deduced from input files if not specified) |
63
+ | `--canonical-root` | | URI root where the site will be deployed |
64
+ | `-r, --recursive` | off | Crawl linked pages |
65
+ | `--dynamic` | off | Trace with headless browser |
66
+ | `--dry-run` | off | Preview without writing |
67
+ | `--fallbacks` | on | Async-load the full original font as a fallback for dynamic content |
68
+ | `--font-display` | `swap` | `auto`/`block`/`swap`/`fallback`/`optional` |
69
+ | `--text` | | Extra characters for every subset |
70
+ | `--cache [dir]` | off | Cache subset results to disk between runs |
71
+ | `--concurrency N` | auto | Max worker threads (defaults to CPU count, capped by available memory at ~50 MB each) |
72
+ | `--chrome-flags` | | Custom Chrome flags for `--dynamic` (comma-separated) |
73
+ | `--source-maps` | off | Preserve CSS source maps (slower) |
74
+ | `--strict` | off | Exit non-zero if any warnings are emitted |
75
+ | `-s, --silent` | off | Suppress all console output |
76
+ | `-d, --debug` | off | Verbose timing and font glyph detection info |
77
+ | `--relative-urls` | off | Emit relative URLs instead of root-relative |
78
+ | `--inline-css` | off | Inline the subset @font-face CSS into HTML |
79
79
 
80
80
  Run `subfont --help` for the full list.
81
81
 
@@ -113,28 +113,28 @@ with `log`, `warn`, and `error` methods — e.g. the global `console`). Pass
113
113
 
114
114
  The `options` object accepts the following keys:
115
115
 
116
- | Option | Type | Default | Description |
117
- | --------------- | ------------------- | -------- | ------------------------------------------------------------------------------------------------------------ |
118
- | `inputFiles` | `string[]` | `[]` | HTML entry points (file paths or URLs). At least one is required unless `root` is given. |
119
- | `root` | `string` | deduced | Path or URL to the web root. Deduced from `inputFiles` if omitted. |
120
- | `canonicalRoot` | `string` | — | URI root where the site will be deployed (used to rewrite absolute URLs). |
121
- | `output` | `string` | — | Output directory. Mutually exclusive with `inPlace`. |
122
- | `inPlace` | `boolean` | `false` | Modify input files in place. |
123
- | `dryRun` | `boolean` | `false` | Trace and compute subsets but do not write any files. |
124
- | `recursive` | `boolean` | `false` | Crawl linked pages starting from `inputFiles`. |
125
- | `dynamic` | `boolean` | `false` | Trace JS-rendered content in headless Chrome (via puppeteer). |
126
- | `fallbacks` | `boolean` | `true` | Keep the full original font for characters outside the subset. |
127
- | `fontDisplay` | `string` | `'swap'` | `font-display` CSS value: `auto`, `block`, `swap`, `fallback`, or `optional`. |
128
- | `text` | `string` | — | Extra characters to include in every subset. |
129
- | `inlineCss` | `boolean` | `false` | Inline the subset `@font-face` CSS into the HTML document. |
130
- | `relativeUrls` | `boolean` | `false` | Emit relative URLs instead of root-relative URLs. |
131
- | `sourceMaps` | `boolean` | `false` | Preserve CSS source maps (slower). |
132
- | `concurrency` | `number` | auto | Max parallel tracing workers. Capped by available memory (~50 MB per worker). |
133
- | `chromeFlags` | `string[]` | `[]` | Extra Chrome flags forwarded to puppeteer when `dynamic` is set. |
134
- | `cache` | `boolean \| string` | `false` | Cache subset results between runs. Pass a path to customize the cache directory; `true` uses the OS tmp dir. |
135
- | `strict` | `boolean` | `false` | Resolve with a non-zero exit (via the CLI) if any warnings are emitted. |
136
- | `silent` | `boolean` | `false` | Suppress all log output to `console`. |
137
- | `debug` | `boolean` | `false` | Emit verbose timing and glyph-detection info. |
116
+ | Option | Type | Default | Description |
117
+ | --------------- | ------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
118
+ | `inputFiles` | `string[]` | `[]` | HTML entry points (file paths or URLs). At least one is required unless `root` is given. |
119
+ | `root` | `string` | deduced | Path or URL to the web root. Deduced from `inputFiles` if omitted. |
120
+ | `canonicalRoot` | `string` | — | URI root where the site will be deployed (used to rewrite absolute URLs). |
121
+ | `output` | `string` | — | Output directory. Mutually exclusive with `inPlace`. |
122
+ | `inPlace` | `boolean` | `false` | Modify input files in place. |
123
+ | `dryRun` | `boolean` | `false` | Trace and compute subsets but do not write any files. |
124
+ | `recursive` | `boolean` | `false` | Crawl linked pages starting from `inputFiles`. |
125
+ | `dynamic` | `boolean` | `false` | Trace JS-rendered content in headless Chrome (via puppeteer). |
126
+ | `fallbacks` | `boolean` | `true` | Async-load the full original font as a fallback for dynamic content. |
127
+ | `fontDisplay` | `string` | `'swap'` | `font-display` CSS value: `auto`, `block`, `swap`, `fallback`, or `optional`. |
128
+ | `text` | `string` | — | Extra characters to include in every subset. |
129
+ | `inlineCss` | `boolean` | `false` | Inline the subset `@font-face` CSS into the HTML document. |
130
+ | `relativeUrls` | `boolean` | `false` | Emit relative URLs instead of root-relative URLs. |
131
+ | `sourceMaps` | `boolean` | `false` | Preserve CSS source maps (slower). |
132
+ | `concurrency` | `number` | auto | Max parallel tracing workers. Defaults to CPU count, capped by available memory (~50 MB per worker). |
133
+ | `chromeFlags` | `string[]` | `[]` | Extra Chrome flags forwarded to puppeteer when `dynamic` is set. |
134
+ | `cache` | `boolean \| string` | `false` | Cache subset results between runs. Pass a path to customize the cache directory; `true` uses `.subfont-cache` inside the `root` directory. |
135
+ | `strict` | `boolean` | `false` | Resolve with a non-zero exit (via the CLI) if any warnings are emitted. |
136
+ | `silent` | `boolean` | `false` | Suppress all log output to `console`. |
137
+ | `debug` | `boolean` | `false` | Emit verbose timing and glyph-detection info. |
138
138
 
139
139
  ## License
140
140
 
@@ -0,0 +1,37 @@
1
+ interface StylesheetWithPredicates {
2
+ text?: string;
3
+ asset?: {
4
+ text?: string;
5
+ };
6
+ predicates?: Record<string, unknown>;
7
+ }
8
+ interface FontTracerPoolOptions {
9
+ taskTimeoutMs?: number;
10
+ }
11
+ declare class FontTracerPool {
12
+ private _workerPath;
13
+ private _numWorkers;
14
+ private _taskTimeoutMs;
15
+ private _workers;
16
+ private _idle;
17
+ private _pendingTasks;
18
+ private _taskCallbacks;
19
+ private _taskTimers;
20
+ private _taskByWorker;
21
+ private _nextTaskId;
22
+ constructor(numWorkers: number, { taskTimeoutMs }?: FontTracerPoolOptions);
23
+ init(): Promise<void>;
24
+ private _clearTaskTimer;
25
+ private _onWorkerMessage;
26
+ private _onWorkerExit;
27
+ private _startTaskTimer;
28
+ private _dispatchPending;
29
+ /**
30
+ * Run fontTracer on the given HTML text + stylesheets in a worker.
31
+ * Returns a promise that resolves to textByProps.
32
+ */
33
+ trace(htmlText: string, stylesheetsWithPredicates: StylesheetWithPredicates[]): Promise<unknown>;
34
+ destroy(): Promise<void>;
35
+ }
36
+ export = FontTracerPool;
37
+ //# sourceMappingURL=FontTracerPool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FontTracerPool.d.ts","sourceRoot":"","sources":["../src/FontTracerPool.ts"],"names":[],"mappings":"AAkBA,UAAU,wBAAwB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAI1B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAqCD,UAAU,qBAAqB;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,cAAM,cAAc;IAClB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,aAAa,CAAmC;IACxD,OAAO,CAAC,cAAc,CAA6B;IACnD,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,WAAW,CAAS;gBAG1B,UAAU,EAAE,MAAM,EAClB,EAAE,aAAuC,EAAE,GAAE,qBAA0B;IAcnE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAiC3B,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,aAAa;IAwCrB,OAAO,CAAC,eAAe;IA2BvB,OAAO,CAAC,gBAAgB;IAsBxB;;;OAGG;IAGH,KAAK,CACH,QAAQ,EAAE,MAAM,EAChB,yBAAyB,EAAE,wBAAwB,EAAE,GAEpD,OAAO,CAAC,OAAO,CAAC;IAsBb,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CA4C/B;AAED,SAAS,cAAc,CAAC"}
@@ -1,191 +1,230 @@
1
- const pathModule = require('path');
2
- const { Worker } = require('worker_threads');
3
-
1
+ "use strict";
2
+ const pathModule = require("path");
3
+ const worker_threads_1 = require("worker_threads");
4
4
  /**
5
5
  * Worker pool for running fontTracer in parallel across pages.
6
6
  * Each worker re-parses HTML with jsdom and runs fontTracer independently.
7
7
  */
8
+ const DEFAULT_TASK_TIMEOUT_MS = 60_000;
8
9
  class FontTracerPool {
9
- constructor(numWorkers) {
10
- this._workerPath = pathModule.join(__dirname, 'fontTracerWorker.js');
11
- this._numWorkers = numWorkers;
12
- this._workers = [];
13
- this._idle = [];
14
- this._pendingTasks = [];
15
- this._taskCallbacks = new Map();
16
- this._taskByWorker = new Map(); // track which taskId each worker is processing
17
- this._nextTaskId = 0;
18
- }
19
-
20
- async init() {
21
- const initPromises = [];
22
- for (let i = 0; i < this._numWorkers; i++) {
23
- const worker = new Worker(this._workerPath);
24
- this._workers.push(worker);
25
-
26
- const initPromise = new Promise((resolve, reject) => {
27
- const onError = reject;
28
- const onMessage = (msg) => {
29
- if (msg.type === 'ready') {
30
- worker.off('message', onMessage);
31
- worker.off('error', onError);
32
- worker.on('message', (msg) => this._onWorkerMessage(worker, msg));
33
- worker.on('exit', (code) => this._onWorkerExit(worker, code));
34
- this._idle.push(worker);
35
- resolve();
36
- }
37
- };
38
- worker.on('message', onMessage);
39
- worker.on('error', onError);
40
- });
41
-
42
- worker.postMessage({ type: 'init' });
43
-
44
- initPromises.push(initPromise);
45
- }
46
- await Promise.all(initPromises);
47
- }
48
-
49
- _onWorkerMessage(worker, msg) {
50
- this._taskByWorker.delete(worker);
51
- const cb = this._taskCallbacks.get(msg.taskId);
52
- if (cb) {
53
- this._taskCallbacks.delete(msg.taskId);
54
- if (msg.type === 'result') {
55
- cb.resolve(msg.textByProps);
56
- } else if (msg.type === 'error') {
57
- cb.reject(new Error(`Worker error: ${msg.error}\n${msg.stack}`));
58
- }
10
+ _workerPath;
11
+ _numWorkers;
12
+ _taskTimeoutMs;
13
+ _workers;
14
+ _idle;
15
+ _pendingTasks;
16
+ _taskCallbacks;
17
+ _taskTimers;
18
+ _taskByWorker;
19
+ _nextTaskId;
20
+ constructor(numWorkers, { taskTimeoutMs = DEFAULT_TASK_TIMEOUT_MS } = {}) {
21
+ this._workerPath = pathModule.join(__dirname, 'fontTracerWorker.js');
22
+ this._numWorkers = numWorkers;
23
+ this._taskTimeoutMs = taskTimeoutMs;
24
+ this._workers = [];
25
+ this._idle = [];
26
+ this._pendingTasks = [];
27
+ this._taskCallbacks = new Map();
28
+ this._taskTimers = new Map();
29
+ this._taskByWorker = new Map();
30
+ this._nextTaskId = 0;
59
31
  }
60
- // Worker is now idle, check for pending tasks
61
- this._idle.push(worker);
62
- this._dispatchPending();
63
- }
64
-
65
- _onWorkerExit(worker, code) {
66
- // Remove crashed worker from tracking
67
- const workerIdx = this._workers.indexOf(worker);
68
- if (workerIdx !== -1) {
69
- this._workers.splice(workerIdx, 1);
32
+ async init() {
33
+ const initPromises = [];
34
+ for (let i = 0; i < this._numWorkers; i++) {
35
+ const worker = new worker_threads_1.Worker(this._workerPath);
36
+ this._workers.push(worker);
37
+ const initPromise = new Promise((resolve, reject) => {
38
+ const onError = reject;
39
+ const onMessage = (msg) => {
40
+ if (msg.type === 'ready') {
41
+ worker.off('message', onMessage);
42
+ worker.off('error', onError);
43
+ worker.on('message', (msg) => this._onWorkerMessage(worker, msg));
44
+ worker.on('exit', (code) => this._onWorkerExit(worker, code));
45
+ this._idle.push(worker);
46
+ resolve();
47
+ }
48
+ };
49
+ worker.on('message', onMessage);
50
+ worker.on('error', onError);
51
+ });
52
+ worker.postMessage({ type: 'init' });
53
+ initPromises.push(initPromise);
54
+ }
55
+ await Promise.all(initPromises);
70
56
  }
71
- const idleIdx = this._idle.indexOf(worker);
72
- if (idleIdx !== -1) {
73
- this._idle.splice(idleIdx, 1);
57
+ _clearTaskTimer(taskId) {
58
+ const timer = this._taskTimers.get(taskId);
59
+ if (timer) {
60
+ clearTimeout(timer);
61
+ this._taskTimers.delete(taskId);
62
+ }
74
63
  }
75
-
76
- if (code !== 0) {
77
- // Reject the task that was in-flight on this worker
78
- const taskId = this._taskByWorker.get(worker);
79
- this._taskByWorker.delete(worker);
80
- if (taskId !== undefined) {
81
- const cb = this._taskCallbacks.get(taskId);
64
+ _onWorkerMessage(worker, msg) {
65
+ if (msg.type === 'ready')
66
+ return;
67
+ this._taskByWorker.delete(worker);
68
+ this._clearTaskTimer(msg.taskId);
69
+ const cb = this._taskCallbacks.get(msg.taskId);
82
70
  if (cb) {
83
- this._taskCallbacks.delete(taskId);
84
- cb.reject(new Error(`Worker exited with code ${code}`));
71
+ this._taskCallbacks.delete(msg.taskId);
72
+ if (msg.type === 'result') {
73
+ cb.resolve(msg.textByProps);
74
+ }
75
+ else if (msg.type === 'error') {
76
+ cb.reject(new Error(`Worker error: ${msg.error}\n${msg.stack}`));
77
+ }
85
78
  }
86
- }
87
-
88
- // If no workers remain, reject all pending tasks
89
- if (this._workers.length === 0) {
90
- for (const task of this._pendingTasks) {
91
- const cb = this._taskCallbacks.get(task.message.taskId);
92
- if (cb) {
93
- this._taskCallbacks.delete(task.message.taskId);
94
- cb.reject(
95
- new Error('All workers have crashed, no workers available')
96
- );
97
- }
79
+ // Worker is now idle, check for pending tasks
80
+ this._idle.push(worker);
81
+ this._dispatchPending();
82
+ }
83
+ _onWorkerExit(worker, code) {
84
+ // Remove crashed worker from tracking
85
+ const workerIdx = this._workers.indexOf(worker);
86
+ if (workerIdx !== -1) {
87
+ this._workers.splice(workerIdx, 1);
88
+ }
89
+ const idleIdx = this._idle.indexOf(worker);
90
+ if (idleIdx !== -1) {
91
+ this._idle.splice(idleIdx, 1);
92
+ }
93
+ if (code !== 0) {
94
+ // Reject the task that was in-flight on this worker
95
+ const taskId = this._taskByWorker.get(worker);
96
+ this._taskByWorker.delete(worker);
97
+ if (taskId !== undefined) {
98
+ this._clearTaskTimer(taskId);
99
+ const cb = this._taskCallbacks.get(taskId);
100
+ if (cb) {
101
+ this._taskCallbacks.delete(taskId);
102
+ cb.reject(new Error(`Worker exited with code ${code}`));
103
+ }
104
+ }
105
+ // If no workers remain, reject all pending tasks
106
+ if (this._workers.length === 0) {
107
+ for (const task of this._pendingTasks) {
108
+ const cb = this._taskCallbacks.get(task.message.taskId);
109
+ if (cb) {
110
+ this._taskCallbacks.delete(task.message.taskId);
111
+ cb.reject(new Error('All workers have crashed, no workers available'));
112
+ }
113
+ }
114
+ this._pendingTasks = [];
115
+ }
98
116
  }
99
- this._pendingTasks = [];
100
- }
101
117
  }
102
- }
103
-
104
- _dispatchPending() {
105
- while (this._idle.length > 0 && this._pendingTasks.length > 0) {
106
- const worker = this._idle.pop();
107
- const task = this._pendingTasks.shift();
108
- this._taskByWorker.set(worker, task.message.taskId);
109
- try {
110
- worker.postMessage(task.message);
111
- } catch (err) {
112
- // postMessage can fail synchronously (e.g. structured clone error).
113
- // Return the worker to the idle pool and reject the task.
114
- this._taskByWorker.delete(worker);
115
- this._idle.push(worker);
116
- const cb = this._taskCallbacks.get(task.message.taskId);
117
- if (cb) {
118
- this._taskCallbacks.delete(task.message.taskId);
119
- cb.reject(err);
118
+ _startTaskTimer(taskId) {
119
+ if (this._taskTimeoutMs <= 0)
120
+ return;
121
+ const timer = setTimeout(() => {
122
+ this._taskTimers.delete(taskId);
123
+ const cb = this._taskCallbacks.get(taskId);
124
+ if (cb) {
125
+ this._taskCallbacks.delete(taskId);
126
+ cb.reject(new Error(`Font tracing task ${taskId} timed out after ${this._taskTimeoutMs}ms`));
127
+ }
128
+ // Terminate the hung worker so it doesn't permanently consume a pool
129
+ // slot. _onWorkerExit will remove it from _workers and _idle.
130
+ for (const [worker, tid] of this._taskByWorker) {
131
+ if (tid === taskId) {
132
+ this._taskByWorker.delete(worker);
133
+ worker.terminate();
134
+ break;
135
+ }
136
+ }
137
+ }, this._taskTimeoutMs);
138
+ timer.unref();
139
+ this._taskTimers.set(taskId, timer);
140
+ }
141
+ _dispatchPending() {
142
+ while (this._idle.length > 0 && this._pendingTasks.length > 0) {
143
+ const worker = this._idle.pop();
144
+ const task = this._pendingTasks.shift();
145
+ this._taskByWorker.set(worker, task.message.taskId);
146
+ try {
147
+ worker.postMessage(task.message);
148
+ this._startTaskTimer(task.message.taskId);
149
+ }
150
+ catch (err) {
151
+ // postMessage can fail synchronously (e.g. structured clone error).
152
+ // Return the worker to the idle pool and reject the task.
153
+ this._taskByWorker.delete(worker);
154
+ this._idle.push(worker);
155
+ const cb = this._taskCallbacks.get(task.message.taskId);
156
+ if (cb) {
157
+ this._taskCallbacks.delete(task.message.taskId);
158
+ cb.reject(err);
159
+ }
160
+ }
120
161
  }
121
- }
122
162
  }
123
- }
124
-
125
- /**
126
- * Run fontTracer on the given HTML text + stylesheets in a worker.
127
- * Returns a promise that resolves to textByProps.
128
- */
129
- trace(htmlText, stylesheetsWithPredicates) {
130
- const taskId = this._nextTaskId++;
131
- // Serialize stylesheets to plain data — asset objects contain DOM/PostCSS
132
- // trees that cannot be transferred via structured clone.
133
- const serializedStylesheets = stylesheetsWithPredicates.map((entry) => ({
134
- text: entry.text || (entry.asset && entry.asset.text) || '',
135
- predicates: entry.predicates || {},
136
- }));
137
- const message = {
138
- type: 'trace',
139
- taskId,
140
- htmlText,
141
- stylesheetsWithPredicates: serializedStylesheets,
142
- };
143
-
144
- return new Promise((resolve, reject) => {
145
- this._taskCallbacks.set(taskId, { resolve, reject });
146
- this._pendingTasks.push({ message });
147
- this._dispatchPending();
148
- });
149
- }
150
-
151
- async destroy() {
152
- // Reject any tasks still waiting in the queue
153
- for (const task of this._pendingTasks) {
154
- const cb = this._taskCallbacks.get(task.message.taskId);
155
- if (cb) {
156
- this._taskCallbacks.delete(task.message.taskId);
157
- cb.reject(new Error('Worker pool destroyed'));
158
- }
163
+ /**
164
+ * Run fontTracer on the given HTML text + stylesheets in a worker.
165
+ * Returns a promise that resolves to textByProps.
166
+ */
167
+ // The pool is payload-agnostic; callers (subsetFonts.ts) interpret the
168
+ // returned textByProps according to font-tracer's contract.
169
+ trace(htmlText, stylesheetsWithPredicates
170
+ // eslint-disable-next-line no-restricted-syntax
171
+ ) {
172
+ const taskId = this._nextTaskId++;
173
+ // Serialize stylesheets to plain data — asset objects contain DOM/PostCSS
174
+ // trees that cannot be transferred via structured clone.
175
+ const serializedStylesheets = stylesheetsWithPredicates.map((entry) => ({
176
+ text: entry.text || (entry.asset && entry.asset.text) || '',
177
+ predicates: entry.predicates || {},
178
+ }));
179
+ const message = {
180
+ type: 'trace',
181
+ taskId,
182
+ htmlText,
183
+ stylesheetsWithPredicates: serializedStylesheets,
184
+ };
185
+ return new Promise((resolve, reject) => {
186
+ this._taskCallbacks.set(taskId, { resolve, reject });
187
+ this._pendingTasks.push({ message });
188
+ this._dispatchPending();
189
+ });
159
190
  }
160
- this._pendingTasks = [];
161
-
162
- // Reject any in-flight tasks still assigned to workers.
163
- // Clear _taskByWorker before terminate() so _onWorkerExit won't double-reject.
164
- for (const [, taskId] of this._taskByWorker) {
165
- const cb = this._taskCallbacks.get(taskId);
166
- if (cb) {
167
- this._taskCallbacks.delete(taskId);
168
- cb.reject(new Error('Worker pool destroyed'));
169
- }
191
+ async destroy() {
192
+ // Clear all task timers
193
+ for (const timer of this._taskTimers.values()) {
194
+ clearTimeout(timer);
195
+ }
196
+ this._taskTimers.clear();
197
+ // Reject any tasks still waiting in the queue
198
+ for (const task of this._pendingTasks) {
199
+ const cb = this._taskCallbacks.get(task.message.taskId);
200
+ if (cb) {
201
+ this._taskCallbacks.delete(task.message.taskId);
202
+ cb.reject(new Error('Worker pool destroyed'));
203
+ }
204
+ }
205
+ this._pendingTasks = [];
206
+ // Reject any in-flight tasks still assigned to workers.
207
+ // Clear _taskByWorker before terminate() so _onWorkerExit won't double-reject.
208
+ for (const [, taskId] of this._taskByWorker) {
209
+ const cb = this._taskCallbacks.get(taskId);
210
+ if (cb) {
211
+ this._taskCallbacks.delete(taskId);
212
+ cb.reject(new Error('Worker pool destroyed'));
213
+ }
214
+ }
215
+ this._taskByWorker.clear();
216
+ // Terminate workers with a 5-second timeout to prevent hanging
217
+ const TERMINATE_TIMEOUT_MS = 5000;
218
+ await Promise.all(this._workers.map((w) => Promise.race([
219
+ w.terminate(),
220
+ new Promise((resolve) => {
221
+ const timer = setTimeout(resolve, TERMINATE_TIMEOUT_MS);
222
+ timer.unref();
223
+ }),
224
+ ])));
225
+ this._workers = [];
226
+ this._idle = [];
170
227
  }
171
- this._taskByWorker.clear();
172
-
173
- // Terminate workers with a 5-second timeout to prevent hanging
174
- const TERMINATE_TIMEOUT_MS = 5000;
175
- await Promise.all(
176
- this._workers.map((w) =>
177
- Promise.race([
178
- w.terminate(),
179
- new Promise((resolve) => {
180
- const timer = setTimeout(resolve, TERMINATE_TIMEOUT_MS);
181
- timer.unref();
182
- }),
183
- ])
184
- )
185
- );
186
- this._workers = [];
187
- this._idle = [];
188
- }
189
228
  }
190
-
191
229
  module.exports = FontTracerPool;
230
+ //# sourceMappingURL=FontTracerPool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FontTracerPool.js","sourceRoot":"","sources":["../src/FontTracerPool.ts"],"names":[],"mappings":"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"}
@@ -13,8 +13,12 @@ async function transferResults(jsHandle) {
13
13
  const results = await jsHandle.jsonValue();
14
14
  for (const [i, result] of results.entries()) {
15
15
  const resultHandle = await jsHandle.getProperty(String(i));
16
- const elementHandle = await resultHandle.getProperty('node');
17
- result.node = elementHandle;
16
+ try {
17
+ const elementHandle = await resultHandle.getProperty('node');
18
+ result.node = elementHandle;
19
+ } finally {
20
+ await resultHandle.dispose();
21
+ }
18
22
  }
19
23
  return results;
20
24
  }
@@ -193,7 +197,11 @@ class HeadlessBrowser {
193
197
  /* istanbul ignore next */
194
198
  () => fontTracer(document)
195
199
  );
196
- return await transferResults(jsHandle);
200
+ try {
201
+ return await transferResults(jsHandle);
202
+ } finally {
203
+ await jsHandle.dispose();
204
+ }
197
205
  } finally {
198
206
  await page.close();
199
207
  }
package/lib/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}