Vue 3 Project Setup and Configuration Guide

Project Initialization with pnpm

Some advantages: approximately 2x faster than similar tools, saves disk space...

https://www.pnpm.cn/

Installation:

npm install -g pnpm

Creating a project:

pnpm create vue

ESLint & Prettier Configuration

Environment Synchronization:

  1. Install the ESLint plugin and enable auto-fix on save
  2. Disable the Prettier plugin and turn off auto-formatting on save
// ESLint plugin + VSCode configuration for auto-formatting and fixing
"editor.codeActionsOnSave": {
    "source.fixAll": true
},
"editor.formatOnSave": false,

.eslintrc.cjs Configuration File

  1. Prettier style configuration: https://prettier.io
    • Single quotes
    • No semicolons
    • Maximum 80 characters per line
    • No trailing commas in objects/arrays
    • Line endings not restricted (Windows/Mac inconsistency)
  2. Vue component names should consist of multiple words (ignoring index.vue)
  3. Props destructuring disabled
rules: {
    'prettier/prettier': [
      'warn',
      {
        singleQuote: true, // Single quotes
        semi: false, // No semicolons
        printWidth: 80, // Maximum 80 characters per line
        trailingComma: 'none', // No trailing commas in objects/arrays
        endOfLine: 'auto' // Line endings not restricted (Windows/Mac inconsistency)
      }
    ],
    'vue/multi-word-component-names': [
      'warn',
      {
        ignores: ['index'] // Vue component names should be multiple words (ignores index.vue)
      }
    ],
    'vue/no-setup-props-destructure': ['off'], // Disable props destructuring validation
    // Added undefined variable error support, create-vue@3.6.3 has this disabled, adding for next chapter demonstration.
    'no-undef': 'error'
  }

Husky-Based Code Checking Workflow

Husky is a Git hooks tool that executes specific commands at particular moments in Git operations.

Husky Configuration

  1. Initialize Git: git init
  2. Initialize Husky tool configuration

https://typicode.github.io/husky/

The init command simplifies Husky setup in your project. It creates a pre-commit script in .husky/ and updates the prepare script in package.. You can then modify it according to your workflow.

pnpm dlx husky-init && pnpm install

In v7, pnpm dlx is the same as pnpx. It downloads a package and executes it.

When you need to create an application, pnpm create is shorthand for pnpm dlx.

For example, pnpm create react-app my-app will download the create-react-app package and run it to bootstrap a React application. This is equivalent to running pnpm dlx create-react-app my-app.

There's also pnpm exec, which doesn't download packages but only runs a package already in node_modules/.bin.

Modify .husky/pre-commit file

pnpm lint

Issue: By default, it performs a full check, which can be time-consuming and may reveal historical issues.

lint-staged Configuration

Installation:

pnpm i lint-staged -D

Configure package.:

{
  // ... omitted ...
  "lint-staged": {
    "*.{js,ts,vue}": [
      "eslint --fix"
    ]
  }
}

{
  "scripts": {
    // ... omitted ...
    "lint-staged": "lint-staged"
  }
}

Modify .husky/pre-commit file:

pnpm lint-staged

Project Directory Structure Adjustment

The default generated directory structure doesn't meet our development requirements, so we need to make some custom modifications. The main tasks are:

  • Delete default initialization files
  • Modify remaining code content
  • Add new directory structures as needed
  • Copy initialization resource files and install preprocessor plugins
  1. Delete files
  2. Modify content

src/router/index.js

import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: []
})

export default router

src/App.vue

<script setup></script>

<template>
  <div>
    <router-view></router-view>
  </div>
</template>

<style scoped></style>

src/main.js

import { createApp } from 'vue'
import { createPinia } from 'pinia'

import App from './App.vue'
import router from './router'

const app = createApp(App)

app.use(createPinia())
app.use(router)
app.mount('#app')
  • Add required directories: api, utils
  • Copy global styles and image files needed for the project to the assets folder, and import global styles in main.js
import '@/assets/main.scss'

Install sass dependency

pnpm add sass -D

VueRouter4 Implementation

Basic Code Analysis

import { createRouter, createWebHistory } from 'vue-router'

// createRouter creates a routing instance, equivalent to new VueRouter()
// 1. History mode: createWebHistory() http://xxx/user
// 2. Hash mode: createWebHashHistory() http://xxx/#/user

// import.meta.env.BASE_URL in Vite is an environment variable: 
// Environment variables and modes | Vite Official Chinese Documentation
// https://vitejs.dev/guide/build.html#public-base-path

// If you deploy to a domain path like: http://xxx/my-path/user
// Add configuration to vite.config.ts: base: my-path, the route will then have the my-path prefix

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: []
})

export default router

Introducing Element UI Component Library

Official documentation: https://element-plus.org/zh-CN/

Installation:

$ pnpm add element-plus

Automatic On-Demand Import:

Install plugins:

pnpm add -D unplugin-vue-components unplugin-auto-import

Add the following code to your Vite or Webpack configuration file:

...
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    ...
    AutoImport({
      resolvers: [ElementPlusResolver()]
    }),
    Components({
      resolvers: [ElementPlusResolver()]
    })
  ]
})

Direct Usage:

<template>
  <div>
    <el-button type="primary">Primary</el-button>
    <el-button type="success">Success</el-button>
    <el-button type="info">Info</el-button>
    <el-button type="warning">Warning</el-button>
    <el-button type="danger">Danger</el-button>
    ...
  </div>
</template>

Easter egg: Files in the components directory are automatically registered by default!

Pinia - Building User Store and Persistence

Official documentation: https://prazdevs.github.io/pinia-plugin-persistedstate/zh/

  1. Install the pinia-plugin-persistedstate plugin
pnpm add pinia-plugin-persistedstate -D
  1. Use in main.js
import persist from 'pinia-plugin-persistedstate'
...
app.use(createPinia().use(persist))
  1. Configure stores/user.js
import { defineStore } from 'pinia'
import { ref } from 'vue'

// User module
export const useUserStore = defineStore(
  'big-user',
  () => {
    const token = ref('') // Define token
    const setToken = (t) => (token.value = t) // Set token

    return { token, setToken }
  },
  {
    persist: true // Persistence
  }
)

Pinia - Unified Store Management

Pinia independent maintenance

  • Current situation: Initialization code is in main.js, store code is in stores, code is scattered and functions are not unified
  • Optimization: Unified maintenance by stores, complete pinia initialization in stores/index.js, and deliver to main.js for use

Store unified export

  • Current situation: Using a store requires importing from different paths like import { useUserStore } from './stores/user.js'
  • Optimization: Unified export from stores/index.js, unified import path './stores', and store maintenance in stores/modules

Data Interaction - Request Tool Design

1. Creating an axios instance

We'll use axios to request backend APIs. Typically, axios is configured (e.g., base URL, etc.).

In general project development, axios is often encapsulated as a separate module for easy use.

Install axios:

pnpm add axios

Create utils/request.js to encapsulate the axios module

Use axios.create to create a custom axios instance

http://www.axios-js.com/zh-cn/docs/#axios-create-config

import axios from 'axios'

const baseURL = 'http://big-event-vue-api-t.itheima.net'

const instance = axios.create({
  // TODO 1. Base URL, timeout
})

instance.interceptors.request.use(
  (config) => {
    // TODO 2. Carry token
    return config
  },
  (err) => Promise.reject(err)
)

instance.interceptors.response.use(
  (res) => {
    // TODO 3. Handle business failure
    // TODO 4. Extract core response data
    return res
  },
  (err) => {
    // TODO 5. Handle 401 error
    return Promise.reject(err)
  }
)

export default instance

2. Complete axios basic configuration

import { useUserStore } from '@/stores/user'
import axios from 'axios'
import router from '@/router'
import { ElMessage } from 'element-plus'

const baseURL = 'http://big-event-vue-api-t.itheima.net'

const instance = axios.create({
  baseURL,
  timeout: 100000
})

instance.interceptors.request.use(
  (config) => {
    const userStore = useUserStore()
    if (userStore.token) {
      config.headers.Authorization = userStore.token
    }
    return config
  },
  (err) => Promise.reject(err)
)

instance.interceptors.response.use(
  (res) => {
    if (res.data.code === 0) {
      return res
    }
    ElMessage({ message: res.data.message || 'Service exception', type: 'error' })
    return Promise.reject(res.data)
  },
  (err) => {
    ElMessage({ message: err.response.data.message || 'Service exception', type: 'error' })
    console.log(err)
    if (err.response?.status === 401) {
      router.push('/login')
    }
    return Promise.reject(err)
  }
)

export default instance
export { baseURL }

Tags: vue3 Project Setup ESLint Prettier Husky

Posted on Fri, 08 May 2026 19:33:46 +0000 by cuboidgraphix