From a6f49ef684ec0b0feb3e2d3b38446241575725d5 Mon Sep 17 00:00:00 2001 From: Ricardo Gobbo de Souza Date: Thu, 21 Jan 2021 15:31:10 -0300 Subject: [PATCH 1/2] fix: threads multi-compiler --- src/getESLint.js | 25 ++++++++++++++----------- src/index.js | 3 ++- src/linter.js | 5 +++-- test/threads.test.js | 4 ++-- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/getESLint.js b/src/getESLint.js index c8a3816..8b92f08 100644 --- a/src/getESLint.js +++ b/src/getESLint.js @@ -46,12 +46,13 @@ export function loadESLint(options) { } /** + * @param {string} key * @param {number} poolSize * @param {Options} options * @returns {Linter} */ -export function loadESLintThreaded(poolSize, options) { - const key = getCacheKey(options); +export function loadESLintThreaded(key, poolSize, options) { + const cacheKey = getCacheKey(key, options); const { eslintPath = 'eslint' } = options; const source = require.resolve('./worker'); const workerOptions = { @@ -74,7 +75,7 @@ export function loadESLintThreaded(poolSize, options) { (worker && (await worker.lintFiles(files))) || /* istanbul ignore next */ [], cleanup: async () => { - cache[key] = local; + cache[cacheKey] = local; context.lintFiles = (files) => local.lintFiles(files); if (worker) { worker.end(); @@ -87,10 +88,11 @@ export function loadESLintThreaded(poolSize, options) { } /** + * @param {string} key * @param {Options} options * @returns {Linter} */ -export default function getESLint({ threads, ...options }) { +export default function getESLint(key, { threads, ...options }) { const max = typeof threads !== 'number' ? threads @@ -99,18 +101,19 @@ export default function getESLint({ threads, ...options }) { : /* istanbul ignore next */ threads; - const key = getCacheKey({ threads, ...options }); - if (!cache[key]) { - cache[key] = - max > 1 ? loadESLintThreaded(max, options) : loadESLint(options); + const cacheKey = getCacheKey(key, { threads, ...options }); + if (!cache[cacheKey]) { + cache[cacheKey] = + max > 1 ? loadESLintThreaded(key, max, options) : loadESLint(options); } - return cache[key]; + return cache[cacheKey]; } /** + * @param {string} key * @param {Options} options * @returns {string} */ -function getCacheKey(options) { - return JSON.stringify(options, jsonStringifyReplacerSortKeys); +function getCacheKey(key, options) { + return JSON.stringify({ key, options }, jsonStringifyReplacerSortKeys); } diff --git a/src/index.js b/src/index.js index ad70f07..a7440f5 100644 --- a/src/index.js +++ b/src/index.js @@ -17,6 +17,7 @@ export class ESLintWebpackPlugin { * @param {Options} options */ constructor(options = {}) { + this.key = Math.random().toString(); this.options = getOptions(options); this.run = this.run.bind(this); } @@ -72,7 +73,7 @@ export class ESLintWebpackPlugin { let report; try { - ({ lint, report } = linter(options, compilation)); + ({ lint, report } = linter(this.key, options, compilation)); } catch (e) { compilation.errors.push(e); return; diff --git a/src/linter.js b/src/linter.js index 02e3058..443dbbe 100644 --- a/src/linter.js +++ b/src/linter.js @@ -21,11 +21,12 @@ import getESLint from './getESLint'; const resultStorage = new WeakMap(); /** + * @param {string} key * @param {Options} options * @param {Compilation} compilation * @returns {{lint: Linter, report: Reporter}} */ -export default function linter(options, compilation) { +export default function linter(key, options, compilation) { /** @type {ESLint} */ let eslint; @@ -41,7 +42,7 @@ export default function linter(options, compilation) { const crossRunResultStorage = getResultStorage(compilation); try { - ({ eslint, lintFiles, cleanup } = getESLint(options)); + ({ eslint, lintFiles, cleanup } = getESLint(key, options)); } catch (e) { throw new ESLintError(e.message); } diff --git a/test/threads.test.js b/test/threads.test.js index 820ec34..0a60689 100644 --- a/test/threads.test.js +++ b/test/threads.test.js @@ -6,7 +6,7 @@ import { loadESLint, loadESLintThreaded } from '../src/getESLint'; describe('Threading', () => { test('Threaded interface should look like non-threaded interface', async () => { const single = loadESLint({}); - const threaded = loadESLintThreaded(1, {}); + const threaded = loadESLintThreaded('foo', 1, {}); for (const key of Object.keys(single)) { expect(typeof single[key]).toEqual(typeof threaded[key]); } @@ -21,7 +21,7 @@ describe('Threading', () => { }); test('Threaded should lint files', async () => { - const threaded = loadESLintThreaded(1, { ignore: false }); + const threaded = loadESLintThreaded('bar', 1, { ignore: false }); try { const [good, bad] = await Promise.all([ threaded.lintFiles(join(__dirname, 'fixtures/good.js')), From 78307ea03fd6ab64af7d2bac456d1b3ea2f39687 Mon Sep 17 00:00:00 2001 From: Ricardo Gobbo de Souza Date: Fri, 22 Jan 2021 08:51:20 -0300 Subject: [PATCH 2/2] fix: set key in apply --- declarations/getESLint.d.ts | 13 +++++++++++-- declarations/index.d.ts | 1 + declarations/linter.d.ts | 2 ++ src/getESLint.js | 6 +++--- src/index.js | 8 +++++++- src/linter.js | 2 +- 6 files changed, 25 insertions(+), 7 deletions(-) diff --git a/declarations/getESLint.d.ts b/declarations/getESLint.d.ts index f555f3c..3ed9274 100644 --- a/declarations/getESLint.d.ts +++ b/declarations/getESLint.d.ts @@ -11,16 +11,25 @@ */ export function loadESLint(options: Options): Linter; /** + * @param {string|undefined} key * @param {number} poolSize * @param {Options} options * @returns {Linter} */ -export function loadESLintThreaded(poolSize: number, options: Options): Linter; +export function loadESLintThreaded( + key: string | undefined, + poolSize: number, + options: Options +): Linter; /** + * @param {string|undefined} key * @param {Options} options * @returns {Linter} */ -export default function getESLint({ threads, ...options }: Options): Linter; +export default function getESLint( + key: string | undefined, + { threads, ...options }: Options +): Linter; export type ESLint = import('eslint').ESLint; export type LintResult = import('eslint').ESLint.LintResult; export type Options = import('./options').PluginOptions & diff --git a/declarations/index.d.ts b/declarations/index.d.ts index 7c16f5e..7ae2022 100644 --- a/declarations/index.d.ts +++ b/declarations/index.d.ts @@ -13,6 +13,7 @@ export class ESLintWebpackPlugin { * @returns {void} */ apply(compiler: Compiler): void; + key: string | undefined; /** * * @param {Compiler} compiler diff --git a/declarations/linter.d.ts b/declarations/linter.d.ts index 3368c35..752a79f 100644 --- a/declarations/linter.d.ts +++ b/declarations/linter.d.ts @@ -1,9 +1,11 @@ /** + * @param {string|undefined} key * @param {Options} options * @param {Compilation} compilation * @returns {{lint: Linter, report: Reporter}} */ export default function linter( + key: string | undefined, options: Options, compilation: Compilation ): { diff --git a/src/getESLint.js b/src/getESLint.js index 8b92f08..fe27f1b 100644 --- a/src/getESLint.js +++ b/src/getESLint.js @@ -46,7 +46,7 @@ export function loadESLint(options) { } /** - * @param {string} key + * @param {string|undefined} key * @param {number} poolSize * @param {Options} options * @returns {Linter} @@ -88,7 +88,7 @@ export function loadESLintThreaded(key, poolSize, options) { } /** - * @param {string} key + * @param {string|undefined} key * @param {Options} options * @returns {Linter} */ @@ -110,7 +110,7 @@ export default function getESLint(key, { threads, ...options }) { } /** - * @param {string} key + * @param {string|undefined} key * @param {Options} options * @returns {string} */ diff --git a/src/index.js b/src/index.js index a7440f5..f1b9ca4 100644 --- a/src/index.js +++ b/src/index.js @@ -11,13 +11,13 @@ import { parseFiles, parseFoldersToGlobs } from './utils'; /** @typedef {import('./options').Options} Options */ const ESLINT_PLUGIN = 'ESLintWebpackPlugin'; +let counter = 0; export class ESLintWebpackPlugin { /** * @param {Options} options */ constructor(options = {}) { - this.key = Math.random().toString(); this.options = getOptions(options); this.run = this.run.bind(this); } @@ -27,6 +27,12 @@ export class ESLintWebpackPlugin { * @returns {void} */ apply(compiler) { + // Generate key for each compilation, + // this differentiates one from the other when being cached. + this.key = compiler.name || `${ESLINT_PLUGIN}_${(counter += 1)}`; + + // If `lintDirtyModulesOnly` is disabled, + // execute the linter on the build if (!this.options.lintDirtyModulesOnly) { compiler.hooks.run.tapPromise(ESLINT_PLUGIN, this.run); } diff --git a/src/linter.js b/src/linter.js index 443dbbe..cc83be8 100644 --- a/src/linter.js +++ b/src/linter.js @@ -21,7 +21,7 @@ import getESLint from './getESLint'; const resultStorage = new WeakMap(); /** - * @param {string} key + * @param {string|undefined} key * @param {Options} options * @param {Compilation} compilation * @returns {{lint: Linter, report: Reporter}}