Skip to content

Commit 4e6bcf4

Browse files
committed
feature #574 Proposal to replace #504 (ESLint/Vue) (Kocal)
This PR was squashed before being merged into the master branch. Discussion ---------- Proposal to replace #504 (ESLint/Vue) This PR add a second argument to `Encore.enableEslintLoader()` that is used to let the ESLint loader lint `.vue` files: ```js Encore.enableEslintLoader(() => {}, { lintVue: true }); ``` Using `lintVue` won't add any ESLint configuration, that the job of the final user (see #504 (comment)). **EDIT:** While #657 is being discussed, you can use the following code to: - let ESLint process your `.vue` files - prevent the error `Use the latest vue-eslint-parser.`, see #656 ```js Encore.enableEslintLoader((options) => { delete options.parser; }, { lintVue: true }); ``` **EDIT 2:** PR #687 has been merged and issue #657 is now resolved. It means that you can use the following code to let eslint-loader handle `.vue` files: ```js Encore.enableEslintLoader(() => {}, { lintVue: true }); ``` Commits ------- 13b0750 chore: remove comment for vue files linting since #687 has been merged 2f1e85b chore: add comment for making .vue files lint working 12b3f77 eslint/vue: add 2nd parameter to Encore#enableEslintLoader eb85b24 eslint/vue: tweak config-generator aa782df eslint/vue: implement `getTest()` on ESlint loader helper bc444ff eslint/vue: tweak `WebpackConfig#enableEslintLoader()`
2 parents 0168b0b + 13b0750 commit 4e6bcf4

File tree

7 files changed

+92
-14
lines changed

7 files changed

+92
-14
lines changed

index.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,13 +1192,27 @@ class Encore {
11921192
* options.extends = 'airbnb';
11931193
* options.emitWarning = false;
11941194
* });
1195+
*
1196+
* // configure Encore-specific options
1197+
* Encore.enableEslintLoader(() => {}, {
1198+
* // set optional Encore-specific options, for instance:
1199+
*
1200+
* // lint `.vue` files
1201+
* lintVue: true
1202+
* });
1203+
* ```
1204+
*
1205+
* Supported options:
1206+
* * {boolean} lintVue (default=false)
1207+
* Configure the loader to lint `.vue` files
11951208
* ```
11961209
*
11971210
* @param {string|object|function} eslintLoaderOptionsOrCallback
1211+
* @param {object} encoreOptions
11981212
* @returns {Encore}
11991213
*/
1200-
enableEslintLoader(eslintLoaderOptionsOrCallback = () => {}) {
1201-
webpackConfig.enableEslintLoader(eslintLoaderOptionsOrCallback);
1214+
enableEslintLoader(eslintLoaderOptionsOrCallback = () => {}, encoreOptions = {}) {
1215+
webpackConfig.enableEslintLoader(eslintLoaderOptionsOrCallback, encoreOptions);
12021216

12031217
return this;
12041218
}

lib/WebpackConfig.js

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ class WebpackConfig {
137137
this.vueOptions = {
138138
useJsx: false,
139139
};
140+
this.eslintOptions = {
141+
lintVue: false,
142+
};
140143

141144
// Features/Loaders options callbacks
142145
this.postCssLoaderOptionsCallback = () => {};
@@ -751,31 +754,33 @@ class WebpackConfig {
751754
this.vueOptions = vueOptions;
752755
}
753756

754-
enableEslintLoader(eslintLoaderOptionsOrCallback = () => {}) {
757+
enableEslintLoader(eslintLoaderOptionsOrCallback = () => {}, eslintOptions = {}) {
755758
this.useEslintLoader = true;
756759

757760
if (typeof eslintLoaderOptionsOrCallback === 'function') {
758761
this.eslintLoaderOptionsCallback = eslintLoaderOptionsOrCallback;
759-
return;
760-
}
761-
762-
if (typeof eslintLoaderOptionsOrCallback === 'string') {
762+
} else if (typeof eslintLoaderOptionsOrCallback === 'string') {
763763
logger.deprecation('enableEslintLoader: Extending from a configuration is deprecated, please use a configuration file instead. See https://eslint.org/docs/user-guide/configuring for more information.');
764764

765765
this.eslintLoaderOptionsCallback = (options) => {
766766
options.extends = eslintLoaderOptionsOrCallback;
767767
};
768-
return;
769-
}
770-
771-
if (typeof eslintLoaderOptionsOrCallback === 'object') {
768+
} else if (typeof eslintLoaderOptionsOrCallback === 'object') {
772769
this.eslintLoaderOptionsCallback = (options) => {
773770
Object.assign(options, eslintLoaderOptionsOrCallback);
774771
};
775-
return;
772+
} else {
773+
throw new Error('Argument 1 to enableEslintLoader() must be either a string, object or callback function.');
774+
}
775+
776+
// Check allowed keys
777+
for (const key of Object.keys(eslintOptions)) {
778+
if (!(key in this.eslintOptions)) {
779+
throw new Error(`"${key}" is not a valid key for enableEslintLoader(). Valid keys: ${Object.keys(this.eslintOptions).join(', ')}.`);
780+
}
776781
}
777782

778-
throw new Error('Argument 1 to enableEslintLoader() must be either a string, object or callback function.');
783+
this.eslintOptions = eslintOptions;
779784
}
780785

781786
enableBuildNotifications(enabled = true, notifierPluginOptionsCallback = () => {}) {

lib/config-generator.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ class ConfigGenerator {
393393

394394
if (this.webpackConfig.useEslintLoader) {
395395
rules.push(applyRuleConfigurationCallback('eslint', {
396-
test: /\.jsx?$/,
396+
test: eslintLoaderUtil.getTest(this.webpackConfig),
397397
loader: 'eslint-loader',
398398
exclude: /node_modules/,
399399
enforce: 'pre',

lib/loaders/eslint.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,5 +69,19 @@ Install ${chalk.yellow('babel-eslint')} to prevent potential parsing issues: ${p
6969
};
7070

7171
return applyOptionsCallback(webpackConfig.eslintLoaderOptionsCallback, eslintLoaderOptions);
72+
},
73+
74+
/**
75+
* @param {WebpackConfig} webpackConfig
76+
* @return {RegExp} to use for eslint-loader `test` rule
77+
*/
78+
getTest(webpackConfig) {
79+
const extensions = ['jsx?'];
80+
81+
if (webpackConfig.eslintOptions.lintVue) {
82+
extensions.push('vue');
83+
}
84+
85+
return new RegExp(`\\.(${extensions.join('|')})$`);
7286
}
7387
};

test/WebpackConfig.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,4 +1395,16 @@ describe('WebpackConfig object', () => {
13951395
expect(() => config.enableIntegrityHashes(true, ['sha1', 'foo', 'sha256'])).to.throw('Invalid hash algorithm "foo"');
13961396
});
13971397
});
1398+
1399+
describe('enableEslintLoader', () => {
1400+
it('Should validate Encore-specific options', () => {
1401+
const config = createConfig();
1402+
1403+
expect(() => {
1404+
config.enableEslintLoader(() => {}, {
1405+
notExisting: false,
1406+
});
1407+
}).to.throw('"notExisting" is not a valid key for enableEslintLoader(). Valid keys: lintVue.');
1408+
});
1409+
});
13981410
});

test/config-generator.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,22 @@ describe('The config-generator function', () => {
416416
expect(JSON.stringify(actualConfig.module.rules)).to.contain('eslint-loader');
417417
expect(JSON.stringify(actualConfig.module.rules)).to.contain('extends-name');
418418
});
419+
420+
it('enableEslintLoader(() => {}, {lintVue: true})', () => {
421+
const config = createConfig();
422+
config.addEntry('main', './main');
423+
config.publicPath = '/';
424+
config.outputPath = '/tmp';
425+
config.enableEslintLoader(() => {}, {
426+
lintVue: true,
427+
});
428+
429+
const actualConfig = configGenerator(config);
430+
expect(JSON.stringify(actualConfig.module.rules)).to.contain('eslint-loader');
431+
432+
const eslintRule = findRule(/\.(jsx?|vue)$/, actualConfig.module.rules);
433+
expect(eslintRule.test.toString()).to.equal(/\.(jsx?|vue)$/.toString());
434+
});
419435
});
420436

421437
describe('addLoader() adds a custom loader', () => {

test/loaders/eslint.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,21 @@ describe('loaders/eslint', () => {
7474
const actualOptions = eslintLoader.getOptions(config);
7575
expect(actualOptions).to.deep.equals({ foo: true });
7676
});
77+
78+
it('getTest() base behavior', () => {
79+
const config = createConfig();
80+
81+
const actualTest = eslintLoader.getTest(config);
82+
expect(actualTest.toString()).to.equals(/\.(jsx?)$/.toString());
83+
});
84+
85+
it('getTest() with Vue', () => {
86+
const config = createConfig();
87+
config.enableEslintLoader(() => {}, {
88+
lintVue: true,
89+
});
90+
91+
const actualTest = eslintLoader.getTest(config);
92+
expect(actualTest.toString()).to.equals(/\.(jsx?|vue)$/.toString());
93+
});
7794
});

0 commit comments

Comments
 (0)