Setting up lint-staged for Vue projects: A step-by-step guide

After setting up a new Vue3 app using the Vue CLI and configuring Prettier as my linter, I decided to implement commitlint, husky, and lint-staged for validating commit messages and linting the code before pushing it.

My Approach

Following the instructions at , I configured commitlint with husky by running the commands:

npm install --save-dev @commitlint/{cli,config-conventional}
echo "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js

npm install husky --save-dev
npx husky install
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit $1'

Next, based on the guidelines at https://github.com/okonet/lint-staged#installation-and-setup, I set up lint-staged with the following command:

npx mrm@2 lint-staged

Then, within the package.json file, I replaced the existing lint-staged configuration with:

"lint-staged": {
  "*": "npm run lint"
}

The Issue

Upon modifying the README.md file in the project and attempting to commit the changes, an error message was encountered:

[... Error message details ...]

Desired Outcome

I aim to only fix files that have been modified, ensuring that the linter focuses on "lintable" files (js, ts, vue, html, etc.). The goal is to avoid errors when utilizing lint-staged with the setup configuration of

"*": "npm run lint"
.

What is the correct approach for configuring lint-staged to target "lintable" files exclusively?

Answer №1

Update on comments concerning lint-staged syntaxes

Different options for lint-staged syntax

I proposed the use of

"**/*.{js,vue}": ["npm run lint:js:fix"]
. Keep in mind that the choice of lint:js:fix is subjective and can be customized to your preferences. It follows the naming convention used by Kent C Dodds, but you could opt for something like lint:watermelon-potato-hehe if you prefer.

In terms of your suggestions:

  1. "**/*.{vue,js,jsx,ts,tsx}": "npm run lint"
    , this configuration covers a wider range of extensions, which is perfectly okay. While .tsx/.jsx may not be commonly used among Vue developers, incorporating .ts might require additional plugins in your ESlint setup. Personally, I recommend checking out tools like Vitesse for starting a Vue3 project with TypeScript support.

Regarding the second part, I generally prefer setting up my own ESlint configuration using eslint --ext .js,.vue --fix. This way, I have more control over the process and better visibility into any troubleshooting that might be required. While tools like vue-cli-service lint offer default configurations tailored for Vue projects, I lean towards creating a personalized Vue configuration alongside vanilla ESlint for a more tailored approach.

If speed is your priority, utilizing vue-cli-service lint for quick linting can be helpful. However, for a more precise configuration and smoother workflow, opting for vanilla ESlint provides greater flexibility and control, potentially reducing issues in the long run.

  1. "**/*.{vue,js,jsx,ts,tsx}": "eslint --ext .vue,.js,.jsx,.ts,.tsx --fix"
    . Although both sides contain similar scripts like lint:js:fix, the addition of extra extensions on the right side allows for further coverage.

You might wonder why we specify extensions on the left for lint-staged and on the right for lint:js:fix? The extensions on the right side are not strictly necessary (as far as I know) since lint-staged only executes commands for the specified extensions on the left. However, being explicit about targeted extensions enhances clarity and enables running npm run lint:js:fix in the CLI without triggering errors on unhandled files such as .txt, .json, .md, or .jpg.

Experimentation is key here—if unsure, consider testing different setups to find the most efficient solution for your needs.

  1. "**/*.{vue,js,jsx,ts,tsx}": "eslint --fix"
    . This configuration may function effectively based on previous explanations, although I haven't personally tested it.
Exploring other file extensions

For .html files, they should be minimal within your Vue project. Utilize W3C validator to ensure compliance if necessary. In terms of HTML within template tags in your .vue files, these sections will undergo proper ESlint checks. Incorporating Prettier complements this setup, offering convenient auto-formatting capabilities once a team-wide .prettierrc configuration is established.

As for .json files, ESlint doesn't handle them natively. To lint/format .json or other specific extensions, explore relevant NPM packages that suit your requirements and integrate them into your pipeline using configurations like

"**/*.json": ["npm run lint-my-json-please"]
.

Ultimately, husky and lint-staged streamline tasks that could manually be performed via the CLI. If you're satisfied with manual execution and results, transitioning to automation requires identifying suitable packages and configuring them accordingly.


In your package.json, consider including the following:

"scripts": {
  "lint:js": "eslint . --ext .js,.vue",
  "lint:js:fix": "eslint --ext .js,.vue --fix",
},

In your .lintstagedrc:

{
  "**/*.{js,vue}": ["npm run lint:js:fix"]
}

In .husky/pre-commit:

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npm run lint-staged

In .husky/commit-msg:

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx --no-install commitlint --edit ""

Consider setting up ESlint error tracking in VSCode for real-time monitoring and automatic formatting upon saving files.

Now, either manually run npm run lint:js for issue detection, or let husky execute lint-staged and apply eslint --fix exclusively to modified .js and .vue files during commits.

Your commitlint.config.js configuration should suffice!


To recap, lint:js examines all JS and Vue files, whereas during commits triggered by husky and lint:js:fix, only touched files undergo linting—this exemplifies the essence of selective linting facilitated by lint-staged.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

I am encountering an issue stating "indexRouter has not been defined"

Encountering an error "indexRouter is not defined" while attempting to run the code below. Despite attempts to remove the line, additional errors persist. Can anyone clarify the rationale behind using the common variable router for both index.js and user.j ...

What mechanism does package.json use to determine whether you are currently operating in development or production mode?

What is the process for package_json to determine when to load devDependencies as opposed to regular dependencies? How does it differentiate between local development and production environments? ...

Tips on how to connect the scope from a controller to a custom directive in Angular

Currently, I am delving into the world of Angular and finding myself immersed in directive lessons. However, as I engage in some practice exercises, I have encountered a stumbling block. Specifically, I have developed a custom directive with the intention ...

Relay information between requests using a RESTful API and various data formats, such as JSON, XML, HTML

In a scenario with a REST API that can deliver JSON, XML, HTML, and other formats, the default response for browsers without JavaScript enabled is HTML. This API utilizes tokens for authentication and authorization. Within a traditional website project, t ...

Issue with mapStateToProps not reflecting changes in props after localStorage modification

Currently, I am working on a redux application that involves authentication. My main concern right now is ensuring that the user remains logged in whenever they interact with the app. Below is a snippet from the bottom of my App.jsx file: function mapStat ...

Tips for implementing an if else statement in ReactJS while utilizing the useEffect hook

Below is the code snippet for returning a Plotly graph. I would like to display a message or alternative layout when there is no data available for the graph, such as showing "No data available". How can I achieve this? import React, { useEffect } from ...

Issue accessing object property in Handlebars template with ExpressJs

Personalized Routes: router.use(function(req, res, next) { res.locals.currentUser = req.user; next(); }); /* Accessing the home page. */ router.get('/', function(req, res, next) { console.log(res.locals.currentUser.username); ==>> t ...

Angular @Input set function not being activated during unit testing

Within my Component @Input('price') set setPrice(price) { this.price = price; this.modifyTotalAmount(); } Unit Testing (component.spec.ts) it('should execute function ', () => { spyOn(fixture.componentInstance, ' ...

Conceal one object when the other is revealed?

Is there a way to hide the element with the class .close-button while showing another element with the ID #loading-animation? Can jQuery conditionals help achieve this? For example: if ($('#loading-animation').is(':visible')) { $ ...

javascript show and hide navigation bar

I am currently working on a HTML menu that includes a button to open it and an unordered list : <nav class="menu"> <button> <h1>Menu</h1> </button> <ul class="mylist" ...

When using addClass("test"), it throws an error message: TypeError: undefined is not a function

Upon examination in the console, I discovered the following: $(".myCssClass")[0].parentNode <li><span class="myCssClass">some text</span></li> I am attempting to add a CSS class to the parent span tag within the <li> element ...

What is the best way to reach a link using Selenium?

Challenge : Unable to interact with a link using JavaScript through Selenium. Attempted Solutions: element = driver.find_element_by_css_selector(a {href: "javascript:void(0)"}) resulted in a SyntaxError. element = driver.execute_script("ja ...

Creating a custom design for legends in Chart.js

I'm currently working on a project using chart.js and I'm trying to customize the label/legend styling for my chart. My goal is to replace the rectangular legend with a circular one. I've come across the suggestion of creating a custom legen ...

Creating a fresh JSON structure by utilizing an established one

I have a JSON data that contains sections and rubrics, but I only need the items for a new listing. The new object named 'items' should consist of an array of all the items. The final JSON output should be sorted by the attribute 'name&apos ...

Issue with Bootstrap modal not closing

I've encountered an issue with a bootstrap modal popup. When I try to close the popup, it doesn't behave as expected. Instead of just hiding the popup and removing the backdrop, it hides the popup but adds another backdrop, making the screen almo ...

Step-by-step guide to implementing a sticky header while scrolling

How can I implement a fixed header on scroll, like the one seen on this website: www.avauntmagazine.com Here is the HTML for my header: <div class="bloc bgc-wild-blue-yonder l-bloc " id="bloc-1"> <div class="container bloc-sm"> &l ...

get data from a JSON array with no specific name on the provided URL

Struggling to extract specific values from a JSON file located at the following URL: The content of the URL data is as follows: [ { "key":{ "parentKey":{ "kind":"user", "id":0, "name":"test 1" }, ...

Observing the timepiece malfunctioning beyond expectations

Let me explain the issue here in a simple way. I have a parent component where I execute a method that changes a property value of an object called products. This is working fine. However, when I pass this object as a prop to a child component and watch i ...

Store the current function in the cache, incorporate new features, and execute those additions upon calling another function

I have a pre-existing function that I am unable to directly access or modify. Due to this limitation, I have resorted to caching the function and incorporating additional functions alongside it. This function loads periodically, sometimes occurring on pag ...

Updating the value of a key in an object is not functioning as expected

There is a single object defined as requestObject: any = { "type": 'type1', "start": 0, "size": 10, "keywords": ['abcd','efgh'], filters: [], } Next, attempting to change the value for keyword, I updat ...