Vue3.x+Vite+Ts初始化项目

2,826 阅读7分钟

大家好,我是王大傻,自Vue3.0推出已经过了很长一段时间,现在都3.2版本了,那么相比于Vue2.x,在3.x版本中我们是如何书写Vue代码的呢?这次,大傻带着大家用Vite+Vue3.0+Ts去初始化一个Vue3.0的项目吧

相关知识点

  1. Vite
    1. Vite是什么
    2. 对比于WebPack的优缺点在哪
  2. Vue3.x
    1. 相比于Vue2.x 写法差异是什么
    2. 结合Ts又该如何去写
  3. Vite+Vue3.x+Ts初始化项目

image.png

Vite

Vite 是什么

Vite究竟是什么呢?它是一个新型的前端构建工具,那么既然是构建工具,那么他给我们带来的必定是提升工作效率, 它主要由两部分构成

  • 开发服务器,主要是为了使用ESModule并通过ESModule实现一些内建功能,如HMR
  • 一套构建指令,主要是通过打包来优化我们生产环境下的静态资源代码

对比于WebPack的优缺点在哪

在没有Vite以前,我们大多用的都是WebPack来构建打包我们的项目从而完成工程化的目的 想必于Webpack,Vite和它的区别是什么呢

名称打包原理优点缺点
webpack通过解析和处理各个模块的依赖关系 利用loader转换文件,再通过plugin注入钩子,打包合并模块,最终生成bundle文件,然后使用express开启本地服务器,浏览器请求的就是打包过后的bundle文件。可以识别多种模块化并通过配置合并输出为我们需要的模块学习成本大,一旦依赖过多处理不好,启动项目龟速
Vite使用koa开启本地服务器,没有webpack那样打包合并的过程,会通过_esmoudle去标记文件为ESModule模块,所以启动服务器很快,在Vue中@vue/compiler-sfc也会对模块进行编译 浏览器再请求编译好的模块。启动时间短,几乎是秒开项目的开发浏览器要支持esmodule,不能识别commonjs语法

了解了优缺点后我们再来看下Vue3.x的具体内容 image.png

Vue3.x

首先,为什么有了Vue3.x,它是为了解决什么问题吗 我个人的理解是:

  1. 首先是响应式原理这块,Vue2.x版本的Object.defineProperty无法对数据的新增删除操作进行一个完美的监听方案,因此在3.x版本使用了Proxy代理的方式来解决了这个问题,关于这个问题大家可以去我之前的juejin.cn/post/705116… 这篇文章来了解一下
  2. 业务模块混乱

image.png 观察这张图,左边是我们Vue2.x一个组件的内容,不同颜色就是我们处理不同业务时候所进行的声明以及操作,例如:

  • 当我们需要处理一个业务时候,需要先在data中进行数据的初始化声明,在template中对数据进行绑定,在生命周期中对这个数据进行赋值,在computed或者watch进行相应的计算监听,这样一套操作下来,我们的数据模块变得很不清晰,往往我们需要改动时候,需要改动的内容涉及到很多地方

右边则是我们Vue3.x中的做法

  • 在Vue3.x中我们需要的功能函数都可以通过按需引入的方式来加载,这样以来,我们可以通过定义不同的函数来完成不同业务的处理,使得我们的数据模块也可以单独书写,只需要在全局的setup函数中去执行即可

image.png

结合Ts我们如何书写

在Vue2.x中我们通过浏览官方文档可以知道,官方给我们提供了Vue-class-component使用类的方式书写也可以通过extend方式进行书写

  1. extend方式 要让 TypeScript 正确推断 Vue 组件选项中的类型,需要使用 Vue.component 或 Vue.extend 定义组件:
import Vue from 'vue' 
const Component = Vue.extend({ 
// 类型推断已启用
}) 
const Component = { 
// 这里不会有类型推断, // 因为 TypeScript 不能确认这是 Vue 组件的选项
}
  1. class方式
import Vue from 'vue'
import Component from 'vue-class-component'
// @Component 修饰符注明了此类为一个 Vue 组件
@Component({ 
// 所有的组件选项都可以放在这里 template: '<button @click="onClick">Click!</button>'
}) 
export default class MyComponent extends Vue {
// 初始数据可以直接声明为实例的 
    property message: string = 'Hello!' // 组件方法也可以直接声明为实例的方法
    onClick (): void { 
    window.alert(this.message)
    } 
}

通过类的方式我们还可以使用 Vue-Property-Decorator 这个库,他给我们提供了vue中其他函数的装饰器

import { Vue, Component, Watch } from 'vue-property-decorator'
 
@Component
export default class YourComponent extends Vue {
  @Prop()
  isShow :false
  @Watch('child')
  onChildChanged(val: string, oldVal: string) {}
 
  @Watch('person', { immediate: true, deep: true })
  onPersonChanged1(val: Person, oldVal: Person) {}
}

Vite+Vue3.x+Ts初始化项目

因为Vue3.x版本就是用Ts来重构了,所以对Ts的支持无疑是更加的友好,那么我们结合Vite来初始化一个项目吧

首先我们初始化Vite

npm init vite@latest

√ Project name: my-project
√ Select a framework: » vue
√ Select a variant: » vue-ts

Scaffolding project in 

Done. Now run:

  cd my-project
  npm install
  npm run dev

然后开启了我们的项目,接下来是ESlint的校验配置

npm install eslint --save-dev
npx eslint --init

? How would you like to use ESLint? ...
  To check syntax only
  To check syntax and find problems
> To check syntax, find problems, and enforce code style // 去检测代码格式找问题 并显示给我们

? What type of modules does your project use? ...
> JavaScript modules (import/export) // js模块
  CommonJS (require/exports)
  None of these
  
 ? Which framework does your project use? ...
  React
> Vue.js
  None of these
  
? Does your project use TypeScript? » No / Yes
  
? Where does your code run? ...  (Press <space> to select, <a> to toggle all, <i> to invert selection)
√ Browser// 运行在浏览器环境
√ Node

? How would you like to define a style for your project? ...
> Use a popular style guide// 使用一个流行的风格
  Answer questions about your style
  Inspect your JavaScript file(s)
  
? Which style guide do you want to follow? ...
  Airbnb: https://github.com/airbnb/javascript
> Standard: https://github.com/standard/standard // 这里用的是standard
  Google: https://github.com/google/eslint-config-google
  XO: https://github.com/xojs/eslint-config-xo
  
 ? What format do you want your config file to be in? ...
> JavaScript// 我们配置文件是 js 也就是.eslintrc.js
  YAML
  JSON
  
 Checking peerDependencies of eslint-config-standard@latest
The config that you've selected requires the following dependencies:

eslint-plugin-vue@latest @typescript-eslint/eslint-plugin@latest eslint-config-standard@latest eslint@^7.12.1 eslint-plugin-import@^2.22.1 eslint-plugin-node@^11.1.0 eslint-plugin-promise@^4.2.1 || ^5.0.0 @typescript-eslint/parser@latest
? Would you like to install them now with npm?

+ eslint-plugin-import@2.23.4
+ eslint-plugin-node@11.1.0
+ eslint-config-standard@16.0.3
+ eslint-plugin-vue@7.11.1
+ eslint@7.29.0
+ @typescript-eslint/parser@4.27.0
+ @typescript-eslint/eslint-plugin@4.27.0
+ eslint-plugin-promise@5.1.0

然后是对eslint配置文件的编写

// .eslintrc.js
module.exports = {
  env: {
    browser: true,
    es2021: true
  },
  extends: [
    // 'plugin:vue/essential',// 这些可以通过看vue官方文档给出的解释进行自行配置
    
    // 使用 Vue 3 规则
    // https://eslint.vuejs.org/user-guide/#bundle-configurations
    'plugin:vue/vue3-strongly-recommended',
    'standard'
  ],
  parserOptions: {
    ecmaVersion: 12,
    parser: '@typescript-eslint/parser',
    sourceType: 'module'
  },
  plugins: [
    'vue',
    '@typescript-eslint'
  ],
  rules: {}
}

image.png 然后通过在我们script中加入相应的校验规则使其生效

接下来是 对Ts的相关配置

  • shimes-vue.d.ts 文件的作用

    • 为了 typescript 做的适配定义文件,因为.vue 文件不是一个常规的文件类型,ts 是不能理解 vue 文件是干嘛的 加这个文件是是告诉 ts,vue 文件是这种类型的。
  • vite-env.d.ts 文件的作用

    • 为了声明 我们在vite中使用env环境的配置 可以通过 import.meta.env.变量名称来访问
  • vue-tsc 和 tsc

    • tsc 只能验证 ts 代码类型
    • vue-tsc 可以验证 ts + Vue Template 中的类型(基于 Volar) 关于Vue3.x对Ts的支持我们可以移步官方文档这块 官方文档 那么结合Ts之后,Vue3.x就有了三种编写方式 Vue 3 支持三种写法:
  • Option API

import Vue from 'vue' 
const Component = Vue.extend({ 
// 类型推断已启用
}) 
const Component = { 
// 这里不会有类型推断, // 因为 TypeScript 不能确认这是 Vue 组件的选项
}
// 或者类语法
import { Vue, Component, Watch } from 'vue-property-decorator'
 
@Component
export default class YourComponent extends Vue {
  @Prop()
  isShow :false
  @Watch('child')
  onChildChanged(val: string, oldVal: string) {}
 
  @Watch('person', { immediate: true, deep: true })
  onPersonChanged1(val: Person, oldVal: Person) {}
}

import { defineComponent, getCurrentInstance } from "@vue/composition-api";
import TestComp from "./TestComp";
import AA from "./AA.vue";

export default defineComponent({
  name: "HelloWorld",
  props: {
    msg: String
  },
  components: {
    TestComp,
    AA
  },
  setup(props, ctx) {
    console.log(getCurrentInstance());
    console.log(ctx);
    return {
      AA
    };
  }
});
// 或者 TSX写法
import { defineComponent } from "@vue/composition-api";
import { VueConstructor } from "vue/types/umd";

type TestCompProps = {
  comp: VueConstructor<Vue>
}
export default defineComponent<TestCompProps>({
  name: "TestComp",
  props: {
    comp: {
      type: Object
    }
  },
  setup(props) {
    const { comp: Comp } = props;
    return () => <Comp />;
  }
});
  • <sciprt setup>(Composition API 的语法糖) 在语法糖里面,我们可以直接使用而不用返回
<script lang="ts" setup>
import { getLoginInfo } from '@/api/common'
import type { ILoginInfo } from '@/api/types/common'
import { onMounted, ref } from 'vue'
const list = ref<ILoginInfo['slide']>([])
onMounted(() => {
  getLoginInfo().then(res => {
    console.log(res)
    list.value = res.slide
  })
})
</script>
// 当然支持tsx
<script lang="ts" setup>
 const abc = <h1>哈哈</h1>
</script>

说到初始化,当然也少不了我们对Axios的封装

import axios, { AxiosRequestConfig } from 'axios'

const request = axios.create({
  // baseURL: import.meta.env.VITE_API_BASEURL
  // baseURL: '/admin'
})
// 请求拦截器
request.interceptors.request.use(function (config) {
  // 统一设置用户Token
  return config
}, function (error) {
  return Promise.reject(error)
})
// 响应拦截器
request.interceptors.response.use(function (response) {
  // 统一处理接口响应错误
  return response
}, function (error) {
  return Promise.reject(error)
})
// 这样封装后我们在请求时候可以定义返回数据的接口

export default <T = any>(config: AxiosRequestConfig) => {
  return request(config).then(res => {
    return res.data.data as T
  })
}

例:
import request from '@/utils/request'
import { ILoginInfo } from './types/common' // 此处的ILoginInfo就是我们接口的实现 大家也可以根据自己业务进行实现
export const getLoginInfo = () => {
  return request<ILoginInfo>({
    method: 'GET',
    url: '/admin/login/info'
  })
}

到此为止我们就初始化了一个Vite+Vue3.0+Ts项目,大家可以凭自己的喜好来选择更舒服友好的代码编写方式。

image.png