【vue】vue3+ts+vite搭建

362 阅读13分钟

(一)环境准备

  • node:16.12.1(node版本需14.0.0以上)
  • 项目搭建
    • 创建⼀个Vite的初始化项⽬:npm init vite
    • 选择模板
      image.png

(二)项目配置文件修改

1. Vite 配置文件

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@': resolve('./src')
    }
  },
  base: './', // 打包路径
  server: {
    port: 8888, // 服务端口号
    open: true, // 服务启动时是否自动打开浏览器
    cors: true // 允许跨域
  }
})

image.png

2. 配置 tsconfig.json文件

{
  "compilerOptions": {
    "target": "ESNext",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "moduleResolution": "Node",
    "strict": true,
    "jsx": "preserve",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "lib": ["ESNext", "DOM"],
    "skipLibCheck": true,
    "noEmit": true,
    // 👆以上是初始化默认配置
    "baseUrl": "./",
    // "paths"是相对于"baseUrl"进行解析
    // 在vite.config里配置了路径别名resolve.alias,为了让编译 ts 时也能够解析对应的路径,我们还需要配置 paths 选项
    "paths": {
      "@/*": ["src/*"]
    }
    /*
      在ts中导入js模块会报错找不到类型声明
      1.解决方法一:
        仅设置 "allowJs": true 即可
        注:allowJs设置true时,下方include不可以加入'src/**\/*.js',否则报错'无法写入文件xx因为它会覆盖输入文件'
      2.解决方法二:
        仅在 env.d.ts 中加入 declare module '*.js'; 模块定义即可
      3.总结:和 "include": ["src/**\/*.js"] 没有任何关系
    */
    // "allowJs": true, // 允许编译器编译JS,JSX文件
    // "typeRoots": [
    //   "node_modules/@types" // 默认会从'node_modules/@types'路径去引入声明文件
    // ],
    // "types": ["node"] // 仅引入'node'模块
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

(三)代码规范配置

1. EditorConfig 配置

(1)作用: 统一不同 IDE 编辑器的代码风格。

(2)配置

  • 在项目的根目录下创建 .editorconfig 文件:
# Editor configuration, see http://editorconfig.org

# 表示是最顶层的 EditorConfig 配置文件
root = true

[*] # 表示所有文件适用
charset = utf-8 # 设置文件字符集为 utf-8
indent_style = space # 缩进风格(tab | space)
indent_size = 2 # 缩进大小
end_of_line = lf # 控制换行类型(lf | cr | crlf)
trim_trailing_whitespace = true # 去除行首的任意空白字符
insert_final_newline = true # 始终在文件末尾插入一个新行

[*.md] # 表示仅 md 文件适用以下规则
max_line_length = off
trim_trailing_whitespace = false
  • VSCode 使用 EditorConfig 需要去插件市场下载插件 EditorConfig VS Code

2. Prettier 配置

(1)作用:当下最流行的代码格式化工具

(2)配置

  • 安装Prettier:npm i prettier -D
  • 在根目录下创建 .prettierrc 文件
  • 配置 .prettierrc 关于更多的配置项信息查阅官网
     {
       "useTabs": false,
       "tabWidth": 2,
       "printWidth": 100,
       "singleQuote": true,
       "trailingComma": "none",
       "bracketSpacing": true,
       "semi": false
     }
    
  • 使用:Prettier安装配置好之后,就能使用命令来格式化代码
    # 格式化所有文件 (. 表示所有文件)
    npx prettier --write .
    
  • VSCode 编辑器使用 Prettier 配置需要下载插件Prettier-Code formatter

3. ESlint 配置

(1)作用:查找并报告代码中问题的工具,并且支持部分问题自动修复

(2)配置

  • 安装 ESLint:npm i eslint -D(本地安装)
  • 配置ESLint
    • 执行 npx eslint --init
    • 选择配置 image.png
      • 如果自动安装依赖失败,则需要手动安装
        npm i @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-config-airbnb-base eslint-plugin-import eslint-plugin-vue -D
        
    • 操作完成后,会在项目根目录下自动生成 .eslintrc.js 配置文件(根据项目实际情况追加ESLint 规则。)
    module.exports = {
      env: {
        browser: true,
        es2021: true,
        node: true
      },
      extends: [
        'plugin:vue/essential',
        // 'eslint:recommended',
        // "airbnb-base"
        'plugin:vue/vue3-essential',
        // 添加 prettier 插件,这样,我们在执行 eslint --fix 命令时,
        // ESLint 就会按照 Prettier 的配置规则来格式化代码,解决prettier/ESLint二者冲突问题。
        'plugin:prettier/recommended'
        // "plugin:@typescript-eslint/recommended"
      ],
      overrides: [],
      // "parser": "@typescript-eslint/parser",
      parserOptions: {
        ecmaVersion: 'latest',
        // 默认的eslint配置无法检测ts的语法,有些关键字会报错,解决interface关键字等识别报错的问题
        parser: '@typescript-eslint/parser',
        sourceType: 'module'
      },
      plugins: ['vue', '@typescript-eslint'],
      rules: {
        // 我们主要使用以下规则配置
        // 错误急别分为三类
        // 1、off 或 0 表示关闭验证规则
        // 2、warn 或 1 表示开启警告验证规则
        // 3、error 或 2 表示开启错误验证规则,程序会报错退出
        semi: [2, 'never'], // 禁止尾部使用分号“ ; ” // "semi": ["warn", "never"],
        'no-var': 'error', // 禁止使用 var
        indent: ['error', 2], // 缩进2格
        'no-mixed-spaces-and-tabs': 'error', // 不能空格与tab混用
        quotes: [2, 'single'], // 使用单引号
        'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
        'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
        // 其它的规则可以去eslint查看,根据自己需要进行添加
        // vue template模板元素第一行最多10个属性
        'vue/max-attributes-per-line': [
          2,
          {
            singleline: 10, //一行最多可以放下10个属性
            multiline: {
              max: 1,
              allowFirstLine: false
            }
          }
        ],
        // 关闭名称校验(使用大驼峰命名方式或者用“-”连接单词)
        'vue/multi-word-component-names': 'off'
        // "vue/singleline-html-element-content-newline": "off",
        // "vue/multiline-html-element-content-newline": "off",
        // "vue/name-property-casing": ["error", "PascalCase"],
        // "vue/no-v-html": "off",
        // 'vue/html-closing-bracket-newline': 'off',
        // 'vue/singleline-html-element-content-newline': 'off',
      }
    }
    
    
  • VSCode 使用 ESLint 配置文件需要去插件市场下载插件 ESLint
    • 如果配置完Eslint提示不生效(可能版本不匹配),就尝试关掉编辑器后重开,或者卸载VSCode的ESLint插件然后重新安装,
    • 设置编辑器保存文件时自动执行 eslint --fix 命令进行代码风格修复,VSCode 在 settings.json 设置文件中,增加以下代码:
      "editor.codeActionsOnSave": {
          "source.fixAll.eslint": true
       }
      ``
      

(3)测试

main.ts 中写一段不符合eslint规则的代码 ,执行npx eslint src/main.ts检查是否报错提示,报错则配置成功

4. 解决 Prettier 和 ESLint 的冲突

(1)作用

ESLint 和 Prettier 配置规则可能会出现用 Prettier 格式化后的代码,ESLint 检测到格式有问题的,从而抛出错误提示的情况,解决两者冲突问题,需要用到 eslint-plugin-prettiereslint-config-prettier

  • eslint-plugin-prettier 将 Prettier 的规则设置到 ESLint 的规则中。
  • eslint-config-prettier 关闭 ESLint 中与 Prettier 中会发生冲突的规则。 最后形成优先级:Prettier 配置规则 > ESLint 配置规则。

(2)配置

  • 安装插件
npm i eslint-plugin-prettier eslint-config-prettier -D
  • 在 .eslintrc.js 添加 prettier 插件。
module.exports = {
  ...
  extends: [
    ...
    'plugin:prettier/recommended' // 添加 prettier 插件
  ],
  ...
}

这样,我们在执行 eslint --fix 命令时,ESLint 就会按照 Prettier 的配置规则来格式化代码,从而解决二者冲突问题。

5. 插件

(1)Volar

  • vue3项目就不要使用Vetur插件了,它不支持很多vue3特性,会有很多红线警告。
  • 请使用官方推荐插件Volar,现已更名为Vue Language Features,再搭配TypeScript Vue Plugin

(四)代码提交检验配置

  • Git Husky是一个基于Git的钩子管理工具,它允许开发者在代码提交或推送等Git操作前执行自定义的脚本
  • Husky可以帮助团队在代码提交前进行代码质量检查、测试运行、格式化等操作,以确保代码满足预定义的要求和规范。
  • 通过使用Git Husky,开发团队可以轻松地将代码质量检查和预定义的规范集成到Git工作流中。这有助于保持项目的一致性、团队协作和提高代码质量。
  • husky 包含很多 hook(钩子),常用有:pre-commitcommit-msgpre-push

1. husky配置:pre-commit

(1)作用:让没通过 ESLint 检测和修复的代码禁止提交

(2)配置

  • 安装:运行npx husky-initnpm install
    在项目初始化一个 husky 配置,这行命令做了四件事:
    • 安装 husky 到开发依赖
      image.png
    • 在项目根目录下创建 .husky 目录;
    • .husky 目录创建 pre-commit hook,并初始化 pre-commit 命令为 npm test
      image.png
    • 修改 package.json 的 scripts,增加 "prepare": "husky install"
      image.png
      到这里,husky 配置完毕,现在我们来使用它:

(3)使用

  • 在 package.json 文件的 scripts 中添加命令:
    "lint:fix": "eslint --fix --ext .vue,.js,.ts src"
    "lint:fix": "eslint --fix ./src --ext .vue,.js,.ts" image.png
    这句话的意思是:
    • 当我们执行 npm run lint:fix 时,
    • 会先对 src 目录下所有的 .vue、.js、.ts 文件执行 eslint --fix 命令,
    • warning等级的代码进行自动修复 error等级的代码是不能修复的,需要手动解决)
  • 修改.husky/pre-commit hook 文件的触发命令:npm run lint:fix
    • 可以先在终端单独运行命令npm run lint:fix看看,没问题再放到.husky/pre-commit文件中
    • 注意: #!/usr/bin/env sh 必须放到第一行,上边不能有其他语句 image.png
  • 上面这个 pre-commit hook 文件的作用是:
    • 当我们执行 git commit -m "xxx" 时,会执行npm run lint:fix命令
    • 然后对 src 目录下所有的 .vue、.js、.ts 文件执行 eslint --fix 命令,
    • 如果 ESLint 通过,成功 commit,否则终止 commit

(4)测试

  • 执行 git commit -m "xxx",看是否会触发husky - pre-commit hook,触发则配置成功
    image.png

(5)报错解决

image.png
解决办法:.pre-commit文件中的 #!/usr/bin/env sh放到第一行,上边其他信息全部删掉

2. husky + lint-staged 配置

(1)作用

  • lint-staged 这个工具一般结合 husky 来使用,它可以让 husky 的 hook 触发的命令只作用于 git add 那些文件(即 git 暂存区的文件),而不会影响到其他文件。
    • husky 配置完还会存在一个问题:有时候我们明明只改动了一两个文件,却要对所有的文件执行 eslint --fix
      假如这是一个历史项目,我们在中途配置了 ESLint 规则,那么在提交代码时,也会对其他未修改的“历史”文件都进行检查,可能会造成大量文件出现 ESLint 错误,显然不是我们想要的结果。
    • 通过lint-staged,我们可以做到只用 ESLint 修复此次写的代码,而不去影响其他的代码。

(2)配置

  • ① 安装 lint-staged:npm i lint-staged -D
  • ② 在 package.json里增加 lint-staged 配置项;
    这行命令表示:只对 git 暂存区的 .vue、.js、.ts 文件执行 eslint --fix
    "lint-staged": {
      "*.{vue,js,ts}": "eslint --fix"
    },
    
    image.png
  • ③ 修改 .husky/pre-commit hook 的触发命令为:npx lint-staged image.png
  • 至此,husky 和 lint-staged 组合配置完成。

(3)测试

image.png

3. husky配置:commit-msg

(1)作用:对commit的信息进行校验

(2)配置

image.png

方法一
  • 执行下面的命令
#!/usr/bin/env sh
# 对commit的文本信息进行校验
# 【方法一】
MSG=`awk '{printf("%s",$0)}' $1`
if [[ $MSG =~ ^(revert: )?(create|feat|fix|conflict|style|save|stash|delete|tool|docs|dx|refactor|revert|perf|test|workflow|build|ci|chore|types|hotfix|update|wip|release)(\(.+\))?(:|:).*$ ]]
then
    # echo -e "\033[32m Success: git commit 校验通过! \033[0m"
    echo -e ""
else
    echo -e "\033[31m Error: 请遵循  type(scope):message 的格式提交 \033[m"
    echo -e "\033[31m Error: type 必须为以下类型之一: [feat,fix,docs,style,delete,refactor,test,chore, ...] \033[m"
    echo -e "\033[31m 详见 .husky/verifyCommit.js文件 \033[m"
    echo -e "\033[31m 例如: feat(模块名称): 文字描述 \033[m"
    exit 1
fi
方法二(会报错,待解决)
  • 在 .husky文件下新建verifyCommit.ts
//verifyCommit.ts
const msg = require('fs').readFileSync('.git/COMMIT_EDITMSG', 'utf-8').trim()
const commitRE =
  /^(revert: )?(feat|fix|docs|dx|style|refactor|perf|test|workflow|build|ci|chore|types|wip|release)(\(.+\))?: .{1,50}/
const mergeRe = /^(Merge pull request|Merge branch)/
console.log('1.git commit开始校验')

if (!commitRE.test(msg)) {
  console.log('2.git commit校验中')

  if (!mergeRe.test(msg)) {
    console.log('3.git commit信息校验不通过')
    console.error(`git commit的信息格式不对, 需要使⽤ title(scope): desc的格式`)
    process.exit(1)
  }
} else {
  console.log('4.git commit信息校验通过')
}

image.png

  • 执行下面的命令
    npx husky add .husky/commit-msg "node ./verifyCommit.ts"
    
    image.png
  • 执行后.husky文件夹下会出现新的文件commit-msg image.png
    #!/usr/bin/env sh
    . "$(dirname -- "$0")/_/husky.sh"
    # 执行./verifyCommit.ts文件中的内容
    node .husky/verifyCommit.ts
    

(3)测试

  • 执行git commit -m "测试commit格式校验",校验不通过 image.png
  • 执行git commit -m "test:测试commit格式校验",校验通过:
    image.png

(五)工具库配置

1. 路由配置

(1)配置

  • 安装:安装支持vue3的路由:npm i vue-router@4
  • 创建: src/router/index.ts 文件
// src/router/index.ts

import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
export const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    name: 'app',
    meta: { title: 'app' },
    component: () => import('@/App.vue')
  },
  {
    path: '/home',
    name: 'Home',
    component: () => import(/* webpackChunkName: "Home" */ '@/views/home-page.vue')
  },
  {
    path: '/router',
    name: 'Router',
    component: () => import('@/views/router-page.vue')
  },
  // { path: '/:pathMatch(.*)*', redirect: '/' } // 替代vue2中的'*'通配符路径
  { path: '/', redirect: { name: 'Home' } }
]

const router = createRouter({
  history: createWebHashHistory(), // history 模式则使用 createWebHistory()
  routes
})
export default router
  • 挂载:main.ts 文件中挂载
import { createApp } from 'vue'
import App from '@/App.vue'
import router from '@/router/index'
createApp(App).use(router).mount('#app')

(2)测试

在App.vue 文件中测试

<router-link to="/home">路由跳转</router-link>
<router-view></router-view>

3. vuex 配置

(1)配置

  • 安装:支持Vue3的状态管理工具npm i vuex@next
  • 创建 src/store/index.ts 文件
import { createStore } from 'vuex'

const defaultState = {
  count: 0
}

// Create a new store instance.
export default createStore({
  state() {
    return defaultState
  },
  // mutations:同步修改数据, mutation内部的函数会把state作为参数,
  mutations: {
    add(state: typeof defaultState) {
      // 我们直接操作state.count就可以完成数据的修改。
      state.count += 1
    }
  },
  // actions:异步修改数据
  actions: {
    // increment(context) {
    //   context.commit('increment')
    // }
    // 这个配置中所有的函数,可以通过解构获得 commit函数。
    // 内部的异步任务完成后,就随时可以调⽤commit来执⾏mutations去更新数据。
    asyncAdd({ commit }) {
      setTimeout(() => {
        commit('add') //可以调⽤commit来执⾏mutations去更新数据。
      }, 1000)
    }
  },
  getters: {
    double(state: typeof defaultState) {
      return 2 * state.count
    }
  }
})
  • 挂载:main.ts 文件中挂载
...
import store from '@/store/index'
createApp(App).use(store).mount('#app')

(2)测试

// src/views/demo/store-demo.vue
<template>
  <div>
    <h2>计数器(store)</h2>
    <p @click="add">同步修改:{{ count }}</p>
    <p @click="asyncAdd">异步修改:{{ count }}</p>
    <p>计算属性getters:{{ double }}</p>
  </div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useStore } from 'vuex'

let store = useStore()
// 从计算属性中获取vuex
// 使用state获取vuex中的值
let count = computed(() => {
  return store.state.count
})
// 使用getters获取vuex中的值
let double = computed(() => {
  return store.getters.double
})
let color = ref('pink') //css中使用
// 同步
function add() {
  store.commit('add')
  color.value = Math.random() > 0.5 ? 'green' : 'pink'
}
// 异步
function asyncAdd() {
  store.dispatch('asyncAdd')
}
</script>
<style scoped>
p {
  color: v-bind(color);
}
</style>

3. axios 配置

(1)配置

  • 安装 Axios : (跟vue版本无关,安装最新即可):npm i axios
  • 配置 Axios : 根据常规规范,axios封装的方法放在 src/utils/http.ts
// src/utils/http.ts
import axios from 'axios'

// import { Message } from 'element-plus'
// 创建axios实例
// 创建请求时可以用的配置选项

const instance = axios.create({
  baseURL: '',
  withCredentials: true,
  timeout: 1000
})
// axios的全局配置
instance.defaults.headers.post = {
  'Content-Type': 'application/x-www-form-urlencoded'
}
instance.defaults.headers.common = {
  'Auth-Type': 'company-web',
  'X-Requested-With': 'XMLHttpRequest',
  token: 'sdfjlsdfjlsdjflsjflsfjlskd'
}

// 添加请求拦截器(post只能接受字符串类型数据)
// 对所有的http请求进⾏统⼀拦截,确保在请求发出之前,从本地存储中获取token,
instance.interceptors.request.use(
  (config) => {
    const token = '' //TODO,获取token,getToken()
    if (token && config.headers) {
      config.headers['X-Token'] = token
    }
    return config
  },
  (error) => {
    return Promise.reject(error)
  }
)

const errorHandle = (status: any, other: any) => {
  // switch (status) {
  //   case 400:
  //     // Message.error('信息校验失败')
  //     break
  //   case 401:
  //     Message.error('认证失败')
  //     break
  //   case 403:
  //     Message.error('token校验失败')
  //     break
  //   case 404:
  //     Message.error('请求的资源不存在')
  //     break
  //   default:
  //     Message.error(other)
  //     break
  // }
}

// 添加响应拦截器
// 后端数据如果出错的话,接⼝还要进⾏统⼀拦截,
// ⽐如接⼝返回的错误是登录状态过期,那么就需要提⽰⽤⼾跳转到登录⻚⾯重新登录。
instance.interceptors.response.use(
  // 响应包含以下信息data,status,statusText,headers,config
  (response) => {
    const res = response.data
    if (res.code !== 200) {
      console.log('接口信息报错', res.message)
      return Promise.reject(new Error(res.message || 'Error'))
    } else {
      return Promise.resolve(res)
    }
  },
  (error) => {
    // Message.error(err)
    // if (error) {
    // errorHandle(response.status, response.data)
    return Promise.reject(error)
    // }
    // Message.error('请求失败')
    // return true
  }
)

export default instance

(2)使用

import Http from '@/utils/http'
export default defineComponent({
  setup() {
    // const store = useStore()
    const getData = () => {
      Http.get('url').then((res: Object) => {
        console.log(res)
      })
    }
    return {
      store,
      getData
    }
  }
})

4. sass配置

(1)安装

安装:npm i sass -D
卸载:npm uninstall sass-loader

(2)使用

<style lang="scss"></style>

5. 组件库安装-element plus

(1)配置

  • 安装组件:npm install element-plus --save
  • 安装图标:npm install @element-plus/icons-vue
  • 挂载:main.ts 文件中挂载
// main.ts
...
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
// 如果您正在使用CDN引入,请删除下面一行。
import * as ElementPlusIconsVue from '@element-plus/icons-vue'

const app = createApp(App)
app.use(ElementPlus).mount('#app')
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
  app.component(key, component)
}

6. MOCKJS

(1)安装

npm i mockjs vite-plugin-mock -D

(2)配置

  • vite.config.ts配置
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
// mock
import { viteMockServe } from 'vite-plugin-mock'
// https://vitejs.dev/config/
export default defineConfig(({ command }) => {
  return {
    // 插件
    plugins: [
      vue(),
      // mock 数据的 dev环境
      viteMockServe({
        // supportTs: true, // 是否开启支持ts
        mockPath: 'mock',// 设置mockPath为根目录下的mock目录
        localEnabled: command === 'serve',// 设置是否监视mockPath对应的文件夹内文件中的更改
        logger: true //是否在控制台显示请求日志
      })
    ],
    resolve: {
      alias: {
        '@': resolve(__dirname, 'src')//resolve('./src')
      }
    },
    // 配置公共样式文件
    css: {
      preprocessorOptions: {
        scss: {
          additionalData: '@import "./src/styles/index.scss";'
        }
      }
    },
    base: './', // 打包路径
    server: {
      port: 8888, // 服务端口号
      open: true, // 服务启动时是否自动打开浏览器
      cors: true // 允许跨域
    }
  }
})

(3)使用

  • 根目录下创建 mock/ index.ts
export default [{
  url: '/mock/api/getAppInfo',
  method: 'get',
  response: () => {
    return {
      code: 0,
      title: 'mock请求测试'
    }
  }
}]
  • 使用 axios 请求mock数据
<template>
  <div />
</template>
<script setup>

import axios from 'axios'
axios.get('/mock/api/getAppInfo').then((res) => {
  console.log(res) // {code: 0, title: 'mock请求测试'}
})
</script>

(六)package.json文件

{
  "name": "vue3-cli",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc && vite build",
    "preview": "vite preview",
    "prepare": "husky install",
    "lint:fix": "eslint --fix ./src --ext .vue,.js,.ts"
  },
  "lint-staged": {
    "*.{vue,js,ts}": "eslint --fix"
  },
  "dependencies": {
    "@typescript-eslint/eslint-plugin": "^5.43.0",
    "@typescript-eslint/parser": "^5.43.0",
    "eslint-plugin-import": "^2.26.0",
    "eslint-plugin-vue": "^9.7.0",
    "vue": "^3.2.41"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^3.2.0",
    "eslint": "^8.27.0",
    "eslint-config-prettier": "^8.5.0",
    "eslint-plugin-prettier": "^4.2.1",
    "husky": "^8.0.0",
    "lint-staged": "^13.0.3",
    "prettier": "^2.7.1",
    "typescript": "^4.6.4",
    "vite": "^3.2.3",
    "vite-plugin-eslint": "^1.8.1",
    "vue-tsc": "^1.0.9"
  }
}