Vue3脚手架实现(七、渲染eslint配置)

192 阅读4分钟

Vue3脚手架实现(一、整体介绍)

Vue3脚手架实现(二、项目环境搭建)

Vue3脚手架实现(三、命令行读取配置)

Vue3脚手架实现(四、模板渲染流程、渲染一个基础项目)

Vue3脚手架实现(五、渲染jsx和prettier配置)

Vue3脚手架实现(六、渲染router和pinia)

Vue3脚手架实现(七、渲染eslint配置)

Vue3脚手架实现(八、渲染vitest配置)

Vue3脚手架实现(九、渲染typescript配置)

Vue3脚手架实现(十、补之前配置)

Vue3脚手架实现(十一、打包项目)


【注意】本期文件改为ts之后,类型会报错,我们后面会出一期文章修改对应的内容。主要是npm init @eslint/config@latest,似乎最新的就是会报错类型报错,如下图我们通过npm init @eslint/config@latest创建的mts文件

image.png


eslint的渲染,我看的相关的create-vue源码中,使用了@vue/create-eslint-config这个包

我们这里直接自己写ejs来进行渲染吧,这样方便自己随意控制

有关eslint可以先看下 eslint官网

eslint配置初识

可以通过eslint生成相关的配置npm init @eslint/config@latest,选择的配置如下

  • 没有ts配置

    • 选取配置 image.png

    • eslint.config.mjs

      import js from "@eslint/js";
      import globals from "globals";
      import pluginVue from "eslint-plugin-vue";
      import { defineConfig } from "eslint/config";
      
      export default defineConfig([
        { files: ["**/*.{js,mjs,cjs,vue}"], plugins: { js }, extends: ["js/recommended"] },
        { files: ["**/*.{js,mjs,cjs,vue}"], languageOptions: { globals: globals.browser } },
        pluginVue.configs["flat/essential"],
      ]);
      
      
    • package.json中的依赖有

      "devDependencies": {
        "@eslint/js": "^9.30.1",
        "eslint": "^9.30.1",
        "eslint-plugin-vue": "^10.3.0",
        "globals": "^16.3.0"
      }
      
  • 有ts配置

    • 配置选择 image.png

    • eslint.config.mjs

    import js from "@eslint/js";
    import globals from "globals";
    import tseslint from "typescript-eslint";
    import pluginVue from "eslint-plugin-vue";
    import { defineConfig } from "eslint/config";
    
    export default defineConfig([
      { files: ["**/*.{js,mjs,cjs,ts,mts,cts,vue}"], plugins: { js }, extends: ["js/recommended"] },
      { files: ["**/*.{js,mjs,cjs,ts,mts,cts,vue}"], languageOptions: { globals: globals.browser } },
      tseslint.configs.recommended,
      pluginVue.configs["flat/essential"],
      { files: ["**/*.vue"], languageOptions: { parserOptions: { parser: tseslint.parser } } },
    ]);
    
    • package.json中的依赖有
    "devDependencies": {
       "@eslint/js": "^9.30.1",
      "eslint": "^9.30.1",
      "eslint-plugin-vue": "^10.3.0",
      "globals": "^16.3.0",
      "typescript-eslint": "^8.35.1"
    }
    

我们可以抽离一下相关的配置,对于eslint的配置,我们单开一个eslint文件夹进行管理。对于eslint的配置base文件夹就是最基础渲染的配置,如果有typescript配置,我们就在一个typescript文件夹中进行管理。

eslint基础配置

  • 相关.vscode配置template\config\eslint\.vscode\
    • extensions.json:插件推荐
      {
        "recommendations": ["dbaeumer.vscode-eslint"]
      }
      
      
    • settings.json:仅修复工具明确声明可自动修复的问题
      {
        "editor.codeActionsOnSave": {
          "source.fixAll": "explicit"
        }
      }
      
      
  • 基础配置:template\eslint\base
    • package.json:我们添加基础的依赖,以及lint命令
      {
        "scripts": {
          "lint": "eslint . --fix"
        },
        "devDependencies": {
          "@eslint/js": "^9.30.1",
          "eslint": "^9.30.1",
          "eslint-plugin-vue": "^10.3.0",
          "globals": "^16.3.0"
        }
      }
      
      
    • eslint.config.mjs.ejs
      import js from '@eslint/js';
      import globals from 'globals';
      import { defineConfig } from 'eslint/config';
      <%_ for (const { importer } of importerList) { _%>
      <%- importer %>
      <%_ } _%>
      
      export default defineConfig([
        <%_ for (const { config } of configList) { _%>
        <%- config %>
        <%_ } _%>
      ])
      
      
      
    • eslint.config.mjs.data.mjs
      export default function getData() {
        return {
          importerList: [
            {
              id: 'pluginVue',
              importer: "import pluginVue from 'eslint-plugin-vue'",
            },
          ],
          configList: [
            {
              id: 'pluginJs',
              config:
                "{ files: ['**/*.{js,mjs,cjs,vue}'], plugins: { js }, extends: ['js/recommended'] },",
            },
            {
              id: 'globals',
              config:
                "{ files: ['**/*.{js,mjs,cjs,vue}'], languageOptions: { globals: globals.browser } },",
            },
            {
              id: 'pluginVue',
              config: "pluginVue.configs['flat/essential'],",
            },
          ],
        }
      }
      
      
      
  • 在index.ts中加入相关代码
const create = async (name: string, options: Options) => {
  ...
  if (needsPinia) {
    render('config/pinia')
  }
  if (needsEslint) {
    render('config/eslint')
    render('eslint/base') // eslint基础配置
  }
  ...
}

有typescript的情况下的eslint配置

如果我们要渲染有typescript的时候的eslint配置的话,需要有几个点

  • package.json的相关包的引入
  • files文件配置的后缀的更改
  • ts的推荐配置
  • vue文件的相关解析器
  • 如果需要在ts的时候,将eslint.config.mjs改为eslint.config.mts文件的话就需要增加这个包配置jiti,相关说明可以见eslint的相关文档。因为这个只是配置文件,我们就用mjs就好,所以我们这里不加这个包,如果有需要用ts的eslint配置文件就自行加入一下这个包即可

那我们可以继续进行配置

  • template\eslint\typescript\eslint.config.mjs.data.mjs:在指定的位置插入对应的配置,或者修改指定id的配置即可

    export default function getData({ oldData }) {
      const tseslintImporter = {
        id: 'tseslint',
        importer: "import tseslint from 'typescript-eslint'",
      }
      const jsPlugins = {
        id: 'pluginJs',
        config:
          "{ files: ['**/*.{js,mjs,cjs,ts,mts,cts,vue}'], plugins: { js }, extends: ['js/recommended'] },",
      }
      const globals = {
        id: 'globals',
        config:
          "{ files: ['**/*.{js,mjs,cjs,ts,mts,cts,vue}'], languageOptions: { globals: globals.browser } },",
      }
      const tseslintConfig = {
        id: 'tseslint',
        config: 'tseslint.configs.recommended,',
      }
      const vueTsParserConfig = {
        id: 'vueTsParser',
        config:
          "{ files: ['**/*.vue'], languageOptions: { parserOptions: { parser: tseslint.parser } } },",
      }
    
      const importerList = oldData.importerList.flatMap((importItem) => {
        return importItem.id === 'pluginVue' ? [tseslintImporter, importItem] : importItem
      })
      const configList = oldData.configList.flatMap((configItem) => {
        if (configItem.id === jsPlugins.id) {
          configItem.config = jsPlugins.config
          return configItem
        }
        if (configItem.id === globals.id) {
          configItem.config = globals.config
          return configItem
        }
        if (configItem.id === 'pluginVue') {
          return [tseslintConfig, configItem, vueTsParserConfig]
        }
        return configItem
      })
      const data = {
        importerList,
        configList,
      }
      return data
    }
    
    
  • template\eslint\typescript\package.json

    {
      "devDependencies": {
        "typescript-eslint": "^8.35.1"
      }
    }
    
    
  • index.ts中增加代码

const create = async (name: string, options: Options) => {
  ...

  // 添加对应的配置
  ...
  if (needsEslint) {
    render('config/eslint')
    render('eslint/base') // eslint基础配置
    if (needsTypeScript) {
      render('eslint/typescript')
    }
  }
  ...
}

有prettier的情况下的eslint配置

使用prettier的时候,eslint和prettier之间可能会有冲突

我们可以使用eslint-config-prettier关闭与 Prettier 冲突或不必要的规则,相关说明见官方文档,包的使用见这里

  • template\eslint\prettier\package.json
{
  "devDependencies": {
    "eslint-config-prettier": "^10.1.5"
  }
}

  • template\eslint\prettier\eslint.config.mjs.data.mjs:我们是eslint 9的flat配置,所以需要注意下import的路径,对应官方文档的使用中有示例
export default function getData({ oldData }) {
  oldData.importerList.push({
    id: 'eslintConfigPrettier',
    importer: "import eslintConfigPrettier from 'eslint-config-prettier/flat'",
  })
  oldData.configList.push({
    id: 'eslintConfigPrettier',
    config: 'eslintConfigPrettier, // 放在最后,关闭和prettier冲突的规则',
  })
  return oldData
}

  • index.ts中增加代码
const create = async (name: string, options: Options) => {
  ...

  // 添加对应的配置
  ...
  if (needsEslint) {
    render('config/eslint')
    render('eslint/base') // eslint基础配置
    if (needsTypeScript) {
      render('eslint/typescript')
    }
    if (needsPrettier) {
      render('eslint/prettier')
    }
  }
  ...
}