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

[WORK-IN-PROGRESS]: ESLint 9 and Flat Config #33

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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
16 changes: 16 additions & 0 deletions .changeset/dry-points-agree.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"@vue/eslint-config-standard": major
---

* Supports ESLint ^9.10, Node.js ^18.18.0 || ^20.9.0 || >=21.1.0, drops support for older versions.
* Supports ESLint Flat Config, drops support for legacy `.eslintrc*` configuration format.
* Removed `createAliasSetting` helper function, as we now automatically detects path aliases in `jsconfig.json` and `tsconfig.json` files.
* Removed examples of Vue CLI project setups.
* Stylistic rules also apply to expressions in `<template>` blocks.

Internal Changes:

* Drops `eslint-config-standard` as a dependency as it never released the latest code that would support Flat Config; we have to maintain the rules ourselves.
* Moved from `eslint-plugin-import` to `eslint-plugin-import-x`.
* Use stylistic rules from `@stylistic/eslint-plugin` instead of the ESLint built-in ones.
* Other dependency updates.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# ESLint [Shareable Configs](http://eslint.org/docs/developer-guide/shareable-configs) for [JavaScript Standard Style](http://standardjs.com) in [Vue.js](https://vuejs.org/) Projects
# ESLint [Shareable Configs](https://eslint.org/docs/latest/extend/shareable-configs) for [JavaScript Standard Style](http://standardjs.com) in [Vue.js](https://vuejs.org/) Projects

[![JavaScript Style Guide - Standard Style](https://raw.githubusercontent.com/standard/standard/master/badge.svg)](http://standardjs.com)

Expand All @@ -9,4 +9,4 @@ This repo contains 2 packages:
- If you are using ESLint in a JavaScript-only project, check the documentation of [`@vue/eslint-config-standard`](./packages/eslint-config-standard#readme)
- If you are using ESLint in a TypeScript project, check the documentation of [`@vue/eslint-config-standard-with-typescript`](./packages/eslint-config-standard-with-typescript#readme)

The [`examples` folder](./examples/) contains example ESLint configurations in projects created by `create-vue` or `@vue/cli`.
The [`examples` folder](./examples/) contains example ESLint configurations in projects created by `create-vue`.
18 changes: 0 additions & 18 deletions examples/create-vue-js/.eslintrc.cjs

This file was deleted.

17 changes: 17 additions & 0 deletions examples/create-vue-js/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import pluginVue from 'eslint-plugin-vue'
import standard from '@vue/eslint-config-standard'

export default [
{
name: 'app/files-to-lint',
files: ['**/*.{ts,mts,tsx,vue}']
},

{
name: 'app/files-to-ignore',
ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**']
},

...pluginVue.configs['flat/essential'],
...standard
]
7 changes: 7 additions & 0 deletions examples/create-vue-js/jsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
}
}
5 changes: 2 additions & 3 deletions examples/create-vue-js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,18 @@
"dev": "vite",
"build": "vite build",
"preview": "vite preview --port 4173",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore"
"lint": "eslint . --fix"
},
"dependencies": {
"pinia": "^2.2.4",
"vue": "^3.5.11",
"vue-router": "^4.4.5"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.10.4",
"@vitejs/plugin-vue": "^5.1.4",
"@vitejs/plugin-vue-jsx": "^4.0.1",
"@vue/eslint-config-standard": "workspace:*",
"eslint": "^8.57.1",
"eslint": "^9.12.0",
"eslint-plugin-vue": "^9.28.0",
"vite": "^5.4.8",
"vue": "^3.5.11"
Expand Down
2 changes: 1 addition & 1 deletion examples/create-vue-js/src/main.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* eslint import/no-unresolved: 2 */
/* eslint import-x/no-unresolved: 2 */
import { createApp } from 'vue'
import { createPinia } from 'pinia'

Expand Down
19 changes: 0 additions & 19 deletions packages/eslint-config-standard/.eslintrc.cjs

This file was deleted.

59 changes: 15 additions & 44 deletions packages/eslint-config-standard/README.md
Original file line number Diff line number Diff line change
@@ -1,69 +1,40 @@
# `@vue/eslint-config-standard`

> eslint-config-standard for Vue
ESLint [Shareable Configs](https://eslint.org/docs/latest/extend/shareable-configs) for [JavaScript Standard Style](http://standardjs.com) in [Vue.js](https://vuejs.org/) Projects

This config is specifically designed to be used by `@vue/cli` & `create-vue` setups
This config is specifically designed to be used by `create-vue` setups
and is not meant for outside use (it can be used but some adaptations
on the user side might be needed - for details see the config file).

A part of its design is that this config may implicitly depend on
other parts of `@vue/cli`/`create-vue` setups, such as `eslint-plugin-vue` being
other parts of `create-vue` setups, such as `eslint-plugin-vue` being
extended in the same resulting config.

## Installation
> [!NOTE]
> The current version doesn't support the legacy `.eslintrc*` configuration format. For that you need to use version 13 or earlier. See the [corresponding README](https://www.npmjs.com/package/@vue/eslint-config-typescript/v/legacy-eslintrc) for more usage instructions.

In order to work around [a known limitation in ESLint](https://github.com/eslint/eslint/issues/3458), we recommend you to use this package alongside `@rushstack/eslint-patch`, so that you don't have to install too many dependencies:
## Installation

```sh
npm add --dev @vue/eslint-config-standard @rushstack/eslint-patch
npm add --dev @vue/eslint-config-standard
```

## Usage

An example `.eslintrc.cjs`:
An example `eslint.config.js`:

```js
require("@rushstack/eslint-patch/modern-module-resolution")
import pluginVue from "eslint-plugin-vue";
import standard from "@vue/eslint-config-standard";

module.exports = {
root: true,
extends: [
'plugin:vue/vue3-essential',
'@vue/eslint-config-standard'
]
}
export default [
...pluginVue.configs["flat/essential"],
...standard,
]
```

## Aliases

By default, none of the built-in rules require you to configure aliases in ESLint.

But if you want to enable some additional rules that need to actually resolve the imported module on the filesystem (e.g. [`import/no-unresolved`](https://github.com/import-js/eslint-plugin-import/blob/v2.26.0/docs/rules/no-unresolved.md)) by yourself, you should configure it.
In that case, we provided a helper function to simplify the task.

For example, it is a widely accepted convention to use `@` as an alias to the `src` folder in the Vue ecosystem. To enable this, you can use the following config:

```js
require('@rushstack/eslint-patch/modern-module-resolution')

const path = require('node:path')
const createAliasSetting = require('@vue/eslint-config-standard/createAliasSetting')

module.exports = {
root: true,
extends: [
'plugin:vue/vue3-essential',
'@vue/eslint-config-standard'
],
rules: {
'import/no-unresolved': 'error'
}
settings: {
...createAliasSetting({
'@': `${path.resolve(__dirname, './src')}`
})
}
}
```

`createAliasSetting` accepts a map of aliases and their corresponding paths, and returns a settings object to be spread in to the `settings` field of the ESLint config.
But if you want to enable some additional rules that need to actually resolve the imported module on the filesystem (e.g. [`import-x/no-unresolved`](https://github.com/import-js/eslint-plugin-import/blob/v2.26.0/docs/rules/no-unresolved.md)) by yourself and need path aliases to be resolved, please make sure configure them in your `jsconfig.json` or `tsconfig.json` file. We use [eslint-import-resolver-next](https://github.com/kuoruan/eslint-import-resolver-next) as the default resolver, which will automatically detect path aliases in these files.
25 changes: 0 additions & 25 deletions packages/eslint-config-standard/createAliasSetting.cjs

This file was deleted.

21 changes: 21 additions & 0 deletions packages/eslint-config-standard/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import pluginVue from 'eslint-plugin-vue'
import standard from './index.js'

export default [
{
name: 'files-to-lint',
files: ['**/*.{js,mjs,jsx,vue}']
},

// As `vue/*` rules are included, it's a requirement.
// TODO: find a better way to handle this.
{ plugins: { vue: pluginVue } },

...standard,

{
rules: {
'import-x/extensions': ['error', 'ignorePackages']
}
}
]
1 change: 0 additions & 1 deletion packages/eslint-config-standard/index.cjs

This file was deleted.

48 changes: 48 additions & 0 deletions packages/eslint-config-standard/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import upstream from './upstream.js'
import stylistic from './stylistic.js'
import template from './template.js'
import resolver from './resolver.js'

// Use deep merge to avoid complications in overriding mechanisms.
// But still export as an array for future extensibility.
export default [
deepMerge(
{
name: 'vue-standard'
},
upstream,
stylistic,
template,
resolver
)
]

function deepMerge (target, ...sources) {
const seen = new WeakMap()

function merge (target, source) {
if (source instanceof Object && !Array.isArray(source)) {
if (seen.has(source)) {
return seen.get(source)
}
seen.set(source, target)

Object.keys(source).forEach((key) => {
if (
source[key] instanceof Object &&
!Array.isArray(source[key]) &&
typeof source[key] !== 'function'
) {
if (!target[key]) Object.assign(target, { [key]: {} })
merge(target[key], source[key])
} else {
Object.assign(target, { [key]: source[key] })
}
})
}
return target
}

sources.forEach((source) => merge(target, source))
return target
}
24 changes: 12 additions & 12 deletions packages/eslint-config-standard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
"name": "@vue/eslint-config-standard",
"version": "8.0.1",
"description": "eslint-config-standard for Vue.js projects",
"main": "index.cjs",
"type": "module",
"main": "index.js",
"exports": {
".": "./index.cjs",
"./createAliasSetting": "./createAliasSetting.cjs",
".": "./index.js",
"./package.json": "./package.json"
},
"publishConfig": {
Expand All @@ -28,18 +28,18 @@
},
"homepage": "https://github.com/vuejs/eslint-config-standard/blob/main/packages/eslint-config-standard#readme",
"dependencies": {
"eslint-config-standard": "^17.1.0",
"eslint-import-resolver-custom-alias": "^1.3.2",
"eslint-import-resolver-node": "^0.3.9",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-n": "^15.7.0",
"eslint-plugin-promise": "^6.6.0"
"@stylistic/eslint-plugin": "^2.12.1",
"eslint-import-resolver-next": "^0.4.1",
"eslint-plugin-import-x": "^4.6.1",
"eslint-plugin-n": "^17.15.1",
"eslint-plugin-promise": "^7.2.1",
"globals": "^15.14.0"
},
"peerDependencies": {
"eslint": "^8.0.1",
"eslint-plugin-vue": "^9.2.0"
"eslint": "^9.10.0",
"eslint-plugin-vue": "^9.28.0"
},
"devDependencies": {
"eslint": "^8.57.1"
"eslint": "^9.10.0"
}
}
13 changes: 13 additions & 0 deletions packages/eslint-config-standard/resolver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { createNextImportResolver } from 'eslint-import-resolver-next'

import eslintPluginImportX from 'eslint-plugin-import-x'
const { createNodeResolver } = eslintPluginImportX

export default {
settings: {
'import-x/resolver-next': [
createNodeResolver(),
createNextImportResolver()
]
}
}
22 changes: 22 additions & 0 deletions packages/eslint-config-standard/stylistic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import stylistic from '@stylistic/eslint-plugin'
import standard from './upstream.js'

const stylisticRulesToReplace = Object.keys(standard.rules)
.filter((ruleName) => !!stylistic.rules[ruleName])

const rules = {}

stylisticRulesToReplace.forEach((ruleName) => {
// disable the original rule
rules[ruleName] = 'off'
// enable the stylistic verison of the rule
rules[`@stylistic/${ruleName}`] = standard.rules[ruleName]
})

export default {
plugins: {
'@stylistic': stylistic
},

rules
}
Loading