Nuxt ESLint 集成更新

本文为译文,原文作者为 Anthony Fu

原文链接:https://nuxt.com/blog/eslint-module

原文发布时间:2024-04-10

概述

我们改进了我们的 ESLint 集成,以支持带有新 flat config 的 ESLint v9。在此过程中,我们探索了许多新的可能性,使其更加个性化、强大,并提供更好的开发者体验。

你可以通过以下命令安装新的 @nuxt/eslint 模块:

npx nuxi module add eslint

继续阅读或通过文档了解更多。

背景

ESLint 已成为当今 web 开发的必备工具。它帮助你捕捉错误并在你的项目中强制执行一致的编码风格。在 Nuxt,我们尽力为 ESLint 提供即开即用的体验,使其易于使用、配置并遵循我们推荐的的最佳实践。

由于 Nuxt 和 ESLint 都在持续发展,历史上我们在 Nuxt 中最终得到了几个不同的 ESLint 包和集成,而且对于应该使用哪一个以及为了什么目的使用它并不总是显而易见的。我们从社区收到了很多反馈。

为了改善这种情况并使其面向未来,我们最近更新了我们的 ESLint 集成,以支持带有 flat configESLint v9。它为自定义你的 ESLint 设置新增了许多能力,提供了更直接和统一的体验。

Nuxt ESLint 单仓库

我们将分散在不同仓库中的 ESLint 相关包移至一个单一的单仓库:nuxt/eslint,并配有一个专门的新文档站点:eslint.nuxt.com

为了帮助理解每个包之间的区别以及应该使用什么,我们还有一个常见问题解答页面 FAQ,比较它们并解释它们的作用域。

这个单仓库 monorepo 现在包括:

  • @nuxt/eslint - 针对 Nuxt 3 的全新、一体化的 ESLint 模块,支持项目感知的 ESLint flat config 等。
  • @nuxt/eslint-config - 针对 Nuxt 3 可定制的共享 ESLint 配置。支持 the flat config formatthe legacy format
  • @nuxt/eslint-plugin - 针对 Nuxt 3 的 ESLint 插件提供 Nuxt 特定规则和配置。
  • 两个 Nuxt 2 的维护模式包。

ESLint Flat Config

在深入新的 Nuxt 集成之前,让我向你介绍 ESLint flat config的概念。

Flat config 是在 ESLint v8.21.0 中作为实验性引入的配置格式,并在 ESLint v9 中成为默认格式。

快速参考以区分:

  • Flat config: eslint.config.js eslint.config.mjs 等。
  • Legacy config: .eslintrc .eslintrc.json .eslintrc.js 等。

为什么?

这篇 ESLint 的博客文章 详细解释了 flat config 背后的动机。简而言之,旧的 eslintrc 格式是在 JavaScript 早期设计的,当时 ES 模块和现代 JavaScript 特性尚未标准化。许多隐含的约定涉及其中,而 extends 特性使最终配置结果难以理解和预测。这也使得共享配置难以维护和调试。

{
  "extends": [
    // Solve from `import("@nuxtjs/eslint-config").then(mod => mod.default)`
    "@nuxtjs",
    // Solve from `import("eslint-config-vue").then(mod => mod.default.configs["vue3-recommended"])`
    "plugin:vue/vue3-recommended",
  ],
  "rules": {
    // ...
  }
}

新的 flat config 将插件和配置解析从 ESLint 的内部约定转移到了原生 ES 模块解析。这反过来使其更加明确和透明,甚至允许你从其他模块导入它。由于 flat config 只是一个 JavaScript 模块,它还为更多自定义打开了大门。

Nuxt Flat Config 预设

在最新的 @nuxt/eslint-config 包中,我们利用我们拥有的灵活性,提供了一个工厂函数,允许你以更高级的方式轻松自定义配置预设。以下是如何使用它的示例:

import nuxt from '@nuxt/eslint-config/flat'

export default nuxt()

@nuxt/eslint-config 从无主见的基础配置开始,这意味着我们只包括 TypeScript、Vue 和 Nuxt 的最佳实践规则,并留给你像代码风格、格式化等其他方面来决定。你还可以在默认情况下与 Prettier 一起运行,用于格式化。

配置还允许你根据需要选择加入更多有主见的特性。例如,如果你想让 ESLint 也负责格式化,你可以通过将 features.stylistic 传递给工厂函数来启用它(由 ESLint Stylistic 提供支持):

import nuxt from '@nuxt/eslint-config/flat'

export default nuxt({
  features: {
    stylistic: true
  }
})

或者使用选项对象调整你的偏好(在此处了解更多选项):

import nuxt from '@nuxt/eslint-config/flat'

export default nuxt({
  features: {
    stylistic: {
      semi: false,
      indent: 2, // 4 or 'tab'
      quotes: 'single',
      // ... and more
    }
  }
})

如果你正在编写 Nuxt 模块,你可以通过将 features.tooling 传递给工厂函数来启用 Nuxt 模块开发规则:

import nuxt from '@nuxt/eslint-config/flat'

export default nuxt({
  features: {
    tooling: true
  }
})

flat config 中的工厂函数允许预设覆盖底层 ESLint 配置的复杂性,并为最终用户提供高级和用户友好的抽象,以便自定义。所有这些都不会要求用户担心内部细节。

虽然这种方法为你提供了一个类似于 Prettier 的体验,只需最少的配置(因为它由 ESLint 提供),但你仍然可以完全灵活地自定义和覆盖细粒度的规则和插件,如有必要。

我们还从 eslint-flat-config-utils 制作了一个 FlatConfigComposer 实用工具,使覆盖和扩展 flat config 变得更加容易。@nuxt/eslint-config/flat 中的工厂函数返回一个 FlatConfigComposer 实例:

import nuxt from '@nuxt/eslint-config/flat'

export default nuxt({
  // ...options for Nuxt integration
})
  .append(
    // ...append other flat config items
  )
  .prepend(
    // ...prepend other flat config items before the base config
  )
  // override a specific config item based on their name
  .override(
    'nuxt/typescript', // specify the name of the target config, or index
    {
      rules: {
        // ...override the rules
        '@typescript-eslint/no-unsafe-assignment': 'off'
      }
    }
  )
  // an so on, operations are chainable

通过这种方法,我们得到了简单易用的高级抽象,以及自定义和微调的强大能力。

Nuxt ESLint 模块

进一步推进这一点,我们为 Nuxt 3 制作了全新的一体化 @nuxt/eslint 模块。它利用 Nuxt 的上下文为你的项目生成项目感知和类型安全的 ESLint 配置。

项目感知规则

我们希望启用 eslint-plugin-vue 中的规则 vue/multi-word-component-names 默认情况下,以避免与现有和未来的 HTML 元素冲突。在 Nuxt 项目中,并非所有组件都需要遵循这个规则,这是一个很好的实践。但我们知道在Nuxt项目中,并非所有的.vue文件都被注册为组件。像app.vue、pages/index.vue、layouts/default.vue等文件在其他 Vue 文件中并不作为组件可用,因此这个规则对它们来说是无关紧要的。

通常,我们可以为像这样的文件关闭规则:

export default [
  {
    files: ['*.vue'],
    rules: {
      'vue/multi-word-component-names': 'error'
    }
  },
  {
    files: ['app.vue', 'error.vue', 'pages/**/*.vue', 'layouts/**/*.vue'],
    rules: {
      // disable the rule for these files
      'vue/multi-word-component-names': 'off'
    }
  }
]

它应该适用于大多数情况。然而,我们知道在 Nuxt 中,你可以为每个目录自定义路径,层允许你为每个目录拥有多个来源。这意味着 linter 规则将不够准确,并可能导致用户手动保持它们一致的额外工作。

类似地,我们希望仅对页面和布局启用 vue/no-multiple-template-root 等规则。随着案例的增加,要求用户手动维护规则变得不现实。

这就是 @nuxt/eslint 的魔力所在!它利用 Nuxt 的上下文生成特定于你的项目结构的配置和规则。非常类似于 Nuxt 提供的 .nuxt/tsconfig.json,你现在也有了可以扩展的项目感知的 .nuxt/eslint.config.mjs

要使用它,你可以将模块添加到你的 Nuxt 项目中:

npx nuxi module add eslint

配置检查器 DevTools 集成

在迁移和研究新的 flat config 期间,我想到了为 flat config 制作一个交互式 UI 检查器,使配置更加透明和易于理解。当你安装了 @nuxt/eslint 模块时,我们已经将其集成到 Nuxt DevTools 中,因此你可以在需要时轻松访问它。

Nuxt DevTools 内的截图

检查器允许你查看已启用的最终解析配置、规则和插件,并进行快速匹配,以查看规则和配置如何应用于特定文件。这对于调试和学习 ESLint 在你的项目中如何工作非常有帮助。

我们很高兴 ESLint 团队也认为它很有用,并对将其用于更广泛的 ESLint 社区感兴趣。我们后来加入了这项工作,并将其制作成了官方的 ESLint 配置检查器(顺便说一下,它是用 Nuxt 构建的)。你可以阅读这篇公告文章 以获取更多详细信息。

规则的类型生成

配置 ESLint 的一个主要痛点是规则和配置的类型信息泄露。很难知道特定规则的可用选项是什么,你需要在每个规则的文档之间跳转以弄清楚。

再次感谢新的 flat config 具有如此多的可能性,我们发现了一个新工具 eslint-typegen,我们可以基于你实际使用的插件为每个规则生成相应的类型,基于规则配置模式。这意味着它是一个通用解决方案,适用于任何 ESLint 插件,并且类型始终是准确和最新的。

@nuxt/eslint 模块中,这个特性已经集成开箱即用,这样你就可以立即获得这种惊人的体验:

ESLint 规则配置截图

开发服务器检查器

有了这个新模块,我们有机会将 @nuxtjs/eslint-module 和 ESLint 的开发服务器检查器合并到新的 @nuxt/eslint 模块中,作为一个可选功能。

注意 大多数时候你可能不需要这个特性,因为你的编辑器集成应该已经在你的编辑器中提供了 ESLint 诊断。然而,对于一些使用不同编辑器的团队,并希望确保 ESLint 始终在运行,能够在开发服务器中运行 ESLint 在某些情况下可能会有所帮助。

要启用它,你可以在模块选项中将检查器 checker 选项设置为 true:

export default defineNuxtConfig({
  modules: [
    '@nuxt/eslint'
  ],
  eslint: {
    checker: true // <---
  }
})

每当你有一些 ESLint 错误时,你将在控制台和浏览器中看到一个警告。要了解更多关于这个特性的信息,你可以查看文档

模块钩子函数

既然我们现在在 Nuxt 模块中拥有 codegen 能力和项目感知配置,我们实际上可以用这个做更多有趣的事情。其中之一是允许模块也贡献到 ESLint 配置中。想象一下,在未来,当你安装一个像 @nuxtjs/i18n 这样的 Nuxt 模块时,它可以自动为 i18n 相关文件启用特定的 ESLint 规则,或者当你安装像 @pinia/nuxt 这样的东西时,它可以安装 Pinia ESLint 插件以强制执行 Pinia 的最佳实践等。

作为一项实验,我们制作了一个模块 nuxt-eslint-auto-explicit-import,它可以自动插入 Nuxt 项目中注册的自动导入,并预配置了 ESLint 预设。这样,你就可以在使用 API 时获得自动导入的相同良好的开发体验,但在你的代码库中仍然有自动插入的显式导入。

这仍然处于早期阶段,我们仍在探索可能性和最佳实践。但我们对潜力和它所开启的机会感到非常兴奋。我们将与社区合作,看看我们如何充分利用它。如果你有任何想法或反馈,请毫不犹豫地与我们分享!

生态系统

在 Nuxt,我们一直非常关心生态系统和社区。在我们探索采用新的 flat config 并改善开发者体验的过程中,我们制作了很多工具来实现这一目标。它们都是通用的,并且可以在 Nuxt 之外使用:

我们致力于支持更广泛的社区,并与开发者合作改进这些工具并扩展它们的可能性。我们很高兴看到这些工具如何使 ESLint 生态系统受益,并为整体开发者体验做出贡献。

未来

flat config 格式仍然相当新,ESLint v9 也只是在几周前刚刚发布。插件和社区正在逐渐适应新的格式。它仍处于探索和实验阶段。

展望未来,我们渴望看到 ESLint 生态系统将如何继续发展,以及我们如何利用新的能力和可能性进一步增强 Nuxt 开发者的体验。我们致力于为 Nuxt 用户提供无缝而强大的开发环境,我们将继续探索新的想法并与社区合作以实现这一目标。

评论