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

Move from eslint-loader to eslint-webpack-plugin, close #847 #985

Merged
merged 1 commit into from
Jan 21, 2022
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
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
# CHANGELOG

## [v1.7.1](https://github.com/symfony/webpack-encore/releases/tag/v1.7.0)

*Jan 20th, 2022*

### Bug Fix

- [#1069](https://github.com/symfony/webpack-encore/pull/1069) - Increased webpack-cli version constraint to v.4.9.1 - *@nspyke*

## [v1.7.0](https://github.com/symfony/webpack-encore/releases/tag/v1.7.0)

*Dec 2nd, 2021*

Dependency changes:

* Official support for `ts-loader` 8 was dropped.
* Official support for `typescript` 8 was dropped and minimum increased to 4.2.2.
* Official support for `typescript` 3 was dropped and minimum increased to 4.2.2.
* Official support for `vue` was bumped to 3.2.14 or higher.
* Official support for `vue-loader` was bumped to 16.7.0 or higher.

Expand Down
33 changes: 33 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1269,6 +1269,7 @@ class Encore {
* Configure the loader to lint `.vue` files
* ```
*
* @deprecated Prefer using "Encore.enableEslintPlugin()" instead.
Kocal marked this conversation as resolved.
Show resolved Hide resolved
* @param {string|object|function} eslintLoaderOptionsOrCallback
* @param {object} encoreOptions
* @returns {Encore}
Expand All @@ -1279,6 +1280,38 @@ class Encore {
return this;
}

/**
* If enabled, the eslint-webpack-plugin is enabled.
*
* https://github.com/webpack-contrib/eslint-webpack-plugin
*
* ```
* // enables the eslint plugin using the default eslint configuration.
* Encore.enableEslintPlugin();
*
* // You can also pass in an object of options
* // that will be passed on to the eslint-webpack-plugin
* Encore.enableEslintPlugin({
* emitWarning: false
* });
*
* // For a more advanced usage you can pass in a callback
* // https://github.com/webpack-contrib/eslint-webpack-plugin#options
* Encore.enableEslintPlugin((options) => {
* options.extensions.push('vue'); // to lint Vue files
* options.emitWarning = false;
* });
* ```
*
* @param {string|object|function} eslintPluginOptionsOrCallback
* @returns {Encore}
*/
enableEslintPlugin(eslintPluginOptionsOrCallback = () => {}) {
webpackConfig.enableEslintPlugin(eslintPluginOptionsOrCallback);

return this;
}

/**
* If enabled, display build notifications using
* webpack-notifier.
Expand Down
26 changes: 26 additions & 0 deletions lib/WebpackConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ class WebpackConfig {
this.usePreact = false;
this.useVueLoader = false;
this.useEslintLoader = false;
this.useEslintPlugin = false;
this.useTypeScriptLoader = false;
this.useForkedTypeScriptTypeChecking = false;
this.useBabelTypeScriptPreset = false;
Expand Down Expand Up @@ -171,6 +172,7 @@ class WebpackConfig {
this.devServerOptionsConfigurationCallback = () => {};
this.vueLoaderOptionsCallback = () => {};
this.eslintLoaderOptionsCallback = () => {};
this.eslintPluginOptionsCallback = () => {};
this.tsConfigurationCallback = () => {};
this.handlebarsConfigurationCallback = () => {};
this.miniCssExtractLoaderConfigurationCallback = () => {};
Expand Down Expand Up @@ -803,6 +805,12 @@ class WebpackConfig {
}

enableEslintLoader(eslintLoaderOptionsOrCallback = () => {}, eslintOptions = {}) {
logger.deprecation('Encore.enableEslintLoader() is deprecated, please use Encore.enableEslintPlugin() instead.');

if (this.useEslintPlugin) {
throw new Error('Encore.enableEslintLoader() can not be called when Encore.enableEslintPlugin() has been called.');
}

this.useEslintLoader = true;

if (typeof eslintLoaderOptionsOrCallback === 'function') {
Expand Down Expand Up @@ -831,6 +839,24 @@ class WebpackConfig {
this.eslintOptions = eslintOptions;
}

enableEslintPlugin(eslintPluginOptionsOrCallback = () => {}) {
if (this.useEslintLoader) {
throw new Error('Encore.enableEslintPlugin() can not be called when Encore.enableEslintLoader() has been called.');
}

this.useEslintPlugin = true;

if (typeof eslintPluginOptionsOrCallback === 'function') {
this.eslintPluginOptionsCallback = eslintPluginOptionsOrCallback;
} else if (typeof eslintPluginOptionsOrCallback === 'object') {
this.eslintPluginOptionsCallback = (options) => {
Object.assign(options, eslintPluginOptionsOrCallback);
};
} else {
throw new Error('Argument 1 to enableEslintPlugin() must be either an object or callback function.');
}
}

enableBuildNotifications(enabled = true, notifierPluginOptionsCallback = () => {}) {
if (typeof notifierPluginOptionsCallback !== 'function') {
throw new Error('Argument 2 to enableBuildNotifications() must be a callback function.');
Expand Down
3 changes: 3 additions & 0 deletions lib/config-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const vuePluginUtil = require('./plugins/vue');
const friendlyErrorPluginUtil = require('./plugins/friendly-errors');
const assetOutputDisplay = require('./plugins/asset-output-display');
const notifierPluginUtil = require('./plugins/notifier');
const eslintPluginUtil = require('./plugins/eslint');
const PluginPriorities = require('./plugins/plugin-priorities');
const applyOptionsCallback = require('./utils/apply-options-callback');
const copyEntryTmpName = require('./utils/copyEntryTmpName');
Expand Down Expand Up @@ -454,6 +455,8 @@ class ConfigGenerator {

vuePluginUtil(plugins, this.webpackConfig);

eslintPluginUtil(plugins, this.webpackConfig);

if (!this.webpackConfig.runtimeConfig.outputJson) {
const friendlyErrorPlugin = friendlyErrorPluginUtil(this.webpackConfig);
plugins.push({
Expand Down
9 changes: 9 additions & 0 deletions lib/features.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,15 @@ const features = {
],
description: 'Enable ESLint checks'
},
eslint_plugin: {
method: 'enableEslintPlugin()',
// eslint is needed so the end-user can do things
packages: [
{ name: 'eslint' },
{ name: 'eslint-webpack-plugin', enforce_version: true },
],
description: 'Enable ESLint checks'
},
copy_files: {
method: 'copyFiles()',
packages: [
Expand Down
31 changes: 7 additions & 24 deletions lib/loaders/eslint.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,12 @@

'use strict';

const forceSync = require('sync-rpc');
const hasEslintConfiguration = forceSync(require.resolve('../utils/has-eslint-configuration'));
const WebpackConfig = require('../WebpackConfig'); //eslint-disable-line no-unused-vars
const loaderFeatures = require('../features');
const applyOptionsCallback = require('../utils/apply-options-callback');

function isMissingConfigError(e) {
if (!e.message || !e.message.includes('No ESLint configuration found')) {
return false;
}

return true;
}

module.exports = {
/**
* @param {WebpackConfig} webpackConfig
Expand All @@ -29,19 +23,11 @@ module.exports = {
getOptions(webpackConfig) {
loaderFeatures.ensurePackagesExistAndAreCorrectVersion('eslint');

const eslint = require('eslint'); // eslint-disable-line node/no-unpublished-require
const engine = new eslint.CLIEngine({
cwd: webpackConfig.runtimeConfig.context,
});

try {
engine.getConfigForFile('webpack.config.js');
} catch (e) {
if (isMissingConfigError(e)) {
const chalk = require('chalk');
const packageHelper = require('../package-helper');
if (!hasEslintConfiguration(webpackConfig)) {
const chalk = require('chalk');
const packageHelper = require('../package-helper');

const message = `No ESLint configration has been found.
const message = `No ESLint configuration has been found.

${chalk.bgGreen.black('', 'FIX', '')} Run command ${chalk.yellow('./node_modules/.bin/eslint --init')} or manually create a ${chalk.yellow('.eslintrc.js')} file at the root of your project.

Expand All @@ -57,10 +43,7 @@ module.exports = {
Install ${chalk.yellow('babel-eslint')} to prevent potential parsing issues: ${packageHelper.getInstallCommand([[{ name: 'babel-eslint' }]])}

`;
throw new Error(message);
}

throw e;
throw new Error(message);
}

const eslintLoaderOptions = {
Expand Down
64 changes: 64 additions & 0 deletions lib/plugins/eslint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* This file is part of the Symfony Webpack Encore package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

'use strict';

const forceSync = require('sync-rpc');
const hasEslintConfiguration = forceSync(require.resolve('../utils/has-eslint-configuration'));
const WebpackConfig = require('../WebpackConfig'); //eslint-disable-line no-unused-vars
const EslintPlugin = require('eslint-webpack-plugin'); //eslint-disable-line node/no-unpublished-require
const applyOptionsCallback = require('../utils/apply-options-callback');
const pluginFeatures = require('../features');

/**
* Support for ESLint.
*
* @param {Array} plugins
* @param {WebpackConfig} webpackConfig
* @return {void}
*/
module.exports = function(plugins, webpackConfig) {
if (webpackConfig.useEslintPlugin) {
pluginFeatures.ensurePackagesExistAndAreCorrectVersion('eslint_plugin');

if (!hasEslintConfiguration(webpackConfig)) {
const chalk = require('chalk');
const packageHelper = require('../package-helper');

const message = `No ESLint configuration has been found.

${chalk.bgGreen.black('', 'FIX', '')} Run command ${chalk.yellow('./node_modules/.bin/eslint --init')} or manually create a ${chalk.yellow('.eslintrc.js')} file at the root of your project.

If you prefer to create a ${chalk.yellow('.eslintrc.js')} file by yourself, here is an example to get you started:

${chalk.yellow(`// .eslintrc.js
module.exports = {
parser: 'babel-eslint',
extends: ['eslint:recommended'],
}
`)}

Install ${chalk.yellow('babel-eslint')} to prevent potential parsing issues: ${packageHelper.getInstallCommand([[{ name: 'babel-eslint' }]])}

`;
throw new Error(message);
}

const eslintPluginOptions = {
emitWarning: true,
extensions: ['js', 'jsx'],
};

plugins.push({
plugin: new EslintPlugin(
applyOptionsCallback(webpackConfig.eslintPluginOptionsCallback, eslintPluginOptions)
),
});
}
};
43 changes: 43 additions & 0 deletions lib/utils/has-eslint-configuration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* This file is part of the Symfony Webpack Encore package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

'use strict';


function isMissingConfigError(e) {
if (!e.message || !e.message.includes('No ESLint configuration found')) {
return false;
}

return true;
}

/**
* @returns {Promise<boolean>}
*/
module.exports = async function() {
/**
* @param {WebpackConfig} webpackConfig
* @returns {Promise<boolean>}
*/
return async function(webpackConfig) {
const { ESLint } = require('eslint'); // eslint-disable-line node/no-unpublished-require
const eslint = new ESLint({
cwd: webpackConfig.runtimeConfig.context,
});

try {
await eslint.calculateConfigForFile('webpack.config.js');
} catch (e) {
return !isMissingConfigError(e);
}

return true;
};
};
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@symfony/webpack-encore",
"version": "1.7.0",
"version": "1.7.1",
"description": "Webpack Encore is a simpler way to integrate Webpack into your application",
"main": "index.js",
"scripts": {
Expand Down Expand Up @@ -45,10 +45,11 @@
"resolve-url-loader": "^3.1.2",
"semver": "^7.3.2",
"style-loader": "^2.0.0",
"sync-rpc": "^1.3.6",
"terser-webpack-plugin": "^5.1.1",
"tmp": "^0.2.1",
"webpack": "^5.35",
"webpack-cli": "^4",
"webpack-cli": "^4.9.1",
"webpack-dev-server": "^4.0.0",
"yargs-parser": "^20.2.4"
},
Expand All @@ -69,11 +70,12 @@
"chai-fs": "^2.0.0",
"chai-subset": "^1.6.0",
"core-js": "^3.0.0",
"eslint": "^6.7.0 || ^7.0.0",
"eslint": "^7.0.0",
"eslint-loader": "^4.0.0",
"eslint-plugin-header": "^3.0.0",
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-node": "^11.1.0",
"eslint-webpack-plugin": "^2.5.4",
"file-loader": "^6.0.0",
"fork-ts-checker-webpack-plugin": "^5.0.0 || ^6.0.0",
"fs-extra": "^9.0.0",
Expand Down
19 changes: 19 additions & 0 deletions test/WebpackConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -1512,5 +1512,24 @@ describe('WebpackConfig object', () => {
});
}).to.throw('"notExisting" is not a valid key for enableEslintLoader(). Valid keys: lintVue.');
});

it('ESLint loader can not be enabled if ESLint Webpack Plugin is already enabled', () => {
const config = createConfig();
config.enableEslintPlugin();

expect(function() {
config.enableEslintLoader();
}).to.throw('Encore.enableEslintLoader() can not be called when Encore.enableEslintPlugin() has been called.');
});
});
describe('enableEslintPlugin', () => {
it('ESLint loader can not be enabled if ESLint Webpack Plugin is already enabled', () => {
const config = createConfig();
config.enableEslintLoader();

expect(function() {
config.enableEslintPlugin();
}).to.throw('Encore.enableEslintPlugin() can not be called when Encore.enableEslintLoader() has been called.');
});
});
});
Loading