Skip to content

Commit

Permalink
feat: a more intuitive way to configure and override (#123)
Browse files Browse the repository at this point in the history
  • Loading branch information
haoqunjiang authored Jan 14, 2025
1 parent 6296f39 commit f7bd7b7
Show file tree
Hide file tree
Showing 106 changed files with 4,097 additions and 1,788 deletions.
163 changes: 79 additions & 84 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,26 @@ Please also make sure that you have `typescript` and `eslint` installed.

## Usage

Because of the complexity of this config, it is exported as a factory function that takes an options object and returns an ESLint configuration object.
Because of the complexity of the configurations, this package exports several utilities:

- `defineConfigWithVueTs`, a utility function whose type signature is the same as the [`config` function from `typescript-eslint`](https://typescript-eslint.io/packages/typescript-eslint#config), but will modify the given ESLint config to work with Vue.js + TypeScript.
- `vueTsConfigs`, contains all the [shared configruations from `typescript-eslint`](https://typescript-eslint.io/users/configs) (in camelCase, e.g. `vueTsConfigs.recommendedTypeChecked`), and applies to `.vue` files in addition to TypeScript files.
- a Vue-specific config factory: `configureVueProject({ scriptLangs, rootDir })`. More info below.

### Minimal Setup

```js
// eslint.config.mjs
import pluginVue from "eslint-plugin-vue";
import vueTsEslintConfig from "@vue/eslint-config-typescript";

export default [
...pluginVue.configs["flat/essential"],
...vueTsEslintConfig(),
]
import pluginVue from 'eslint-plugin-vue'
import {
defineConfigWithVueTs,
vueTsConfigs,
} from '@vue/eslint-config-typescript'

export default defineConfigWithVueTs(
pluginVue.configs['flat/essential'],
vueTsConfigs.recommended,
)
```

The above configuration enables [the essential rules for Vue 3](https://eslint.vuejs.org/rules/#priority-a-essential-error-prevention) and [the recommended rules for TypeScript](https://typescript-eslint.io/rules/?=recommended).
Expand All @@ -48,58 +55,54 @@ All the `<script>` blocks in `.vue` files *MUST* be written in TypeScript (shoul

```js
// eslint.config.mjs
import pluginVue from "eslint-plugin-vue";
import vueTsEslintConfig from "@vue/eslint-config-typescript";

export default [
...pluginVue.configs["flat/essential"],

...vueTsEslintConfig({
// Optional: extend additional configurations from `typescript-eslint`.
// Supports all the configurations in
// https://typescript-eslint.io/users/configs#recommended-configurations
extends: [
// By default, only the recommended rules are enabled.
"recommended",
// You can also manually enable the stylistic rules.
// "stylistic",

// Other utility configurations, such as `eslintRecommended`, (note that it's in camelCase)
// are also extendable here. But we don't recommend using them directly.
],

// Optional: specify the script langs in `.vue` files
// Defaults to `{ ts: true, js: false, tsx: false, jsx: false }`
supportedScriptLangs: {
ts: true,

// [!DISCOURAGED]
// Set to `true` to allow plain `<script>` or `<script setup>` blocks.
// This might result-in false positive or negatives in some rules for `.vue` files.
// Note you also need to configure `allowJs: true` and `checkJs: true`
// in corresponding `tsconfig.json` files.
js: false,

// [!STRONGLY DISCOURAGED]
// Set to `true` to allow `<script lang="tsx">` blocks.
// This would be in conflict with all type-aware rules.
tsx: false,

// [!STRONGLY DISCOURAGED]
// Set to `true` to allow `<script lang="jsx">` blocks.
// This would be in conflict with all type-aware rules and may result in false positives.
jsx: false,
},

// <https://github.com/vuejs/eslint-plugin-vue/issues/1910#issuecomment-1819993961>
// Optional: the root directory to resolve the `.vue` files, defaults to `process.cwd()`.
// You may need to set this to the root directory of your project if you have a monorepo.
// This is useful when you allow any other languages than `ts` in `.vue` files.
// Our config helper would resolve and parse all the `.vue` files under `rootDir`,
// and only apply the loosened rules to the files that do need them.
rootDir: import.meta.dirname,
})
]
import pluginVue from 'eslint-plugin-vue'
import {
defineConfigWithVueTs,
vueTsConfigs,
configureVueProject,
} from '@vue/eslint-config-typescript'

configureVueProject({
// Optional: specify the script langs in `.vue` files
// Defaults to `['ts']`.
scriptLangs: [
'ts',

// [!DISCOURAGED]
// Include 'js' to allow plain `<script>` or `<script setup>` blocks.
// This might result-in false positive or negatives in some rules for `.vue` files.
// Note you also need to configure `allowJs: true` and `checkJs: true`
// in corresponding `tsconfig.json` files.
'js',

// [!STRONGLY DISCOURAGED]
// Include 'tsx' to allow `<script lang="tsx">` blocks.
// This would be in conflict with all type-aware rules.
'tsx',

// [!STRONGLY DISCOURAGED]
// Include 'jsx' to allow `<script lang="jsx">` blocks.
// This would be in conflict with all type-aware rules and may result in false positives.
'jsx',
],

// <https://github.com/vuejs/eslint-plugin-vue/issues/1910#issuecomment-1819993961>
// Optional: the root directory to resolve the `.vue` files, defaults to `process.cwd()`.
// You may need to set this to the root directory of your project if you have a monorepo.
// This is useful when you allow any other languages than `ts` in `.vue` files.
// Our config helper would resolve and parse all the `.vue` files under `rootDir`,
// and only apply the loosened rules to the files that do need them.
rootDir: import.meta.dirname,
})

export default defineConfigWithVueTs(
pluginVue.configs["flat/essential"],

// We STRONGLY RECOMMEND you to start with `recommended` or `recommendedTypeChecked`.
// But if you are determined to configure all rules by yourself,
// you can start with `base`, and then turn on/off the rules you need.
vueTsConfigs.base,
)
```

### Linting with Type Information
Expand All @@ -111,34 +114,26 @@ It is not always easy to set up the type-checking environment for ESLint without
So we don't recommend you to configure individual type-aware rules and the corresponding language options all by yourself.
Instead, you can start by extending from the `recommendedTypeChecked` configuration and then turn on/off the rules you need.

As of now, all the rules you need to turn on must appear *before* calling `...vueTsEslintConfig({ extends: ['recommendedTypeChecked'] })`, and all the rules you need to turn off must appear *after* calling it.

```js
// eslint.config.mjs
import pluginVue from "eslint-plugin-vue";
import vueTsEslintConfig from "@vue/eslint-config-typescript";

export default [
...pluginVue.configs["flat/essential"],

{
files: ['**/*.ts', '**/*.tsx', '**/*.mts', '**/*.vue'],
rules: {
// Turn on other rules that you need.
'@typescript-eslint/require-array-sort-compare': 'error'
}
},
...vueTsEslintConfig({ extends: ['recommendedTypeChecked'] }),
{
files: ['**/*.ts', '**/*.tsx', '**/*.mts', '**/*.vue'],
rules: {
// Turn off the recommended rules that you don't need.
'@typescript-eslint/no-redundant-type-constituents': 'off',
}
}
]
import pluginVue from 'eslint-plugin-vue'
import {
defineConfigWithVueTs,
vueTsConfigs,
} from '@vue/eslint-config-typescript'

export default defineConfigWithVueTs(
pluginVue.configs['flat/essential'],
vueTsConfigs.recommendedTypeChecked
)
```

## Use As a Normal Shared ESLint Config (Not Recommended)

You can use this package as a normal ESLint config, without the `defineConfigWithVueTs` helper. But in this case, overriding the rules for `.vue` files would be more difficult and comes with many nuances. Please be cautious.

You can check [the documentation for 14.1 and earlier versions](https://github.com/vuejs/eslint-config-typescript/tree/v14.1.4#usage) for more information.

## Further Reading

- [All the extendable configurations from `typescript-eslint`](https://typescript-eslint.io/users/configs).
Expand Down
23 changes: 12 additions & 11 deletions examples/allow-js/eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import pluginVue from "eslint-plugin-vue";
import vueTsEslintConfig from "@vue/eslint-config-typescript";
import pluginVue from 'eslint-plugin-vue'
import {
defineConfigWithVueTs,
vueTsConfigs,
configureVueProject,
} from '@vue/eslint-config-typescript'

export default [
configureVueProject({ scriptLangs: ['js', 'ts'] })

export default defineConfigWithVueTs(
{
name: 'app/files-to-lint',
files: ['**/*.js', '**/*.mjs', '**/*.ts', '**/*.mts', '**/*.vue'],
Expand All @@ -12,11 +18,6 @@ export default [
ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'],
},

...pluginVue.configs["flat/essential"],
...vueTsEslintConfig({
supportedScriptLangs: {
ts: true,
js: true
}
}),
]
pluginVue.configs['flat/essential'],
vueTsConfigs.recommended,
)
10 changes: 5 additions & 5 deletions examples/allow-js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@
},
"devDependencies": {
"@tsconfig/node20": "^20.1.4",
"@types/node": "^20.17.10",
"@types/node": "^20.17.12",
"@vitejs/plugin-vue": "^5.2.1",
"@vue/eslint-config-typescript": "workspace:*",
"@vue/tsconfig": "^0.7.0",
"eslint": "^9.17.0",
"eslint": "^9.18.0",
"eslint-plugin-vue": "^9.32.0",
"npm-run-all2": "^7.0.2",
"typescript": "~5.6.3",
"vite": "^6.0.5",
"vue-tsc": "^2.1.10"
"typescript": "~5.7.3",
"vite": "^6.0.7",
"vue-tsc": "^2.2.0"
}
}
6 changes: 6 additions & 0 deletions examples/api-before-14.3/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue}]
charset = utf-8
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
30 changes: 30 additions & 0 deletions examples/api-before-14.3/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
.DS_Store
dist
dist-ssr
coverage
*.local

/cypress/videos/
/cypress/screenshots/

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

*.tsbuildinfo
7 changes: 7 additions & 0 deletions examples/api-before-14.3/.prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": false,
"singleQuote": true,
"arrowParens": "avoid"
}
8 changes: 8 additions & 0 deletions examples/api-before-14.3/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"recommendations": [
"Vue.volar",
"vitest.explorer",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}
61 changes: 61 additions & 0 deletions examples/api-before-14.3/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# api-before-14.3

This template should help get you started developing with Vue 3 in Vite.

## Recommended IDE Setup

[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).

## Type Support for `.vue` Imports in TS

TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.

## Customize configuration

See [Vite Configuration Reference](https://vite.dev/config/).

## Project Setup

```sh
npm install
```

### Compile and Hot-Reload for Development

```sh
npm run dev
```

### Type-Check, Compile and Minify for Production

```sh
npm run build
```

### Run Unit Tests with [Vitest](https://vitest.dev/)

```sh
npm run test:unit
```

### Run End-to-End Tests with [Cypress](https://www.cypress.io/)

```sh
npm run test:e2e:dev
```

This runs the end-to-end tests against the Vite development server.
It is much faster than the production build.

But it's still recommended to test the production build with `test:e2e` before deploying (e.g. in CI environments):

```sh
npm run build
npm run test:e2e
```

### Lint with [ESLint](https://eslint.org/)

```sh
npm run lint
```
8 changes: 8 additions & 0 deletions examples/api-before-14.3/cypress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { defineConfig } from 'cypress'

export default defineConfig({
e2e: {
specPattern: 'cypress/e2e/**/*.{cy,spec}.{js,jsx,ts,tsx}',
baseUrl: 'http://localhost:4173'
}
})
8 changes: 8 additions & 0 deletions examples/api-before-14.3/cypress/e2e/example.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// https://on.cypress.io/api

describe('My First Test', () => {
it('visits the app root url', () => {
cy.visit('/')
cy.contains('h1', 'You did it!')
})
})
5 changes: 5 additions & 0 deletions examples/api-before-14.3/cypress/fixtures/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "[email protected]",
"body": "Fixtures are a great way to mock data for responses to routes"
}
Loading

0 comments on commit f7bd7b7

Please sign in to comment.