Vite+Vue2+Composition-api+<script setup>+TypeScript搭配如何开发项目?

简介: 好久没写文章了,今天终于有时间可以安安静静写文章了。

前言


Vite相信大家都用过,它是一种新型前端开发与构建工具,能够显著提升前端开发体验。我们在搭建Vite项目,选择Vue模板之后,默认会下载Vue3模板。如果你的公司现在还没有准备使用Vue3,而在使用Vue2,那么这篇文章值得你继续看下去。下面,我将带大家如何搭建一个 Vite+Vue2+Composition-api+<script setup>+TypeScript  搭配使用的项目。这篇文章很干,请大家点点赞哦!


安装所需依赖


又到了实战环节,下面可以一步步跟着我哦! 我这里使用的是yarn 依赖管理工具。


初始化项目


这里使用快捷初始化命令:


yarn init -y


创建完package.json文件之后,我们可以手动修改下项目名称字段name

vitevue2p


初始化Vite


安装Vite。


yarn add vite -D


初始化Vue2


我们需要安装Vue2,所以直接这样安装。


yarn add vue


目前,我安装的版本是^2.6.14


另外,我们还需要安装vue-template-compiler这个依赖,此包可用于将Vue 2.0模板预编译为渲染函数,以避免运行时编译开销和CSP限制。在编写具有非常特定需求的构建工具时,才需要单独使用它。所以,我们这里单独安装。


yarn add vue-template-compiler -D


最后,如果想让Vite支持Vue2,就必须安装这个依赖vite-plugin-vue2


yarn add vite-plugin-vue2 -D


支持Composition-api


Composition-api字面意思是组合API,它是为了实现基于函数的逻辑复用机制而产生的。这也是Vue3亮点之一,那么我们如何才能够在Vue2项目中使用呢?这需要安装@vue/composition-api依赖。


yarn add @vue/composition-api


支持<script setup>语法


<script setup> 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖,是Vue3.2新加入的语法。那么,我们也可以在Vue2项目中使用它。


你需要安装unplugin-vue2-script-setup依赖。


yarn add unplugin-vue2-script-setup -D


了解更多,可以查看https://github.com/antfu/unplugin-vue2-script-setup


在Vue2项目中使用Volar


以下是官方的解释:


我们建议将 VS Code 与 Volar 结合使用以获得最佳体验(如果您拥有 Vetur,您可能希望禁用它)。 使用 Volar 时,您需要安装 @vue/runtime-dom 作为 devDependencies 以使其在 Vue 2 上工作。


yarn add @vue/runtime-dom -D


支持TypeScript语法


随着应用的增长,静态类型系统可以帮助防止许多潜在的运行时错误,所以我们推荐使用TypeScript。


yarn add typescript -D


最后,我把安装的所有依赖列出来,可以参照有没有漏的。


"dependencies": {
    "@vue/composition-api": "^1.1.5",
    "vue": "^2.6.14"
  },
  "devDependencies": {
    "@vue/runtime-dom": "^3.2.11",
    "typescript": "^4.4.3",
    "unplugin-vue2-script-setup": "^0.6.4",
    "vite": "^2.5.7",
    "vite-plugin-vue2": "^1.8.1",
    "vue-template-compiler": "^2.6.14"
  }


搭建项目架构


首先,我先列出我自己搭建的项目文件目录,我是参照Vite默认模板而创建的文件目录。


- public
  -- favicon.ico
- src
  -- assets
    --- logo.png
  -- components
    --- Async.vue
    --- Bar.vue
    --- Foo.vue
    --- HelloWorld.vue
  -- App.vue
  -- main.ts
  -- shims-vue.d.ts
- index.html
- package.json
- ref-macros.d.ts
- tsconfig.json
- vite.config.ts


下面,我们按排列顺序分别看下文件中都放了什么东西?


public文件夹中放着一个ico图标文件,这个不再说明。src文件夹中文件有点多,我们放在最后讨论。


index.html


谈到index.html这个文件,我们需要引入Vite官网一段话:


你可能已经注意到,在一个 Vite 项目中,index.html 在项目最外层而不是在 public 文件夹内。这是有意而为之的:在开发期间 Vite 是一个服务器,而 index.html 是该 Vite 项目的入口文件。

Vite 将 index.html 视为源码和模块图的一部分。Vite 解析 <script type="module" src="..."> ,这个标签指向你的 JavaScript 源码。甚至内联引入 JavaScript 的 <script type="module"> 和引用 CSS 的 <link href> 也能利用 Vite 特有的功能被解析。另外,index.html 中的 URL 将被自动转换,因此不再需要 %PUBLIC_URL% 占位符了。


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <link rel="icon" href="/favicon.ico" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Vite App</title>
</head>
<body>
  <div id="app"></div>
  <script type="module" src="/src/main.ts"></script>
</body>
</html>


package.json


这个文件定义了这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证等元数据)。这里,需要注意的是我们自定义了 "scripts"字段,有三个命令:"vite --open""vite preview""vite build"


{
  "name": "vitevue2p",
  "version": "0.1.1",
  "description": "",
  "keywords": [],
  "license": "MIT",
  "main": "dist/index.js",
  "module": "dist/index.mjs",
  "scripts": {
    "dev": "vite --open",
    "serve": "vite preview",
    "build": "vite build"
  },
  "dependencies": {
    "@vue/composition-api": "^1.1.5",
    "vue": "^2.6.14"
  },
  "devDependencies": {
    "@vue/runtime-dom": "3.2.11",
    "typescript": "^4.4.3",
    "unplugin-vue2-script-setup": "^0.6.4",
    "vite": "^2.5.7",
    "vite-plugin-vue2": "^1.8.1",
    "vue-template-compiler": "^2.6.14"
  }
}


ref-macros.d.ts


d.ts后缀结尾的是TypeScript中的类型定义文件。我们知道自从引入 Composition API 以来,一个主要未解决的问题是 refsreactive的使用,到处使用 .value 可能很麻烦,如果不使用类型系统,很容易错过。 一些用户特别倾向于只使用reactive,这样他们就不必处理 refs


为了优化,官方提出了一个RFC,大家可以打开下面这个网址 https://github.com/vuejs/rfcs/discussions/369 了解一下。


下面,可以看下一个简单的例子。


// declaring a reactive variable backed by an underlying ref
let count = $ref(1)
// no need for .value anymore!
console.log(count) // 1
function inc() {
  // assignments are reactive
  count++
}


另外,这是一项实验性功能。实验性功能可能会改变补丁版本之间的行为。建议将您的 vue 依赖项固定到确切的版本以避免损坏。


言归正传,我们来看下ref-macros.d.ts文件中的内容。


import type {
  Ref,
  UnwrapRef,
  ComputedRef,
  WritableComputedOptions,
  WritableComputedRef,
  ShallowUnwrapRef,
} from '@vue/composition-api'
declare const RefMarker: unique symbol
  type RefValue<T> = T & { [RefMarker]?: any }
declare const ComputedRefMarker: unique symbol
  type ComputedRefValue<T> = T & { [ComputedRefMarker]?: any }
declare const WritableComputedRefMarker: unique symbol
  type WritableComputedRefValue<T> = T & { [WritableComputedRefMarker]?: any }
  type ToRawRefs<T extends object> = {
    [K in keyof T]: T[K] extends ComputedRefValue<infer V>
      ? ComputedRefValue<V>
      : T[K] extends WritableComputedRefValue<infer V>
        ? WritableComputedRef<V>
        : T[K] extends RefValue<infer V>
          ? Ref<V>
          : T[K] extends object
            ? T[K] extends
            | Function
            | Map<any, any>
            | Set<any>
            | WeakMap<any, any>
            | WeakSet<any>
              ? T[K]
              : ToRawRefs<T[K]>
            : T[K];
  }
/**
   * Vue ref transform macro for binding refs as reactive variables.
   */
declare function _$<T>(arg: ComputedRef<T>): ComputedRefValue<T>
declare function _$<T>(
  arg: WritableComputedRef<T>
): WritableComputedRefValue<T>
declare function _$<T>(arg: Ref<T>): RefValue<T>
declare function _$<T extends object>(arg?: T): ShallowUnwrapRef<T>
/**
   * Vue ref transform macro for accessing underlying refs of reactive varaibles.
   */
declare function _$$<T>(value: T): ComputedRef<T>
declare function _$$<T>(
  value: WritableComputedRefValue<T>
): WritableComputedRef<T>
declare function _$$<T>(value: RefValue<T>): Ref<T>
declare function _$$<T extends object>(arg: T): ToRawRefs<T>
declare function _$ref<T>(arg?: T | Ref<T>): RefValue<UnwrapRef<T>>
declare function _$shallowRef<T>(arg?: T): RefValue<T>
declare function _$computed<T>(
  getter: () => T,
  // debuggerOptions?: DebuggerOptions
): ComputedRefValue<T>
declare function _$computed<T>(
  options: WritableComputedOptions<T>,
  // debuggerOptions?: DebuggerOptions
): WritableComputedRefValue<T>
declare global {
  const $: typeof _$
  const $$: typeof _$$
  const $ref: typeof _$ref
  const $shallowRef: typeof _$shallowRef
  const $computed: typeof _$computed
}


tsconfig.json


tsconfig.json文件中指定了用来编译这个项目的根文件和编译选项。


我们这里需要注意如果您的 IDE 缺少全局类型。


{
  "compilerOptions": {
    "types": [
      "unplugin-vue2-script-setup/types"
    ]
  }
}


Volar 优先支持 Vue 3。Vue 3 和 Vue 2 模板有些不同。您需要设置 ExperimentCompatMode 选项以支持 Vue 2 模板。


{
  "compilerOptions": {
    ...
  },
  "vueCompilerOptions": {
    "experimentalCompatMode": 2
  },
}


最后,文件内容如下:


{
  "compilerOptions": {
    "target": "es2017",
    "module": "esnext",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "strict": true,
    "strictNullChecks": true,
    "resolveJsonModule": true,
    "types": [
      "unplugin-vue2-script-setup/types"
    ]
  },
  "vueCompilerOptions": {
    "experimentalCompatMode": 2
  }
}


vite.config.ts


这个文件是Vite的配置文件。当以命令行方式运行 vite 时,Vite 会自动解析项目根目录下名为 vite.config.js(或vite.config.ts) 的文件。


这里需要注意 refTransform 现在是插件根级选项,需要手动定义为true。(为什么配置refTransform,可以看上面ref-macros.d.ts文件中对refs处理,不使用.value的介绍)。


另外,如果想支持<script setup>语法,必须在这里以插件的形式配置。


import { defineConfig } from 'vite'
import { createVuePlugin as Vue2 } from 'vite-plugin-vue2'
import ScriptSetup from 'unplugin-vue2-script-setup/vite'
export default defineConfig({
  plugins: [
    Vue2(),
    ScriptSetup({
      refTransform: true,
    }),
  ],
})


介绍完这些文件,剩下的就是src文件夹中的文件了,因为文件过多,我们把它单独放在Src文件夹栏目中。


Src文件夹


assets文件中只有logo.png一个图片,你可以把静态文件放在当中,这里不多过介绍。


main.ts


这是Vue2的入口文件,我们可以看到这里VueCompositionAPI被当做插件引入。另外,我们引入的App.vue以及其他*.vue为后缀的文件,需要有专门的类型定义文件进行声明,在下面的shims-vue.d.ts文件中我们会讲到。


import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'
import App from './App.vue'
Vue.use(VueCompositionAPI)
const app = new Vue({ render: h => h(App) })
app.$mount('#app')


shims-vue.d.ts


declare module '*.vue' {
  import Vue from 'vue'
  export default Vue
}


App.vue


这个文件是页面入口文件。我们来看下它是如何写的,这是Vue2项目,但是写法与Vue3项目无异,只不过在Vue2项目中需要'@vue/composition-api'使用Composition-api,而Vue3项目直接引入vue


另外,这里看到我们直接使用<script setup>语法,替换了之前setup()方法,使代码更简洁。还有我们可以直接引入组件,直接在模板中使用。


更多关于<script setup>语法的内容可以看看https://v3.cn.vuejs.org/api/sfc-script-setup.html,了解更多使用方法。


<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <hello-world name="Vue 2 + TypeScript + Vite + Composition-api" @update="onUpdate" />
    <async-component />
  </div>
</template>
<script setup lang="ts">
import { defineAsyncComponent } from '@vue/composition-api'
import HelloWorld from './components/HelloWorld.vue'
const AsyncComponent = defineAsyncComponent(() => import('./components/Async.vue'))
function onUpdate(e: any) {
  console.log(e)
}
</script>
<script lang="ts">
export default {
  name: 'App',
}
</script>
<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>


HelloWorld.vue


然后,我们再看下这个文件中什么内容。这里需要注意的是$ref() $computed()方法,这就是之前提到的refTransform语法,不得不说,这比以前使用.value处理方便多了。


<template>
  <div>
    <h1>{{ msg }}, {{ name }}</h1>
    <button @click="inc">
      Inc
    </button>
    <div>{{ count }} x 2 = {{ doubled }}</div>
    <button @click="dec()" v-html="decText" />
    <component :is="count > 2 ? Foo : Bar" />
  </div>
</template>
<script setup lang="ts">
import { watch } from '@vue/composition-api'
import Foo from './Foo.vue'
import Bar from './Bar.vue'
const props = withDefaults(defineProps<{ msg: string; name: string | number }>(), { msg: 'Hello' })
const emit = defineEmits(['update'])
let count = $ref(1)
// eslint-disable-next-line prefer-const
let doubled = $computed(() => count * 2)
function inc() {
  count += 1
}
function dec() {
  count -= 1
}
const decText = '<b>Dec</b>'
watch(()=>count, value => emit('update', value))
</script>
<style scoped>
button{
  margin: 20px 0;
}
</style>


其他文件就不过多介绍了,就只是简单的模板文件。


Foo.vue


<template>
  <div>Foo</div>
</template>


Bar.vue


<template>
  <div>Bar</div>
</template>


Async.vue


<template>
  <div>Async Component</div>
</template>


结语


最后,我们启动下项目。


yarn dev


微信截图_20220506195013.png


如上图所示,启动成功。


相信这样可以在一定程度上提升你 Vue 2 的开发体验,赶快来!


以下是本篇文章的源码地址:


https://github.com/maomincoding/viteVue2p


如果觉得这篇文章对你有帮助,感谢点赞哦~



相关文章
|
19天前
|
JavaScript 前端开发
Vue2整合TypeScript:借助vue-property-decorator以类模式编写组件
Vue2整合TypeScript:借助vue-property-decorator以类模式编写组件
86 3
|
26天前
|
JavaScript 前端开发 API
探索Vue.js 3的组合式API:一种更灵活的组件状态管理方式
【10月更文挑战第5天】探索Vue.js 3的组合式API:一种更灵活的组件状态管理方式
|
28天前
|
JavaScript API
|
27天前
|
JavaScript 前端开发 安全
|
6月前
|
设计模式 JavaScript API
Vue.js的provide/inject API实现了依赖注入
【5月更文挑战第17天】Vue.js的provide/inject API实现了依赖注入,允许父组件向深层子组件传递依赖,降低耦合,提高代码可维护性和测试性。通过provide选项提供依赖,如`provide: {foo: &#39;foo&#39;, bar: this.bar}`,子组件通过inject选项接收,如`inject: [&#39;foo&#39;, &#39;bar&#39;]`。适用于跨组件共享数据、插件开发和高阶组件。然而,应谨慎使用以防止过度复杂化代码结构。
49 0
|
3月前
|
JavaScript 前端开发 API
Vue.js 3.x新纪元:Composition API引领潮流,Options API何去何从?前端开发者必看的抉择指南!
【8月更文挑战第30天】Vue.js 3.x 引入了 Composition API,为开发者提供了更多灵活性和控制力。本文通过示例代码对比 Composition API 与传统 Options API 的差异,帮助理解两者在逻辑复用、代码组织、类型推断及性能优化方面的不同,并指导在不同场景下的选择。Composition API 改善了代码可读性和维护性,尤其在大型项目中优势明显,同时结合 TypeScript 提供更好的类型推断和代码提示,减少错误并提升开发效率。尽管如此,在选择 API 时仍需考虑项目复杂性、团队熟悉度等因素。
51 0
|
3月前
|
JavaScript 前端开发 安全
【技术革新】Vue.js + TypeScript:如何让前端开发既高效又安心?
【8月更文挑战第30天】在使用Vue.js构建前端应用时,结合TypeScript能显著提升代码质量和开发效率。TypeScript作为JavaScript的超集,通过添加静态类型检查帮助早期发现错误,减少运行时问题。本文通过具体案例展示如何在Vue.js项目中集成TypeScript,并利用其类型系统提升代码质量。首先,使用Vue CLI创建支持TypeScript的新项目,然后构建一个简单的待办事项应用,通过定义接口描述数据结构并在组件中使用类型注解,确保代码符合预期并提供更好的编辑器支持。
79 0
|
3月前
|
JavaScript 前端开发 安全
立等可取的 Vue + Typescript 函数式组件实战
立等可取的 Vue + Typescript 函数式组件实战
|
3月前
|
JavaScript 前端开发 测试技术
[译] 用 Vue.js 3 Composition API 创建 i18n 插件
[译] 用 Vue.js 3 Composition API 创建 i18n 插件
|
4月前
|
JavaScript 前端开发
【Vue3+TypeScript】CRM系统项目搭建之 — 关于如何设计出优质的 Vue 业务组件
【Vue3+TypeScript】CRM系统项目搭建之 — 关于如何设计出优质的 Vue 业务组件
47 0
【Vue3+TypeScript】CRM系统项目搭建之 — 关于如何设计出优质的 Vue 业务组件