Skip to content

Commit

Permalink
feat(module)!: generate withNuxt function for easer composition (#344)
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Mar 20, 2024
1 parent 065fbe2 commit 9c9f8f3
Show file tree
Hide file tree
Showing 10 changed files with 129 additions and 43 deletions.
47 changes: 27 additions & 20 deletions docs/content/1.packages/0.module.md
Expand Up @@ -56,22 +56,31 @@ export default defineNuxtConfig({
And create an `eslint.config.mjs` file under **your project root**, with the following content:

```js [eslint.config.mjs]
import nuxt from './.nuxt/eslint.config.mjs'

export default [
...nuxt,
// your custom flat config here.
]
import withNuxt from './.nuxt/eslint.config.mjs'

export default withNuxt(
// your custom flat configs go here, for example:
// {
// files: ['**/*.ts', '**/*.tsx'],
// rules: {
// 'no-console': 'off' // allow console.log in TypeScript files
// }
// },
// {
// ...
// }
)
```

`withNuxt` will takes rest arguments of flat configs and append them after Nuxt flat config items. You can use the [Nuxt DevTools](https://github.com/nuxt/devtools) panel to inspect the resolved ESLint flat config. Or run [`npx eslint-flat-config-viewer`](https://github.com/antfu/eslint-flat-config-viewer) manually to inspect.

## Receipts

### Work with VS Code

Note that ESLint Flat config is not yet enabled by default in the [ESLint VS Code extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint), you will need to enable it via the `eslint.experimental.useFlatConfig` to get ESLint working in VS Code. (This is likely not needed after ESLint v9).

```json
// .vscode/settings.json
```json [.vscode/settings.json]
{
// Enable the ESlint flat config support
"eslint.experimental.useFlatConfig": true
Expand All @@ -80,11 +89,11 @@ Note that ESLint Flat config is not yet enabled by default in the [ESLint VS Cod

### Use with Prettier

This module does not enable any stylistic/formatting rules by default. You can use Prettier alongside directly.
This module does not enable stylistic/formatting rules by default. You can use Prettier alongside directly.

### Use with ESLint Stylistic

If instead, you prefer to use ESLint for formatting as well, we also integrated [ESLint Stylistic](https://eslint.style/) to make it easy. You can opt-in by setting `config.stylistic` to `true` in the `eslint` module options.
If you prefer to use ESLint for formatting as well, we also integrated [ESLint Stylistic](https://eslint.style/) to make it easy. You can opt-in by setting `config.stylistic` to `true` in the `eslint` module options.

```ts [nuxt.config.ts]
export default defineNuxtConfig({
Expand Down Expand Up @@ -168,17 +177,15 @@ This will make this module only generate the Nuxt-specific rules and disables, s

For example, with [`@antfu/eslint-config`](https://github.com/antfu/eslint-config):

```js
// eslint.config.js
```js [eslint.config.mjs]
// @ts-check
import antfu from '@antfu/eslint-config'
import nuxt from './.nuxt/eslint.config.mjs'

export default antfu(
{
// ...@antfu/eslint-config options,
},
// Add the Nuxt rules
nuxt,
import withNuxt from './.nuxt/eslint.config.mjs'

export default withNuxt(
antfu({
// ...@antfu/eslint-config options
}),
// ...your other rules
)
```
33 changes: 31 additions & 2 deletions docs/content/1.packages/1.config.md
Expand Up @@ -49,14 +49,13 @@ bun add -D @nuxt/eslint-config eslint
2. Import the config factory function from `@nuxt/eslint-config/flat` entry in your `eslint.config.mjs`:

```js [eslint.config.mjs]
import createConfigForNuxt from '@nuxt/eslint-config/flat'
import { createConfigForNuxt } from '@nuxt/eslint-config/flat'

export default createConfigForNuxt({
// options here
})
```


You might also want to add a script entry to your `package.json:

```json [package.json]
Expand All @@ -67,6 +66,36 @@ You might also want to add a script entry to your `package.json:
}
```

### Customizing the Config

Note that `createConfigForNuxt()` returns `Promise<FlatConfig[]>`. ESLint allows you to run the promise directly to the default export. If you want to combine with other configs, you will need await and spread the result. For example:

```js [eslint.config.mjs]
import { createConfigForNuxt } from '@nuxt/eslint-config/flat'

export default [
...await createConfigForNuxt({
// options here
}),
// other configs
]
// (which uses Top-level await)
```

To make it easier, you can also use our helper `defineFlatConfigs`, which will also resolve and flatten the configs for you:

```js [eslint.config.mjs]
import { defineFlatConfigs, createConfigForNuxt } from '@nuxt/eslint-config/flat'

export default defineFlatConfigs(
createConfigForNuxt({
// options here
}),
// other configs
)
```


## Legacy Config Format

The legacy config configures for TypeScript and Vue integrations for ESLint. It is unopinionated and static, that does not contains stylistic rules nor project-aware settings.
Expand Down
11 changes: 8 additions & 3 deletions docs/nuxt.config.ts
Expand Up @@ -33,9 +33,6 @@ export default defineNuxtConfig({
routes: ['/api/search.json'],
autoSubfolderIndex: false,
},
experimental: {
wasm: true,
},
},

hooks: {
Expand All @@ -49,4 +46,12 @@ export default defineNuxtConfig({
}
},
},

$production: {
nitro: {
experimental: {
wasm: true,
},
},
},
})
8 changes: 4 additions & 4 deletions eslint.config.js
@@ -1,13 +1,13 @@
// @ts-check
import createConfig from '@nuxt/eslint-config/flat'
import { createConfigForNuxt, defineFlatConfigs } from '@nuxt/eslint-config/flat'

export default [
export default defineFlatConfigs(
{
ignores: [
'packages-legacy/**',
],
},
...createConfig({
createConfigForNuxt({
features: {
stylistic: true,
},
Expand All @@ -33,4 +33,4 @@ export default [
'vue/no-v-html': 'off',
},
},
]
)
1 change: 0 additions & 1 deletion packages/eslint-config/src/flat.ts
@@ -1,2 +1 @@
export * from './flat/index'
export { default } from './flat/index'
22 changes: 20 additions & 2 deletions packages/eslint-config/src/flat/index.ts
@@ -1,4 +1,4 @@
import type { FlatConfig, NuxtESLintConfigOptions } from './types'
import type { Awaitable, FlatConfig, NuxtESLintConfigOptions } from './types'
import disables from './configs/disables'
import nuxt from './configs/nuxt'
import base from './configs/base'
Expand All @@ -9,7 +9,25 @@ import stylistic from './configs/stylistic'

export * from './types'

export default function createConfigForNuxt(options: NuxtESLintConfigOptions = {}): FlatConfig[] {
/**
* Provide type definitions for constructing ESLint flat config items.
*
* This function takes flat config item, or an array of them as rest arguments.
* It also automatically resolves the promise if the config item is a promise.
*/
export async function defineFlatConfigs(...configs: Awaitable<FlatConfig | FlatConfig[]>[]): Promise<FlatConfig[]> {
const resolved = await Promise.all(configs)
return resolved.flat()
}

/**
* Create an array of ESLint flat configs for Nuxt 3, based on the given options.
*
* Usually it would be use `@nuxt/eslint` module which will generate the necessary configuration based on your project.
*
* @see https://eslint.nuxt.com/packages/module
*/
export async function createConfigForNuxt(options: NuxtESLintConfigOptions = {}): Promise<FlatConfig[]> {
const items: FlatConfig[] = []

if (options.features?.standalone !== false) {
Expand Down
2 changes: 2 additions & 0 deletions packages/eslint-config/src/flat/types.ts
Expand Up @@ -79,3 +79,5 @@ export interface NuxtESLintConfigOptions {
export interface FlatConfig extends Linter.FlatConfig {
name?: string
}

export type Awaitable<T> = T | Promise<T>
41 changes: 33 additions & 8 deletions packages/module/src/modules/config.ts
Expand Up @@ -27,6 +27,21 @@ export async function setupConfigGen(options: ModuleOptions, nuxt: Nuxt) {
},
})

addTemplate({
filename: 'eslint.config.d.mts',
write: true,
async getContents() {
return [
'import type { FlatConfig } from "@nuxt/eslint-config/flat"',
'export { defineFlatConfigs } from "@nuxt/eslint-config/flat"',
'declare const configs: Promise<FlatConfig[]>',
'declare const withNuxt: typeof defineFlatConfigs',
'export default withNuxt',
'export { withNuxt }',
].join('\n')
},
})

setupDevToolsIntegration(nuxt)
}

Expand All @@ -39,11 +54,15 @@ async function generateESLintConfig(options: ModuleOptions, nuxt: Nuxt, addons:
...typeof options.config !== 'boolean' ? options.config || {} : {},
}

importLines.push({
from: '@nuxt/eslint-config/flat',
name: 'default',
as: 'createConfigForNuxt',
})
importLines.push(
{
from: '@nuxt/eslint-config/flat',
name: 'createConfigForNuxt',
}, {
from: '@nuxt/eslint-config/flat',
name: 'defineFlatConfigs',
},
)

const basicOptions: NuxtESLintConfigOptions = {
features: {
Expand All @@ -53,7 +72,7 @@ async function generateESLintConfig(options: ModuleOptions, nuxt: Nuxt, addons:
dirs: getDirs(nuxt),
}

configItems.push(`// Nuxt Configs\n...createConfigForNuxt(${JSON.stringify(basicOptions, null, 2)})`)
configItems.push(`// Nuxt Configs\ncreateConfigForNuxt(${JSON.stringify(basicOptions, null, 2)})`)

for (const addon of addons) {
const resolved = await addon()
Expand All @@ -66,11 +85,17 @@ async function generateESLintConfig(options: ModuleOptions, nuxt: Nuxt, addons:
return [
'// ESLint config generated by Nuxt',
stringifyImports(importLines, false),
'export { defineFlatConfigs }',
'',
`export default [`,
`export const configs = defineFlatConfigs(`,
configItems.join(',\n\n'),
`]`,
`)`,
'',
'export function withNuxt(...customs) {',
' return defineFlatConfigs(configs, ...customs)',
'}',
'',
'export default withNuxt',
].join('\n')
}

Expand Down
5 changes: 3 additions & 2 deletions playground/eslint.config.js
@@ -1,3 +1,4 @@
import nuxt from './.nuxt/eslint.config.mjs'
// @ts-check
import withNuxt from './.nuxt/eslint.config.mjs'

export default nuxt
export default withNuxt()
2 changes: 1 addition & 1 deletion playground/package.json
Expand Up @@ -5,7 +5,7 @@
"scripts": {
"play:dev": "nuxi dev",
"play:build": "nuxi build",
"lint": "nuxi preprare && eslint ."
"lint": "nuxi prepare && eslint ."
},
"devDependencies": {
"nuxt": "^3.11.1"
Expand Down

0 comments on commit 9c9f8f3

Please sign in to comment.