Skip to content

Commit 4c09057

Browse files
committed
feat: replace eslint-loader by eslint-webpack-plugin
1 parent 83773ae commit 4c09057

File tree

6 files changed

+116
-93
lines changed

6 files changed

+116
-93
lines changed

packages/@vue/cli-plugin-eslint/__tests__/eslintPlugin.spec.js

+30
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,33 @@ test('should save report results to file with --output-file option', async () =>
195195
// results file should show "Missing semicolon" errors
196196
expect(resultsFileContents).toEqual(expect.stringContaining('Missing semicolon'))
197197
})
198+
199+
test('should persist cache', async () => {
200+
const project = await create('eslint-cache', {
201+
plugins: {
202+
'@vue/cli-plugin-eslint': {
203+
config: 'airbnb',
204+
lintOn: 'save'
205+
}
206+
}
207+
})
208+
209+
let done
210+
const donePromise = new Promise(resolve => {
211+
done = resolve
212+
})
213+
const { has, run } = project
214+
const server = run('vue-cli-service serve')
215+
216+
server.stdout.on('data', data => {
217+
data = data.toString()
218+
if (data.match(/Compiled successfully/)) {
219+
done()
220+
}
221+
})
222+
223+
await donePromise
224+
server.kill('SIGTERM')
225+
226+
expect(has('node_modules/.cache/.eslintcache')).toBe(true)
227+
})

packages/@vue/cli-plugin-eslint/index.js

+21-46
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,38 @@
11
const path = require('path')
2+
const eslintWebpackPlugin = require('eslint-webpack-plugin')
23

4+
/** @type {import('@vue/cli-service').ServicePlugin} */
35
module.exports = (api, options) => {
46
if (options.lintOnSave) {
57
const extensions = require('./eslintOptions').extensions(api)
68
// Use loadModule to allow users to customize their ESLint dependency version.
79
const { resolveModule, loadModule } = require('@vue/cli-shared-utils')
810
const cwd = api.getCwd()
9-
const eslintPkg =
10-
loadModule('eslint/package.json', cwd, true) ||
11-
loadModule('eslint/package.json', __dirname, true)
12-
13-
// eslint-loader doesn't bust cache when eslint config changes
14-
// so we have to manually generate a cache identifier that takes the config
15-
// into account.
16-
const { cacheIdentifier } = api.genCacheConfig(
17-
'eslint-loader',
18-
{
19-
'eslint-loader': require('eslint-loader/package.json').version,
20-
eslint: eslintPkg.version
21-
},
22-
[
23-
'.eslintrc.js',
24-
'.eslintrc.yaml',
25-
'.eslintrc.yml',
26-
'.eslintrc.json',
27-
'.eslintrc',
28-
'.eslintignore',
29-
'package.json'
30-
]
31-
)
3211

3312
api.chainWebpack(webpackConfig => {
3413
const { lintOnSave } = options
3514
const allWarnings = lintOnSave === true || lintOnSave === 'warning'
3615
const allErrors = lintOnSave === 'error'
3716

38-
webpackConfig.module
39-
.rule('eslint')
40-
.pre()
41-
.exclude
42-
.add(/node_modules/)
43-
.add(path.dirname(require.resolve('@vue/cli-service')))
44-
.end()
45-
.test(/\.(vue|(j|t)sx?)$/)
46-
.use('eslint-loader')
47-
.loader(require.resolve('eslint-loader'))
48-
.options({
49-
extensions,
50-
cache: true,
51-
cacheIdentifier,
52-
emitWarning: allWarnings,
53-
// only emit errors in production mode.
54-
emitError: allErrors,
55-
eslintPath: path.dirname(
56-
resolveModule('eslint/package.json', cwd) ||
57-
resolveModule('eslint/package.json', __dirname)
58-
),
59-
formatter: loadModule('eslint/lib/formatters/codeframe', cwd, true)
60-
})
17+
/** @type {import('eslint-webpack-plugin').Options & import('eslint').ESLint.Options} */
18+
const eslintWebpackPluginOptions = {
19+
// common to both plugin and ESlint
20+
extensions,
21+
// ESlint options
22+
cwd,
23+
cache: true,
24+
cacheLocation: api.resolve('node_modules/.cache/.eslintcache'),
25+
// plugin options
26+
context: cwd,
27+
emitWarning: allWarnings,
28+
emitError: allErrors,
29+
eslintPath: path.dirname(
30+
resolveModule('eslint/package.json', cwd) ||
31+
resolveModule('eslint/package.json', __dirname)
32+
),
33+
formatter: loadModule('eslint/lib/formatters/codeframe', cwd, true)
34+
}
35+
webpackConfig.plugin('eslint').use(eslintWebpackPlugin, [eslintWebpackPluginOptions])
6136
})
6237
}
6338

packages/@vue/cli-plugin-eslint/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
},
2525
"dependencies": {
2626
"@vue/cli-shared-utils": "^4.5.8",
27-
"eslint-loader": "^4.0.2",
27+
"eslint-webpack-plugin": "^2.4.0",
2828
"globby": "^9.2.0",
2929
"inquirer": "^7.1.0",
3030
"webpack": "^4.0.0",

packages/@vue/cli-service-global/__tests__/globalService.spec.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const launchPuppeteer = require('@vue/cli-test-utils/launchPuppeteer')
1111
const cwd = path.resolve(__dirname, 'temp')
1212
const binPath = require.resolve('@vue/cli/bin/vue')
1313
const write = (file, content) => fs.writeFile(path.join(cwd, file), content)
14+
const remove = (file) => fs.remove(path.join(cwd, file))
1415

1516
const entryVue = fs.readFileSync(path.resolve(__dirname, 'entry.vue'), 'utf-8')
1617

@@ -26,6 +27,7 @@ beforeEach(async () => {
2627
await write('App.vue', entryVue)
2728
await write('Other.vue', entryVue)
2829
await write('foo.js', entryJs)
30+
await remove('node_modules/.cache')
2931
})
3032

3133
test('global serve', async () => {
@@ -55,9 +57,12 @@ test('global serve', async () => {
5557

5658
test('global serve with eslint', async () => {
5759
try {
60+
const cachePath = path.join(cwd, 'node_modules/.cache/.eslintcache')
61+
expect(fs.existsSync(cachePath)).toBe(false)
5862
await serve(
5963
() => execa(binPath, ['serve', 'foo.js'], { cwd }),
60-
async ({ page, nextUpdate, helpers }) => {
64+
async ({ nextUpdate, helpers }) => {
65+
expect(fs.existsSync(cachePath)).toBe(true)
6166
expect(await helpers.getText('h1')).toMatch('hi')
6267

6368
write('foo.js', entryJs.replace(`$mount('#app')`, `$mount('#app');`))
@@ -72,7 +77,7 @@ test('global serve with eslint', async () => {
7277
// Failed because of no-extra-semi
7378
expect(err).toMatch('Failed to compile with 1 errors')
7479
}
75-
expect.assertions(3)
80+
expect.assertions(5)
7681
})
7782

7883
let server, browser, page

packages/@vue/cli-service-global/lib/globalConfigPlugin.js

+31-26
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const { loadPartialConfigSync } = require('@babel/core')
66
module.exports = function createConfigPlugin (context, entry, asLib) {
77
return {
88
id: '@vue/cli-service-global-config',
9+
/** @type {import('@vue/cli-service').ServicePlugin} */
910
apply: (api, options) => {
1011
const _entry = path.resolve(context, entry)
1112
api.chainWebpack(config => {
@@ -85,6 +86,7 @@ module.exports = function createConfigPlugin (context, entry, asLib) {
8586
// messed up when the project is inside another project.
8687
const ESLintConfigFile = findExisting(context, [
8788
'.eslintrc.js',
89+
'.eslintrc.cjs',
8890
'.eslintrc.yaml',
8991
'.eslintrc.yml',
9092
'.eslintrc.json',
@@ -99,33 +101,36 @@ module.exports = function createConfigPlugin (context, entry, asLib) {
99101
const hasBabelConfig = !!babelConfig && babelConfig.hasFilesystemConfig()
100102

101103
// set inline eslint options
102-
config.module
103-
.rule('eslint')
104-
.include
105-
.clear()
106-
.end()
107-
.exclude
108-
.add(/node_modules/)
109-
.end()
110-
.use('eslint-loader')
111-
.tap(loaderOptions => Object.assign({}, loaderOptions, {
112-
useEslintrc: hasESLintConfig,
113-
baseConfig: {
114-
extends: [
115-
'plugin:vue/essential',
116-
'eslint:recommended'
117-
],
118-
parserOptions: {
119-
parser: '@babel/eslint-parser',
120-
requireConfigFile: hasBabelConfig,
121-
babelOptions
122-
},
123-
rules: {
124-
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
125-
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
126-
}
104+
config
105+
.plugin('eslint')
106+
.tap(args => {
107+
/** @type {import('eslint-webpack-plugin').Options & import('eslint').ESLint.Options} */
108+
const eslintWebpackPluginOptions = {
109+
// eslint@7 load config and plugin related to baseConfig.extends from cwd,
110+
// By default, cwd is the current working directory of `vue serve`,
111+
// should load baseConfig.extends config(dependencies of @vue/cli-service-global) from `__dirname`
112+
cwd: __dirname,
113+
useEslintrc: hasESLintConfig,
114+
baseConfig: {
115+
extends: [
116+
'plugin:vue/essential',
117+
'eslint:recommended'
118+
],
119+
parserOptions: {
120+
parser: '@babel/eslint-parser',
121+
requireConfigFile: hasBabelConfig,
122+
babelOptions
123+
},
124+
rules: {
125+
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
126+
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
127127
}
128-
}))
128+
}
129+
}
130+
Object.assign(args[0], eslintWebpackPluginOptions)
131+
132+
return args
133+
})
129134

130135
if (!asLib) {
131136
// set html plugin template

yarn.lock

+26-18
Original file line numberDiff line numberDiff line change
@@ -2708,6 +2708,19 @@
27082708
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
27092709
integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==
27102710

2711+
"@types/eslint@^7.2.4":
2712+
version "7.2.5"
2713+
resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.2.5.tgz#92172ecf490c2fce4b076739693d75f30376d610"
2714+
integrity sha512-Dc6ar9x16BdaR3NSxSF7T4IjL9gxxViJq8RmFd+2UAyA+K6ck2W+gUwfgpG/y9TPyUuBL35109bbULpEynvltA==
2715+
dependencies:
2716+
"@types/estree" "*"
2717+
"@types/json-schema" "*"
2718+
2719+
"@types/estree@*":
2720+
version "0.0.45"
2721+
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.45.tgz#e9387572998e5ecdac221950dab3e8c3b16af884"
2722+
integrity sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g==
2723+
27112724
"@types/execa@^0.9.0":
27122725
version "0.9.0"
27132726
resolved "https://registry.yarnpkg.com/@types/execa/-/execa-0.9.0.tgz#9b025d2755f17e80beaf9368c3f4f319d8b0fb93"
@@ -2867,7 +2880,7 @@
28672880
ast-types "0.12.1"
28682881
recast "0.17.2"
28692882

2870-
"@types/json-schema@^7.0.3", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.6":
2883+
"@types/json-schema@*", "@types/json-schema@^7.0.3", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.6":
28712884
version "7.0.6"
28722885
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0"
28732886
integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==
@@ -8774,17 +8787,6 @@ eslint-import-resolver-webpack@^0.12.1, eslint-import-resolver-webpack@^0.12.2:
87748787
resolve "^1.13.1"
87758788
semver "^5.7.1"
87768789

8777-
eslint-loader@^4.0.2:
8778-
version "4.0.2"
8779-
resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-4.0.2.tgz#386a1e21bcb613b3cf2d252a3b708023ccfb41ec"
8780-
integrity sha512-EDpXor6lsjtTzZpLUn7KmXs02+nIjGcgees9BYjNkWra3jVq5vVa8IoCKgzT2M7dNNeoMBtaSG83Bd40N3poLw==
8781-
dependencies:
8782-
find-cache-dir "^3.3.1"
8783-
fs-extra "^8.1.0"
8784-
loader-utils "^2.0.0"
8785-
object-hash "^2.0.3"
8786-
schema-utils "^2.6.5"
8787-
87888790
eslint-module-utils@^2.6.0:
87898791
version "2.6.0"
87908792
resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz#579ebd094f56af7797d19c9866c9c9486629bfa6"
@@ -8934,6 +8936,17 @@ eslint-visitor-keys@^2.0.0:
89348936
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8"
89358937
integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==
89368938

8939+
eslint-webpack-plugin@^2.4.0:
8940+
version "2.4.0"
8941+
resolved "https://registry.yarnpkg.com/eslint-webpack-plugin/-/eslint-webpack-plugin-2.4.0.tgz#dcfd2653d0e15e52251f34dd3690ce60718d5589"
8942+
integrity sha512-j0lAJj3RnStAFdIH2P0+nsEImiBijwogZhL1go4bI6DE+9OhQuOmJ/xtmxkLtNr1w0cf5SRNkDlmIe8t/pHgww==
8943+
dependencies:
8944+
"@types/eslint" "^7.2.4"
8945+
arrify "^2.0.1"
8946+
jest-worker "^26.6.2"
8947+
micromatch "^4.0.2"
8948+
schema-utils "^3.0.0"
8949+
89378950
eslint@^7.13.0:
89388951
version "7.13.0"
89398952
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.13.0.tgz#7f180126c0dcdef327bfb54b211d7802decc08da"
@@ -12575,7 +12588,7 @@ jest-worker@^24.6.0, jest-worker@^24.9.0:
1257512588
merge-stream "^2.0.0"
1257612589
supports-color "^6.1.0"
1257712590

12578-
jest-worker@^26.5.0:
12591+
jest-worker@^26.5.0, jest-worker@^26.6.2:
1257912592
version "26.6.2"
1258012593
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed"
1258112594
integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==
@@ -15278,11 +15291,6 @@ object-copy@^0.1.0:
1527815291
define-property "^0.2.5"
1527915292
kind-of "^3.0.3"
1528015293

15281-
object-hash@^2.0.3:
15282-
version "2.0.3"
15283-
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.0.3.tgz#d12db044e03cd2ca3d77c0570d87225b02e1e6ea"
15284-
integrity sha512-JPKn0GMu+Fa3zt3Bmr66JhokJU5BaNBIh4ZeTlaCBzrBsOeXzwcKKAK1tbLiPKgvwmPXsDvvLHoWh5Bm7ofIYg==
15285-
1528615294
object-inspect@^1.8.0:
1528715295
version "1.8.0"
1528815296
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0"

0 commit comments

Comments
 (0)