Bootstrap

基于Vite构建企业级前端项目

Vite + Vue3 + TS前端企业级项目搭建

想了解项目的最新动态,以及更多知识? 👉 mood-blog-front

Vite脚手架构建项目

开发环境

  1. 开发编辑器:vscode-v1.84.2
  2. 包管理工具:pnpm -v8.10.5、npm-v10.2.3
  3. 脚手架:vite-v5.0.2
  4. Nodejs:node-v18.18.2
  5. 预编译样式:sass-v1.69.5
  6. 组件库:Element Plus-v2.4.2
  7. 浏览器:版本 119.0.6045.106(正式版本) (64 位)
  8. 状态管理:pinia-v2.1.7
  9. 国际化:vue-i18n-v9.4.1
  10. 路由管理:vue-router-v4.2.5
  11. Ajax请求:axios-v1.6.2、@types/axios-v0.14.0
  12. 生成注释插件:koroFileHeader-v4.9.3 (文件快捷键:ctrl + win + i,函数快捷键:ctrl + win + t,随机搞笑图:ctrl + win + j)
  • 构建项目
pnpm create vite my-vue-app --template vue-ts
  • 安装依赖
pnpm install
  • 完整的package.json文件

    {
      "name": "mood-blog-front",
      "private": true,
      "version": "0.0.0",
      "type": "module",
      "scripts": {
        "dev": "vite --host",
        "build": "vue-tsc && vite build",
        "build:pre": "vue-tsc --noEmit && vite build --mode staging",
        "build:pro": "vue-tsc --noEmit && vite build --mode production",
        "preview": "vite preview",
        "prepare": "husky install",
        "lint:create": "eslint --init",
        "lint:css": "stylelint **/*.{vue,css,sass,scss} --fix",
        "lint": "eslint \"src/**/*.{js,vue,ts,jsx,tsx}\" --fix",
        "format": "prettier --config .prettierrc.cjs \"src/**/*.{vue,js,ts,jsx,tsx}\" --write"
      },
      "dependencies": {
        "axios": "^1.6.2",
        "dayjs": "^1.11.10",
        "element-plus": "^2.4.2",
        "normalize.css": "^8.0.1",
        "nprogress": "^0.2.0",
        "pinia": "^2.1.7",
        "qs": "^6.11.2",
        "vue": "^3.3.8",
        "vue-i18n": "^9.4.1",
        "vue-router": "^4.2.5"
      },
      "lint-staged": {
        "*.{js,jsx,vue,ts,tsx}": [
          "npm run lint",
          "npm run format"
        ],
        "*.{vue,sass,scss,css}": [
          "npm run lint:css"
        ]
      },
      "devDependencies": {
        "@commitlint/cli": "^18.4.3",
        "@commitlint/config-conventional": "^18.4.3",
        "@types/axios": "^0.14.0",
        "@types/eslint": "^8.44.7",
        "@types/node": "^20.10.0",
        "@types/nprogress": "^0.2.3",
        "@types/qs": "^6.9.10",
        "@typescript-eslint/eslint-plugin": "^6.12.0",
        "@typescript-eslint/parser": "^6.12.0",
        "@vitejs/plugin-vue": "^4.5.0",
        "eslint": "^8.54.0",
        "eslint-config-airbnb-base": "^15.0.0",
        "eslint-config-prettier": "^9.0.0",
        "eslint-import-resolver-alias": "^1.1.2",
        "eslint-plugin-import": "^2.29.0",
        "eslint-plugin-prettier": "^5.0.1",
        "eslint-plugin-vue": "^9.18.1",
        "husky": "^8.0.3",
        "lint-staged": "^15.1.0",
        "postcss": "^8.4.31",
        "postcss-html": "^1.5.0",
        "prettier": "^3.1.0",
        "sass": "^1.69.5",
        "stylelint": "^15.11.0",
        "stylelint-config-recommended-vue": "^1.5.0",
        "stylelint-config-standard": "^34.0.0",
        "stylelint-config-standard-scss": "^11.1.0",
        "typescript": "^5.3.2",
        "unplugin-auto-import": "^0.17.1",
        "unplugin-vue-components": "^0.25.2",
        "vite": "^5.0.0",
        "vite-plugin-eslint": "^1.8.1",
        "vite-plugin-stylelint": "^5.2.1",
        "vue-tsc": "^1.8.22",
        "pinia-plugin-persistedstate": "^3.2.0",
         "unplugin-vue-setup-extend-plus": "^1.0.0"
      }
    }
    

目录结构

mood-blog-front
├─ .env
├─ .env.development
├─ .env.production
├─ .env.staging
├─ .eslintrc.cjs
├─ .eslintrcignore
├─ .husky
│  ├─ commit-msg
│  ├─ pre-commit
│  └─ _
│     ├─ .gitignore
│     └─ husky.sh
├─ .prettierignore
├─ .prettierrc.cjs
├─ .stylelintcache
├─ .stylelintignore
├─ .stylelintrc.cjs
├─ auto-imports.d.ts
├─ commitlint.config.js
├─ components.d.ts
├─ index.html
├─ package.json
├─ pnpm-lock.yaml
├─ public
│  └─ vite.svg
├─ README.md
├─ src
│  ├─ api
│  │  └─ rest.ts
│  ├─ App.vue
│  ├─ assets
│  │  ├─ styles
│  │  │  ├─ base.scss
│  │  │  ├─ bem.scss
│  │  │  └─ index.scss
│  │  └─ vue.svg
│  ├─ components
│  │  └─ Layout
│  │     ├─ Foot
│  │     │  └─ index.vue
│  │     ├─ Head
│  │     │  └─ index.vue
│  │     ├─ index.vue
│  │     ├─ Main
│  │     │  └─ index.vue
│  │     └─ Sider
│  │        └─ index.vue
│  ├─ global
│  │  └─ index.ts
│  ├─ lang
│  │  ├─ en
│  │  │  └─ index.ts
│  │  ├─ index.ts
│  │  └─ zh
│  │     └─ index.ts
│  ├─ main.ts
│  ├─ plugins
│  │  └─ nprogress
│  │     └─ index.ts
│  ├─ router
│  │  ├─ dynamicRoutes.ts
│  │  ├─ index.ts
│  │  └─ promission.ts
│  ├─ store
│  │  ├─ mainStore.ts
│  │  └─ namespace.ts
│  ├─ types
│  │  ├─ Api
│  │  │  ├─ index.ts
│  │  │  ├─ rest.ts
│  │  │  └─ user.ts
│  │  └─ core
│  │     └─ index.ts
│  ├─ utils
│  │  ├─ dayjs.ts
│  │  ├─ request.ts
│  │  └─ types
│  ├─ views
│  │  └─ Home.vue
│  └─ vite-env.d.ts
├─ tsconfig.json
├─ tsconfig.node.json
└─ vite.config.ts

TypeScript

依赖安装

pnpm install typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-import-resolver-alias @types/eslint @types/node -D  

配置文件

// tsconfig.json

{
  "compilerOptions": {
    // 编译成es最新的版本代码
    "target": "ESNext",
    "useDefineForClassFields": true,
    "module": "ESNext",
    // 编译过程中需要引入的库文件的列表
    "lib": [
      "ESNext",
      "DOM",
      "DOM.Iterable"
    ],
    "skipLibCheck": true,
    /* Bundler mode */
    "moduleResolution": "Node",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    // "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve",
    /* Linting */
    "strict": true,
    "strictNullChecks": false,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "sourceMap": true,
    "esModuleInterop": true,
    "skipDefaultLibCheck": true,
    // 默认所有可见的"@type"包惠在编译过程中被包含进来
    "types": [
      "vite/client"
    ],
    // 解析非相对模块名的基准目录
    "baseUrl": ".",
    // 模块名到基于baseUrl的路径映射
    "paths": {
      "@/*": [
        "src/*"
      ],
      "*.ts": [
        "*"
      ]
    }
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "src/**/*.d.ts"
  ],
  "references": [
    {
      "path": "./tsconfig.node.json"
    }
  ]
}

ESlint

依赖安装

这里顺带将prettier的相关依赖也引入了

pnpm install eslint eslint-plugin-vue eslint-config-prettier prettier eslint-plugin-import eslint-plugin-prettier eslint-config-airbnb-base -D 

初始化

将该命令粘贴到package.json文件的scripts中,在终端使用npm run lint:create

ESlint配置好后在终端使用第二行命令进行语法检查,npm run lint

"lint:create": "eslint --init",
"lint": "eslint \"src/**/*.{js,vue,ts,jsx,tsx}\" --fix"

配置文件

.eslintrc.cjs
module.exports = {
    "env": {
        "browser": true,
        "es2021": true,
        "node": true,
        "vue/setup-compiler-macros": true,
    },
    "extends": [
        "plugin:vue/vue3-strongly-recommended",
        "airbnb-base",
        "prettier"
    ],
    // ESlint会对代码校验,parser的作用是将代码转换成ESTree(AST语法树)进行代码校验
    "parser": "vue-eslint-parser",
    "parserOptions": {
        // es版本号或年份
        "ecmaVersion": 13,
        "parser": "@typescript-eslint/parser",
        // 源码类型 默认是script, es模块使用module
        "sourceType": "module",
        // 额外的语言类型
        "ecmaFeatures": {
            "tsc": true,
            "jsx": true
        }
    },
    // 全局自定义的宏,这样在源文件中使用全局变量不会报错或警告
    "globals": {
        "defireProps": "readonly",
        "defineEmits": "readonly",
        "defineExpose": "readonly",
        "withDefaults": "readonly",
    },
    // 前缀eslint-plugin- 可以省略
    // vue官方提供了一个ESlint插件————eslint-plugin-vue,它提供了parser和rules。
    // parse:vue-eslint-parser放在上面的parsers里,rules放在extends字段里,选择合适的规则
    "plugins": [
        "vue",
        "@typescript-eslint"
    ],
    "settings": {
        // 项目内别名
        "import/resolver": {
            "alias": {
                map: [
                    ["@", "./src"]
                ]
            }
        },
        // 允许的拓展名
        "import/extensions": [".js", ".jsx", ".ts", ".tsx", ".mjs"]
    },
    // 自定义规则, 覆盖上面extends继承的第三方库的规则,根据组内成员灵活定义
    "rules": {
        "import/no-extraneous-dependencies": 0,
        "no-param-reassign": 0,
        "vue/multi-word-component-names": 0,
        "vue/attribute-hyphenation": 0,
        "vue/v-on-event-hyphenation": 0,
        'no-console': process.env.NODE_ENV === 'production' ? 2 : 0,
        'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
        'vue/no-v-for-template-key': 'off', // vue3  v-for 中template 可以设置key
        '@typescript-eslint/no-explicit-any': 'off', // 表示禁用此规则,允许使用 any 类型
        '@typescript-eslint/no-var-requires': 'off', // 禁止使用 require() 导入。off 表示禁用此规则,允许使用 require()。
        "eqeqeq": ['error', 'always'], // 要求使用恒等(===)而不是等于(==)进行比较,否则报错。
        'vue/no-multiple-template-root': 'off', // vue3 模板可以有多个根结点
        'vue/custom-event-name-casing': 'off', // 自定义 Vue.js 事件名称的大小写规则。off 表示禁用此规则。
        'no-use-before-define': 'error', // 禁止在定义之前使用变量。error 表示将此视为错误
        'guard-for-in': 'error', // 要求在 for-in 循环中使用 hasOwnProperty 方法进行条件过滤,否则报错。
        'consistent-this': ['error', '_this', 'that', 'self'], // 要求在代码中使用指定的别名代替 this(_this、that、self),否则报错。
    }
}
.eslintrcignore
*.sh
node_modules
*.nd
*.woff
*.ttf
.vscode
.idea
dist
/pub1ic
/docs
.husky
/bin
.es7intrc.js
prettier.config.js
/src/mock/*

# Logs
lags
*.log
npm-debug.1og*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
.DS_Store
dist-ssr
*.local

/cypress/videos/
/cypress/screenshots/

# Editor directories and files
.vscode
!.vscode/extendsions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

components.d.ts

Prettier

将这行命令粘贴到package.json文件的scripts中,终端运行npm run format,进行代码格式的校验。

 "format": "prettier --config .prettierrc.cjs \"src/**/*.{vue,js,ts,jsx,tsx}\" --write"

配置文件

.prettierrc.cjs
module.exports = {
    // 超过最大值换行
    "printWidth": 120,
    // 缩进字节数
    "tabWidth": 2,
    // 缩进不使用tab,使用空格
    "useTabs": false,
    // 句尾添加分号
    "semi": false,
    // 使用单引号代替双引号
    "singleQuote": true,
    // 默认值。因为使用了一些折行敏感型的渲染器(如GitHub comment)而按照markdown文本样式进行折行
    "proseWrap": "preserve",
    // (x) => {} 箭头函数参数只有一个时是否要有小括号。avoid:省略括号
    "arrowParens": "always",
    // 在对象,数组括号与文字之间加空格 "{ foo: bar }"
    "bracketSpacing": true,
    // 不格式化vue文件,vue文件的格式化单独设置
    // "disableLanguages": ["vue"],
    // 结尾是 \n \r \n\r auto
    "endOfLine": "auto",
    // 不让prettier使用eslint的代码格式进行校验
    // "eslintIntegration": false,
    "htmlWhitespaceSensitivity": "ignore",
    // 不使用prettier格式化的文件填写在项目的.prettierignore文件中
    // "ignorePath": ".prettierignore",
    // 在jsx中把'>' 是否单独放一行
    // "jsxBracketSameLine": false,
    // 在jsx中使用单引号代替双引号
    "jsxSingleQuote": false,
    // 格式化的解析器,默认是babylon
    // "parser": "babylon",
    // Require a 'prettierconfig' to format prettier
    // "requireConfig": false,
    //不让prettier使用stylelint的代码格式进行校验
    // "stylelintIntegration": false,
    // 在对象或数组最后一个元素后面是否加逗号(在ES5中加尾逗号)
    "trailingComma": "es5",
    // 不让prettier使用tslint的代码格式进行校验
    // "tslintIntegration": false,
    // 每个文件格式化的范围是文件的全部内容
    "rangeStart": 0,
    "rangeEnd": Infinity,
    // 不需要自动在文件开头插入@prettier
    "insertPragma": false,
    // 使用默认的这行标准
    "proseWrap": "always",
    // 对象的key仅在必要时使用引号
    "quoteProps": "as-needed"
}
.prettierignore
/dist/*
.local
.output.js
/node_modules/**
src/.DS_Store

**/*.svg
**/*.sh

/public/*
components.d.ts

Husky、Lint-staged

依赖安装

pnpm install husky lint-staged -D

相关配置

  1. 添加命令到package.jsonscripts中,npm run prepare安装husky。

    "prepare":"husky install"
    
  2. 添加lint-stagedpackage.json文件中。

    "lint-staged": {
        "*.{js,jsx,vue,ts,tsx}": [
         "npm run lint",
         "npm run format"
       ]
     },
    
  3. 添加git hooks的pre-commit,在终端执行以下命令。此步骤完成后,再commit时,会先执行lintformat,代码的语法和格式校验,

npx husky add .husky/pre-commit "npx lint-staged"

Commitlint

commitlint用于规范代码提交

依赖安装
 pnpm i @commitlint/config-conventional @commitlint/cli -D
添加到husky
npx husky add .husky/commit-msg "npx --no -- commitlint --edit ${1}"
配置文件

这里使用的es module, 所以导出使用的是export default, 如果用的command module,使用module.exports

// commitlint.config.js

// more:https://github.com/angular/angular/blob/main/CONTRIBUTING.md
export default {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [
      2,
      'always',
      [
        'build', // 编译相关的修改,如发布版本,对项目构建或依赖的改动
        'ci', // 对CI 配置文件和脚本的更改
        'chore', // 构建过程或辅助工具的变动,比如增加依赖库等
        'update', // 更新功能
        'docs', // 文档变动 documentation
        'feat', // 新增功能 feature
        'fix', // 修复bug
        'perf', // 性能优化  performance
        'refactor', // 重构
        'revert', // 撤回commit,回滚上一个版本
        'style', // 格式(不影响代码运行的变动)
        'test', // 测试(单元/集成测试)
      ],
    ],
    'type-case': [0],
    'type-empty': [0],
    'scope-empty': [0],
    'scope-case': [0],
    'subject-full-stop': [0, 'never'],
    'subject-case': [0, 'never'],
    'header-max-length': [0, 'always', 100],
  },
}
测试

可以尝试在commit时不使用规范的提交消息,看是否报错。如果不想按照以下规范提交,可以使用git commit -m "your commit message" --no-verify

git add .

git commit -m "chore: init"

Stylelint

依赖安装

vite-plugin-stylelint是一个插件,需要在vite.config.ts文件中的plugins中使用

pnpm i postcss-html stylelint-config-standard-scss stylelint-config-recommended-vue vite-plugin-stylelint postcss -D

添加命令

使用npm run lint:css,或尝试commit提交代码,看是否会在提交之前进行样式文件的语法检查。

"lint:css": "stylelint **/*.{vue,css,sass,scss} --fix"
"lint-staged": {
    "*.{js,jsx,vue,ts,tsx}": [
      "npm run lint",
      "npm run format"
    ],
    
    // 新增
    "*.{vue,sass,scss,css}": [
      "npm run lint:css"
    ]
  },

配置文件

我这里使用的是scss的语法检查,可自行集成pnpm install sass -D

.stylelintrc.cjs
module.exports = {
    extends: [
        "stylelint-config-standard-scss",
        "stylelint-config-recommended-vue/scss"
    ]
}
.stylelintignore
/dist/*
.local
.output.js
/node_modules/**

/public/*

测试

  1. 新建分支
    git branch release/v1.0.0
    
  2. 切换分支
    git checkout release/v1.0.0
    
  3. 编写代码后,提交分支上的代码
    git add .
    git commit -m "chore: XXXXX"
    
  4. 切回主分支
    git checkout <主分支名称>
    
  5. 合并分支
    git merge release/v1.0.0
    
  6. 提交代码
    git commit -m "chore: XXXXX"
    
  7. 添加遥控仓库,推送代码
    git remote add <名称> <仓库地址>
    git push -u <名称> <主分支名称>
    
  8. 发布版本,打上标签
    npm run release
    git push --follow-tags <名称> <主分支名称>
    
    // npm publish 发布到npm
    
;