vite + vue3 + ts 搭建一套自己的后台管理系统 (1)

4,969 阅读6分钟

前言

因为之前文章写的比较匆忙,也没有什么经验,写的比较粗糙,有不少细节遗漏了,如果是对项目不熟悉的小伙伴,可能有的地方会看的云里雾里。目前把每个专栏里都更新了一篇文章,也终于抽出时间来把之前遗漏的地方做一下补充。

技术选型

公司用的技术是 vue2 要做新项目,react 与 vue3 二选一,之前的一个项目也用过 react 不过是用 class 那种方式。算是比较早一点了。最后选择了 vue3,如果有时间可以用 react Hooks方式重构一下。于是就选了 vue3 + ts,脚手架的话选用 vite

工欲善其事必先利其器

使用 vite 搭建项目时 node 版本不能太低,我的 node 版本为 14.18.2 。如果你的电脑中有老项目,不能随意升级 node 版本可以使用 nvm 来进行 node 版本管理,我们来简单看下nvm 的用法

nvm 是什么

nvm 全英文也叫 node.js version management,是一个nodejs的版本管理工具。nvm 和n 都是 node.js 版本管理工具,为了解决 node.js 各种版本存在不兼容现象可以通过它可以安装和切换不同版本的 node.js。

nvm 下载与安装

官网地址 nvm.uihtm.com

image.png

下载完成以后直接下一步到最后就可以(注意不要使用中文的安装目录,软件的安装都不建议)

使用

安装完成以后 cmd 进入控制台 nvm-v 查看是否安装成功

image.png 查看目前的已经安装的版本 nvm list

image.png 查看可以安装的版本 nvm list available

image.png 安装自己想要的版本 nvm install 18.6.0 (上面版本自己随意选择)

image.png 查看已经安装好的全部版本

image.png 切换版本 nvm use 18.6.0

image.png

1 初始化项目

当时用的 vite3 现在已经到 vite4 了,应该差别不大,具体不同跟着api来就行。下面是我的项目配置选项 npm create vite@latest

image.png

image.png

  1. 根据提示 npm install npm run dev 运行项目(这个是vite4,为了截图演示,和vite3差别不大)

image.png

2 代码格式化

采用 eslint + prettier 安装 eslint-config-prettiereslint-plugin-prettier 进行代码格式化 .eslintrc.cjs 如下

  yarn add  eslint-plugin-prettier  eslint-config-prettier --dev

对比源文件修改内容为,extends , parserOptions , 以及添加的 rules 规则 ( vue-global-api 可暂时不加,这个是全局引用的配置)

image.png

/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')

module.exports = {
  root: true,
  extends: ['plugin:vue/vue3-essential', 'eslint:recommended', '@vue/eslint-config-typescript', '@vue/eslint-config-prettier', 'vue-global-api'],
  parserOptions: { parser: '@typescript-eslint/parser', ecmaVersion: 'latest', sourceType: 'module' },
  rules: {
    'no-inferrable-types': 'off', // **此处为修改*
    'vue/multi-word-component-names': ['error', { ignores: ['index'] }],
    // --以下是Possible Errors JS代码中的逻辑错误相关
    'no-extra-parens': 'error', // 禁止不必要的括号
    // "no-console": "error" // 不允许打印console.log
    'no-template-curly-in-string': 'error', // 禁止在常规字符串中出现模板字符串语法${xxx}
    // --以下是Best Practices 最佳实践
    'default-case': 'error', // 强制switch要有default分支
    'dot-location': ['error', 'property'], // 要求对象的点要跟属性同一行
    eqeqeq: 'error', // 要求使用 === 和 !==
    'no-else-return': 'error', // 禁止在else前有return,return和else不能同时存在
    'no-empty-function': 'error', // 禁止出现空函数,有意而为之的可以在函数内部加条注释
    'no-multi-spaces': 'error', // 禁止出现多个空格,如===前后可以有一个空格,但是不能有多个空格
    'no-multi-str': 'error', // 禁止出现多行字符串,可以使用模板字符串换行
    'no-self-compare': 'error', // 禁止自身比较
    'no-unmodified-loop-condition': 'error', // 禁止一成不变的循环条件,如while条件,防止死循环
    'no-useless-concat': 'error', // 禁止没有必要的字符串拼接,如'a'+'b'应该写成'ab'
    'require-await': 'error', // 禁止使用不带await的async表达式
    // --以下是Stylistic Issues 主观的代码风格
    'array-element-newline': ['error', 'consistent'], // 数组元素要一致的换行或者不换行
    'block-spacing': 'error', // 强制函数/循环等块级作用域中的花括号内前后有一个空格(对象除外)
    'brace-style': ['error', '1tbs', { allowSingleLine: true }], // if/elseif/else左花括号要跟if..同行,右花括号要换行;或者全部同一行
    'comma-dangle': ['error', 'only-multiline'], // 允许在对象或数组的最后一项(不与结束括号同行)加个逗号
    'comma-spacing': 'error', // 要求在逗号后面加个空格,禁止在逗号前面加一个空格
    'comma-style': 'error', // 要求逗号放在数组元素、对象属性或变量声明之后,且在同一行
    'computed-property-spacing': 'error', // 禁止在计算属性中出现空格,如obj[ 'a' ]是错的,obj['a']是对的
    'eol-last': 'error', // 强制文件的末尾有一个空行
    'func-call-spacing': 'error', // 禁止函数名和括号之间有个空格
    'function-paren-newline': 'error', // 强制函数括号内的参数一致换行或一致不换行
    // 'implicit-arrow-linebreak': 'error', // 禁止箭头函数的隐式返回 在箭头函数体之前出现换行
    // indent: ['error', 2], // 使用一致的缩进,2个空格
    'key-spacing': 'error', // 强制对象键值冒号后面有一个空格
    'lines-around-comment': 'error', // 要求在块级注释/**/之前有一个空行

    'newline-per-chained-call': ['error', { ignoreChainWithDepth: 2 }], // 链式调用长度超过2时,强制要求换行
    'no-lonely-if': 'error', // 禁止else中出现单独的if
    'no-multiple-empty-lines': 'error', // 限制最多出现两个空行
    'no-trailing-spaces': 'error', // 禁止在空行使用空白字符
    'no-unneeded-ternary': 'error', // 禁止多余的三元表达式,如a === 1 ? true : false应缩写为a === 1
    'no-whitespace-before-property': 'error', // 禁止属性前有空白,如console. log(obj['a']),log前面的空白有问题
    'nonblock-statement-body-position': 'error', // 强制单行语句不换行
    'one-var-declaration-per-line': 'error', // 强制变量初始化语句换行
    'operator-assignment': 'error', // 尽可能的简化赋值操作,如x=x+1 应简化为x+=1
    'semi-spacing': 'error', // 强制分号后面有空格,如for (let i=0; i<20; i++)
    'semi-style': 'error', // 强制分号出现在句末
    'space-before-blocks': 'error', // 强制块(for循环/if/函数等)前面有一个空格,如for(...){}是错的,花括号前面要空格:for(...) {}
    'space-infix-ops': 'error', // 强制操作符(+-/*)前后有一个空格
    'spaced-comment': 'error', // 强制注释(//或/*)后面要有一个空格
    // // --以下是ECMAScript 6 ES6相关的
    'arrow-body-style': 'error', // 当前头函数体的花括号可以省略时,不允许出现花括号
    // 'arrow-parens': ['error', 'as-needed'], // 箭头函数参数只有一个时,不允许写圆括号
    'arrow-spacing': 'error', // 要求箭头函数的=>前后有空格
    'no-confusing-arrow': 'error', // 禁止在可能与比较操作符混淆的地方使用箭头函数
    'no-duplicate-imports': 0, // 禁止重复导入
    'no-useless-computed-key': 'error', // 禁止不必要的计算属性,如obj3={['a']: 1},其中['a']是不必要的,直接写'a'
    'no-var': 'error', // 要求使用let或const,而不是var
    'object-shorthand': 'error', // 要求对象字面量使用简写
    'prefer-const': 'error', // 要求使用const声明不会被修改的变量
    'prefer-template': 'error', // 使用模板字符串,而不是字符串拼接
    'rest-spread-spacing': 'error', // 扩展运算符...和表达式之间不允许有空格,如... re1错误,应该是...re1
    'template-curly-spacing': 'error', // 禁止模板字符串${}内前后有空格
    'vue/comment-directive': 'off'
  }
}

.prettierrc

{
  "semi": false,
  "singleQuote": true,
  "useTabs": false,
  "tabWidth": 2,
  "printWidth": 200,
  "trailingComma": "none",
  "endOfLine": "auto"
}

在 vscode中安装 eslint 和 prettier 插件 下面是 vscode 中的 .setting.json 文件

image.png image.png

{
  // 选择vue文件的格式化工具
  "[vue]": {
    // 1.使用prettier,无法配置函数名后的空格
    // "editor.defaultFormatter": "esbenp.prettier-vscode"
    // 2.使用prettier-eslint
    "editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
  },
  // #每次保存的时候自动格式化
  "editor.formatOnSave": true,
  // 自动修复
  "editor.codeActionsOnSave": {

    "source.fixAll.eslint": true
  },
  // "eslint.enable": true, //是否开启vscode的eslint
  // 配置 ESLint 检查的文件类型
  "eslint.validate": ["javascript", "vue", "html"],
  "eslint.options": {
    //指定vscode的eslint所处理的文件的后缀
    "extensions": [".js", ".vue", ".ts", ".tsx"]
  },
  //  #使用单引号替代双引号
  "prettier.singleQuote": true,
  "prettier.trailingComma": "none",
  "prettier.bracketSpacing": true,
  //  #让函数(名)和后面的括号之间加个空格
  "javascript.format.insertSpaceBeforeFunctionParenthesis": true,
  "files.insertFinalNewline": true,
  // #让vue中的js按编辑器自带的ts格式进行格式化
  "vetur.format.defaultFormatter.js": "prettier-eslint",
  "git.enableSmartCommit": true,
  "editor.quickSuggestions": {
    "strings": true
  },
  //一定要在vutur.defaultFormatterOptions参数中设置,单独修改prettier扩展的设置是无法解决这个问题的,因为perttier默认忽略了vue文件(事实上从忽略列表移除vue也不能解决这个问题)
  "vetur.format.defaultFormatterOptions": {
    "prettier": {
      "semi": false, // 格式化不加分号
      "singleQuote": true // 格式化以单引号为主
    },
    "js-beautify-html": {
      // force-aligned | force-expand-multiline
      "wrap_attributes": "force-aligned"
    },
    "prettyhtml": {
      "printWidth": 100,
      "singleQuote": false,
      "wrapAttributes": false,
      "sortAttributes": true
    }
  },
  // 关于@src目录路径提示的配置
  // 安装vscode插件 `Path Intellisense`
  "path-intellisense.mappings": {
    "@": "${workspaceRoot}/src"
  },
  "prettier.bracketSameLine": true,
  "prettier.printWidth": 200,
  "prettier.requireConfig": true,
  "eslint.codeActionsOnSave.rules": null,
  "explorer.confirmDelete": false,
  "prettier.arrowParens": "avoid",
  "prettier.semi": false,
  "editor.minimap.enabled": false,
  "breadcrumbs.enabled": false,
  "backgroundCover.imagePath": "c:\\Users\\Administrator\\Desktop\\images\\vscode-bg.jpg",
  "tabnine.experimentalAutoImports": true,
  "prettier.vueIndentScriptAndStyle": true,
  "workbench.colorTheme": "Default Dark+",
  "debug.javascript.debugByLinkOptions": "on",
  "backgroundCover.opacity": 0.2
}

我们来看下配置是否好用,保存前保存后

image.png

image.png

3 配置 scss 与全局 css 变量

   npm install sass  sass-loader --save-dev
   
   css: {
    preprocessorOptions: {
      scss: { additionalData: '@import "@/assets/style/base.scss";' }
    }
  }

在vite.config.ts 添加配置

image.png 在 vue 文件中使用

image.png

4 引入 ui 框架 Ant Design 配置按需引入。vue 自动引入

1. ui框架与全局组件

 npm install ant-design-vue --save
 npm i unplugin-vue-components -D

vite.config.ts

 plugins: [
    vue(),
    Components({
      resolvers: [AntDesignVueResolver()], // antd按需引入
      dirs: ['src/components'] // 自定义全局组件按需引入
    })
  ],

此时我们的根目录会新增一个 components.d.ts 我们在代码中测试一下。同时我们也可以设置全局组件自动引入,在 Components 里面配置 dirs 指向我们的全局组件目录。我们定义全局组件,如果有使用的话在 components.d.ts就会自动更新配置 image.png image.png

2 vue3 中 Composition API 自动引入

npm i -D unplugin-auto-import

配置完成以后会新增一个 auto-imports.d.ts 文件 image.png 我们在代码中测试一下,会发现有 eslint 报错

image.png 我们在 eslint.cjs 中添加一个 vue 配置即可解决 安装 vue-global-api

 npm install -D vue-global-api
extends: [
    'plugin:vue/vue3-essential', 
    'eslint:recommended', 
    '@vue/eslint-config-typescript', 
    '@vue/eslint-config-prettier', 
    'vue-global-api'  //添加这个配置
],

5 项目打包配置

1 npm run build 打包报错

image.png 解决方法:tsconfig.json 中添加生成的 auto-imports.d.tscomponents.d.ts 配置即可

"include": ["env.d.ts", "src/**/*", "src/**/*.vue","./auto-imports.d.ts","./components.d.ts"],

2 添加 gzip 压缩

npm install -D vite-plugin-compression

vite.config.ts 文件添加配置

import AutoImport from 'unplugin-auto-import/vite'

plugins: [
     ...
    // 压缩配置
    viteCompression({
      verbose: true, // 默认即可
      disable: false, // 开启压缩(不禁用),默认即可
      deleteOriginFile: false, // 删除源文件
      threshold: 10240, // 压缩前最小文件大小
      algorithm: 'gzip', // 压缩算法
      ext: '.gz' // 文件类型
    })
  ],

nginx 添加配置

gzip  on;
gzip_disable ¡°MSIE [1-6].(?!.*SV1)¡±;
gzip_http_version 1.1;
gzip_vary on;
gzip_proxied any;
gzip_min_length 5000;
gzip_buffers 16 8k;
gzip_comp_level 6;
gzip_types text/css text/xml text/plain text/javascript application/javascript application/json application/xml application/rss+xml application/xhtml+xml;

3 打包文件配置

npm install -D terser

plugins 同层级添加 build 属性配置

 build: {
    minify: 'terser',
    terserOptions: {
      compress: {
        keep_infinity: true, // 防止 Infinity 被压缩成 1/0,这可能会导致 Chrome 上的性能问题
        drop_console: true, // 生产环境去除 console
        drop_debugger: true // 生产环境去除 debugger
      }
    },
     rollupOptions: {
     //打包文件目录整理
      output: {
        chunkFileNames: 'static/js/[name]-[hash].js',
        entryFileNames: 'static/js/[name]-[hash].js',
        // assetFileNames: 'static/[ext]/[name]-[hash].[ext]' 开启会出现异常bug
        manualChunks(id) {
          if (id.includes('node_modules')) {
            // 超大静态资源拆分
            return id.toString().split('node_modules/')[1].split('/')[0].toString()
          }
        }
      }
    },
    chunkSizeWarningLimit: 1500 // chunk 大小警告的限制(以 kbs 为单位)
  },

4 多环境配置

一般我们的项目分为开发环境,测试环境,与生产环境,我们配置不同的命令打包不同的版本,这样就不用来回修改接口。我们来看下实现。
在根目录创建文件夹 env 然后在该文件夹下创建 .env, .env.uat ,.env.prod

image.png

vite.config.tsplugins 同层级添加配置

envDir: path.resolve(__dirname, './env'),

package.json 中添加配置

  "scripts": {
    "dev": "vite --port 8888 --open",
    "dev:uat": "vite --mode uat",
    "dev:prod": "vite --mode prod",
    "build": "run-p type-check build-only",
    "build:uat": "run-p type-check && vite build --mode uat",
    "build:prod": "run-p type-check && vite build --mode prod",
    "preview": "vite preview --open",
    "build-only": "vite build",
    "type-check": "vue-tsc --noEmit",
    "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path.gitignore"
  },

最后

差不多项目的基本配置已经完成了,如果有遗漏的地方会及时更新。下篇文章进行项目的实现,动态路由权限,开发规范,一些常用组件封装,axios 接口封装等!