Skip to content

Commit 2fc0a3c

Browse files
committed
fix(gatsby): use separate eslint-loader for rules that are always required (#29317)
* fix(gatsby): use separate eslint-loader for rules that are always required * Add the second loader only when custom eslint config is set (cherry picked from commit a1543bf)
1 parent 7797522 commit 2fc0a3c

File tree

4 files changed

+39
-236
lines changed

4 files changed

+39
-236
lines changed

packages/gatsby/src/utils/__tests__/eslint-config.ts

-130
This file was deleted.

packages/gatsby/src/utils/eslint-config.ts

+5-41
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@ const eslintRequirePreset = require.resolve(`./eslint/required`)
88
export const eslintRequiredConfig: CLIEngine.Options = {
99
rulePaths: [eslintRulePaths],
1010
useEslintrc: false,
11+
allowInlineConfig: false,
12+
// @ts-ignore
13+
emitWarning: true,
1114
baseConfig: {
15+
parser: require.resolve(`babel-eslint`),
1216
parserOptions: {
13-
ecmaVersion: 2018,
17+
ecmaVersion: 2020,
1418
sourceType: `module`,
1519
ecmaFeatures: {
1620
jsx: true,
@@ -25,46 +29,6 @@ export const eslintRequiredConfig: CLIEngine.Options = {
2529
},
2630
}
2731

28-
export function mergeRequiredConfigIn(
29-
existingOptions: CLIEngine.Options
30-
): void {
31-
// make sure rulePaths include our custom rules
32-
if (existingOptions.rulePaths) {
33-
if (
34-
Array.isArray(existingOptions.rulePaths) &&
35-
!existingOptions.rulePaths.includes(eslintRulePaths)
36-
) {
37-
existingOptions.rulePaths.push(eslintRulePaths)
38-
}
39-
} else {
40-
existingOptions.rulePaths = [eslintRulePaths]
41-
}
42-
43-
// make sure we extend required preset
44-
if (!existingOptions.baseConfig) {
45-
existingOptions.baseConfig = {}
46-
}
47-
48-
if (existingOptions.baseConfig.extends) {
49-
if (
50-
Array.isArray(existingOptions.baseConfig.extends) &&
51-
!existingOptions.baseConfig.extends.includes(eslintRequirePreset)
52-
) {
53-
existingOptions.baseConfig.extends.push(eslintRequirePreset)
54-
} else if (
55-
typeof existingOptions.baseConfig.extends === `string` &&
56-
existingOptions.baseConfig.extends !== eslintRequirePreset
57-
) {
58-
existingOptions.baseConfig.extends = [
59-
existingOptions.baseConfig.extends,
60-
eslintRequirePreset,
61-
]
62-
}
63-
} else {
64-
existingOptions.baseConfig.extends = [eslintRequirePreset]
65-
}
66-
}
67-
6832
export const eslintConfig = (
6933
schema: GraphQLSchema,
7034
usingJsxRuntime: boolean

packages/gatsby/src/utils/webpack-utils.ts

+21-52
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,7 @@ import {
2020

2121
import { builtinPlugins } from "./webpack-plugins"
2222
import { IProgram, Stage } from "../commands/types"
23-
import {
24-
eslintConfig,
25-
mergeRequiredConfigIn,
26-
eslintRequiredConfig,
27-
} from "./eslint-config"
23+
import { eslintConfig, eslintRequiredConfig } from "./eslint-config"
2824

2925
type LoaderResolver<T = {}> = (options?: T) => Loader
3026

@@ -69,6 +65,7 @@ interface ILoaderUtils {
6965
exports: LoaderResolver
7066

7167
eslint(schema: GraphQLSchema): Loader
68+
eslintRequired(): Loader
7269
}
7370

7471
interface IModuleThatUseGatsby {
@@ -103,6 +100,7 @@ interface IRuleUtils {
103100
postcss: ContextualRuleFactory<{ overrideBrowserOptions: Array<string> }>
104101

105102
eslint: (schema: GraphQLSchema) => RuleSetRule
103+
eslintRequired: () => RuleSetRule
106104
}
107105

108106
type PluginUtils = BuiltinPlugins & {
@@ -335,6 +333,13 @@ export const createWebpackUtils = (
335333
}
336334
},
337335

336+
eslintRequired: () => {
337+
return {
338+
options: eslintRequiredConfig,
339+
loader: require.resolve(`eslint-loader`),
340+
}
341+
},
342+
338343
imports: (options = {}) => {
339344
return {
340345
options,
@@ -496,6 +501,17 @@ export const createWebpackUtils = (
496501
}
497502
}
498503

504+
rules.eslintRequired = (): RuleSetRule => {
505+
return {
506+
enforce: `pre`,
507+
test: /\.jsx?$/,
508+
exclude: (modulePath: string): boolean =>
509+
modulePath.includes(VIRTUAL_MODULES_BASE_PATH) ||
510+
vendorRegex.test(modulePath),
511+
use: [loaders.eslintRequired()],
512+
}
513+
}
514+
499515
rules.yaml = (): RuleSetRule => {
500516
return {
501517
test: /\.ya?ml$/,
@@ -754,50 +770,3 @@ export function reactHasJsxRuntime(): boolean {
754770

755771
return false
756772
}
757-
758-
export function ensureRequireEslintRules(config: Configuration): Configuration {
759-
if (!config.module) {
760-
config.module = {
761-
rules: [],
762-
}
763-
}
764-
// for fast refresh we want to ensure that that there is eslint rule running
765-
// because user might have added their own `eslint-loader` let's check if there is one
766-
// and adjust it to add the rule or append new loader with required rule
767-
const rule = config.module.rules.find(rule => {
768-
if (typeof rule.loader === `string`) {
769-
return (
770-
rule.loader === `eslint-loader` ||
771-
rule.loader.endsWith(`eslint-loader/index.js`) ||
772-
rule.loader.endsWith(`eslint-loader/dist/cjs.js`)
773-
)
774-
}
775-
776-
return false
777-
})
778-
779-
if (rule) {
780-
if (typeof rule.options !== `string`) {
781-
if (!rule.options) {
782-
rule.options = {}
783-
}
784-
mergeRequiredConfigIn(rule.options)
785-
}
786-
} else {
787-
config.module.rules.push({
788-
enforce: `pre`,
789-
test: /\.jsx?$/,
790-
exclude: (modulePath: string): boolean =>
791-
modulePath.includes(VIRTUAL_MODULES_BASE_PATH) ||
792-
vendorRegex.test(modulePath),
793-
use: [
794-
{
795-
loader: require.resolve(`eslint-loader`),
796-
options: eslintRequiredConfig,
797-
},
798-
],
799-
})
800-
}
801-
802-
return config
803-
}

packages/gatsby/src/utils/webpack.config.js

+13-13
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const report = require(`gatsby-cli/lib/reporter`)
1515
import { withBasePath, withTrailingSlash } from "./path"
1616
import { getGatsbyDependents } from "./gatsby-dependents"
1717
const apiRunnerNode = require(`./api-runner-node`)
18-
import { createWebpackUtils, ensureRequireEslintRules } from "./webpack-utils"
18+
import { createWebpackUtils } from "./webpack-utils"
1919
import { hasLocalEslint } from "./local-eslint-config-finder"
2020
import { getAbsolutePathForVirtualModule } from "./gatsby-webpack-virtual-modules"
2121

@@ -339,11 +339,21 @@ module.exports = async (
339339
// get schema to pass to eslint config and program for directory
340340
const { schema, program } = store.getState()
341341

342+
const isCustomEslint = hasLocalEslint(program.directory)
343+
342344
// if no local eslint config, then add gatsby config
343-
if (!hasLocalEslint(program.directory)) {
345+
if (!isCustomEslint) {
344346
configRules = configRules.concat([rules.eslint(schema)])
345347
}
346348

349+
// Enforce fast-refresh rules even with local eslint config
350+
if (
351+
isCustomEslint &&
352+
process.env.GATSBY_HOT_LOADER === `fast-refresh`
353+
) {
354+
configRules = configRules.concat([rules.eslintRequired()])
355+
}
356+
347357
configRules = configRules.concat([
348358
{
349359
oneOf: [rules.cssModules(), rules.css()],
@@ -732,15 +742,5 @@ module.exports = async (
732742
parentSpan,
733743
})
734744

735-
let finalConfig = getConfig()
736-
737-
if (
738-
stage === `develop` &&
739-
process.env.GATSBY_HOT_LOADER === `fast-refresh` &&
740-
hasLocalEslint(program.directory)
741-
) {
742-
finalConfig = ensureRequireEslintRules(finalConfig)
743-
}
744-
745-
return finalConfig
745+
return getConfig()
746746
}

0 commit comments

Comments
 (0)