Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recompile speedups #55

Merged
merged 3 commits into from
Nov 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,13 @@ Accepts a function that will have one argument: an array of eslint messages (obj

Lint only changed files, skip lint on start.

#### `threads`

- Type: `Boolean | Number`
- Default: `false`

Will run lint tasks across a thread pool. The pool size is automatic unless you specify a number.

### Errors and Warning

**By default the plugin will auto adjust error reporting depending on eslint errors/warnings counts.**
Expand Down
1 change: 1 addition & 0 deletions declarations/utils.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ export function parseFoldersToGlobs(
patterns: string | string[],
extensions?: string | string[]
): string[];
export function jsonStringifyReplacerSortKeys(_: string, value: any): any;
40 changes: 34 additions & 6 deletions src/getESLint.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import os from 'os';
import JestWorker from 'jest-worker';

import { getESLintOptions } from './options';
import { jsonStringifyReplacerSortKeys } from './utils';

/** @type {{[key: string]: any}} */
const cache = {};

/** @typedef {import('eslint').ESLint} ESLint */
/** @typedef {import('eslint').ESLint.LintResult} LintResult */
Expand Down Expand Up @@ -47,6 +51,7 @@ export function loadESLint(options) {
* @returns {Linter}
*/
export function loadESLintThreaded(poolSize, options) {
const key = getCacheKey(options);
const { eslintPath = 'eslint' } = options;
const source = require.resolve('./worker');
const workerOptions = {
Expand All @@ -57,18 +62,28 @@ export function loadESLintThreaded(poolSize, options) {

const local = loadESLint(options);

/** @type {Worker} */
/** @type {Worker?} */
// prettier-ignore
const worker = (/** @type {Worker} */ new JestWorker(source, workerOptions));
let worker = (/** @type {Worker} */ new JestWorker(source, workerOptions));

return {
/** @type {Linter} */
const context = {
...local,
threads: poolSize,
lintFiles: (files) => worker.lintFiles(files),
lintFiles: async (files) =>
(worker && (await worker.lintFiles(files))) ||
/* istanbul ignore next */ [],
cleanup: async () => {
worker.end();
cache[key] = local;
context.lintFiles = (files) => local.lintFiles(files);
if (worker) {
worker.end();
worker = null;
}
},
};

return context;
}

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

return max > 1 ? loadESLintThreaded(max, options) : loadESLint(options);
const key = getCacheKey({ threads, ...options });
if (!cache[key]) {
cache[key] =
max > 1 ? loadESLintThreaded(max, options) : loadESLint(options);
}
return cache[key];
}

/**
* @param {Options} options
* @returns {string}
*/
function getCacheKey(options) {
return JSON.stringify(options, jsonStringifyReplacerSortKeys);
}
1 change: 0 additions & 1 deletion src/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ import schema from './options.json';
export function getOptions(pluginOptions) {
const options = {
extensions: 'js',
threads: true,
...pluginOptions,
};

Expand Down
2 changes: 1 addition & 1 deletion src/options.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
]
},
"threads": {
"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.",
"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.",
"anyOf": [{ "type": "number" }, { "type": "boolean" }]
}
}
Expand Down
21 changes: 21 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,24 @@ export function parseFoldersToGlobs(patterns, extensions = []) {
return pattern;
});
}

/**
*
* @param {string} _ key, but unused
* @param {any} value
*/
export const jsonStringifyReplacerSortKeys = (_, value) => {
/**
* @param {{ [x: string]: any; }} sorted
* @param {string | number} key
*/
const insert = (sorted, key) => {
// eslint-disable-next-line no-param-reassign
sorted[key] = value[key];
return sorted;
};

return value instanceof Object && !(value instanceof Array)
? Object.keys(value).sort().reduce(insert, {})
: value;
};
2 changes: 2 additions & 0 deletions test/utils/conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export default (entry, pluginConf = {}, webpackConf = {}) => {
// folder to skip it on the global linting, but here we want the opposite
// (we only use .eslintignore on the test that checks this)
ignore: false,
// TODO: update tests to run both states: test.each([[{threads: false}], [{threads: true}]])('it should...', async ({threads}) => {...})
threads: true,
...pluginConf,
}),
],
Expand Down