Skip to content

Commit d862d92

Browse files
fix: recompile speedups (#55)
* fix: don't use threads after intial build * fix: flip threads default * docs: move `threads` option Co-authored-by: Ricardo Gobbo de Souza <[email protected]>
1 parent bdb5210 commit d862d92

File tree

7 files changed

+66
-8
lines changed

7 files changed

+66
-8
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,13 @@ Accepts a function that will have one argument: an array of eslint messages (obj
159159

160160
Lint only changed files, skip lint on start.
161161

162+
#### `threads`
163+
164+
- Type: `Boolean | Number`
165+
- Default: `false`
166+
167+
Will run lint tasks across a thread pool. The pool size is automatic unless you specify a number.
168+
162169
### Errors and Warning
163170

164171
**By default the plugin will auto adjust error reporting depending on eslint errors/warnings counts.**

declarations/utils.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ export function parseFoldersToGlobs(
1818
patterns: string | string[],
1919
extensions?: string | string[]
2020
): string[];
21+
export function jsonStringifyReplacerSortKeys(_: string, value: any): any;

src/getESLint.js

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ import os from 'os';
33
import JestWorker from 'jest-worker';
44

55
import { getESLintOptions } from './options';
6+
import { jsonStringifyReplacerSortKeys } from './utils';
7+
8+
/** @type {{[key: string]: any}} */
9+
const cache = {};
610

711
/** @typedef {import('eslint').ESLint} ESLint */
812
/** @typedef {import('eslint').ESLint.LintResult} LintResult */
@@ -47,6 +51,7 @@ export function loadESLint(options) {
4751
* @returns {Linter}
4852
*/
4953
export function loadESLintThreaded(poolSize, options) {
54+
const key = getCacheKey(options);
5055
const { eslintPath = 'eslint' } = options;
5156
const source = require.resolve('./worker');
5257
const workerOptions = {
@@ -57,18 +62,28 @@ export function loadESLintThreaded(poolSize, options) {
5762

5863
const local = loadESLint(options);
5964

60-
/** @type {Worker} */
65+
/** @type {Worker?} */
6166
// prettier-ignore
62-
const worker = (/** @type {Worker} */ new JestWorker(source, workerOptions));
67+
let worker = (/** @type {Worker} */ new JestWorker(source, workerOptions));
6368

64-
return {
69+
/** @type {Linter} */
70+
const context = {
6571
...local,
6672
threads: poolSize,
67-
lintFiles: (files) => worker.lintFiles(files),
73+
lintFiles: async (files) =>
74+
(worker && (await worker.lintFiles(files))) ||
75+
/* istanbul ignore next */ [],
6876
cleanup: async () => {
69-
worker.end();
77+
cache[key] = local;
78+
context.lintFiles = (files) => local.lintFiles(files);
79+
if (worker) {
80+
worker.end();
81+
worker = null;
82+
}
7083
},
7184
};
85+
86+
return context;
7287
}
7388

7489
/**
@@ -84,5 +99,18 @@ export default function getESLint({ threads, ...options }) {
8499
: /* istanbul ignore next */
85100
threads;
86101

87-
return max > 1 ? loadESLintThreaded(max, options) : loadESLint(options);
102+
const key = getCacheKey({ threads, ...options });
103+
if (!cache[key]) {
104+
cache[key] =
105+
max > 1 ? loadESLintThreaded(max, options) : loadESLint(options);
106+
}
107+
return cache[key];
108+
}
109+
110+
/**
111+
* @param {Options} options
112+
* @returns {string}
113+
*/
114+
function getCacheKey(options) {
115+
return JSON.stringify(options, jsonStringifyReplacerSortKeys);
88116
}

src/options.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ import schema from './options.json';
4747
export function getOptions(pluginOptions) {
4848
const options = {
4949
extensions: 'js',
50-
threads: true,
5150
...pluginOptions,
5251
};
5352

src/options.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@
7777
]
7878
},
7979
"threads": {
80-
"description": "Set to true to auto-selected based on number of cpus. Set to a number greater than 1 to set an explicit maximum. Set to false, 1 or less to disable and only run in main process.",
80+
"description": "Default is false. Set to true for an auto-selected pool size based on number of cpus. Set to a number greater than 1 to set an explicit pool size. Set to false, 1, or less to disable and only run in main process.",
8181
"anyOf": [{ "type": "number" }, { "type": "boolean" }]
8282
}
8383
}

src/utils.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,24 @@ export function parseFoldersToGlobs(patterns, extensions = []) {
6060
return pattern;
6161
});
6262
}
63+
64+
/**
65+
*
66+
* @param {string} _ key, but unused
67+
* @param {any} value
68+
*/
69+
export const jsonStringifyReplacerSortKeys = (_, value) => {
70+
/**
71+
* @param {{ [x: string]: any; }} sorted
72+
* @param {string | number} key
73+
*/
74+
const insert = (sorted, key) => {
75+
// eslint-disable-next-line no-param-reassign
76+
sorted[key] = value[key];
77+
return sorted;
78+
};
79+
80+
return value instanceof Object && !(value instanceof Array)
81+
? Object.keys(value).sort().reduce(insert, {})
82+
: value;
83+
};

test/utils/conf.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ export default (entry, pluginConf = {}, webpackConf = {}) => {
1818
// folder to skip it on the global linting, but here we want the opposite
1919
// (we only use .eslintignore on the test that checks this)
2020
ignore: false,
21+
// TODO: update tests to run both states: test.each([[{threads: false}], [{threads: true}]])('it should...', async ({threads}) => {...})
22+
threads: true,
2123
...pluginConf,
2224
}),
2325
],

0 commit comments

Comments
 (0)