Skip to content

Vp fmt and lint: extends as an alternative to overrides #1769

@destroyer22719

Description

@destroyer22719

Description

Current: overrides (verbose)

Every override must fully repeat all base plugins and rules, forcing each overrides entry starts from a clean slate:

export default defineConfig({
  lint: {
    plugins: ["typescript", "jsdoc", "import", "promise"],
    rules: {
      "typescript/no-unnecessary-type-assertion": "error",
      "typescript/no-unsafe-type-assertion": "error",
      "typescript/array-type": "error",
      "typescript/no-explicit-any": "error",
      "typescript/explicit-function-return-type": "error",
      "typescript/consistent-type-definitions": ["error", "type"],
      "typescript/no-non-null-assertion": "error",
      "typescript/consistent-type-imports": "error",
      "typescript/consistent-type-assertions": ["error", { assertionStyle: "never" }],
    },
    overrides: [
      {
        files: ["apps/web/**"],
        // Must list ALL base plugins again + add "vue"
        plugins: ["typescript", "jsdoc", "import", "promise", "vue"],
        // Must list ALL base rules again + add vue rules
        rules: {
          "typescript/no-unnecessary-type-assertion": "error",
          "typescript/no-unsafe-type-assertion": "error",
          "typescript/array-type": "error",
          "typescript/no-explicit-any": "error",
          "typescript/explicit-function-return-type": "error",
          "typescript/consistent-type-definitions": ["error", "type"],
          "typescript/no-non-null-assertion": "error",
          "typescript/consistent-type-imports": "error",
          "typescript/consistent-type-assertions": ["error", { assertionStyle: "never" }],
          "vue/component-name-in-template-casing": ["error", "PascalCase"],
          "vue/html-self-closing": "error",
        },
      },
      {
        files: ["apps/api/**"],
        //  Must repeat ALL base plugins + add "node"
        plugins: ["typescript", "jsdoc", "import", "promise", "node"],
        env: { node: true },
        // Must repeat ALL base rules + add node rules
        rules: {
          "typescript/no-unnecessary-type-assertion": "error",
          "typescript/no-unsafe-type-assertion": "error",
          "typescript/array-type": "error",
          "typescript/no-explicit-any": "error",
          "typescript/explicit-function-return-type": "error",
          "typescript/consistent-type-definitions": ["error", "type"],
          "typescript/no-non-null-assertion": "error",
          "typescript/consistent-type-imports": "error",
          "typescript/consistent-type-assertions": ["error", { assertionStyle: "never" }],
          "node/no-process-env": "error",
          "node/no-unsupported-features/es-syntax": "error",
        },
      },
    ],
  },
});

Problems:

  • ~50 lines just for two overrides
  • Adding or changing a base rule means updating every override
  • Easy to forget to sync rules between overrides, leading to inconsistent linting
  • The plugins list triples in length and omitting it means "inherit nothing"

Proposed: extends (inherits base)

extends entries inherit the base plugins, rules, options, and env — you only add/override what differs:

export default defineConfig({
  lint: {
    plugins: ["typescript", "jsdoc", "import", "promise"],
    rules: {
      "typescript/no-unnecessary-type-assertion": "error",
      "typescript/no-unsafe-type-assertion": "error",
      "typescript/array-type": "error",
      "typescript/no-explicit-any": "error",
      "typescript/explicit-function-return-type": "error",
      "typescript/consistent-type-definitions": ["error", "type"],
      "typescript/no-non-null-assertion": "error",
      "typescript/consistent-type-imports": "error",
      "typescript/consistent-type-assertions": ["error", { assertionStyle: "never" }],
    },
    extends: [
      {
        files: ["apps/web/**"],
        //  Only add "vue" — base plugins are inherited
        plugins: ["vue"],
        // Only add vue-specific rules — base rules inherit automatically
        rules: {
          "vue/component-name-in-template-casing": ["error", "PascalCase"],
          "vue/html-self-closing": "error",
        },
      },
      {
        files: ["apps/api/**"],
        // Only add "node" — base plugins inherited
        plugins: ["node"],
        env: { node: true },
        // Only add node-specific rules
        rules: {
          "node/no-process-env": "error",
          "node/no-unsupported-features/es-syntax": "error",
        },
      },
    ],
  },
});

Validations

  • Read the Contributing Guidelines.
  • Confirm this request is for Vite+ itself and not for Vite, Vitest, tsdown, Rolldown, or Oxc.
  • Check that there isn't already an issue requesting the same feature.

Metadata

Metadata

Assignees

Priority

None yet

Start date

None yet

Target date

None yet

Effort

None yet

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions