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

开发 项目管理
我们在搭建Vite项目,选择Vue模板之后,默认会下载Vue3模板。如果你的公司现在还没有准备使用Vue3,而在使用Vue2,那么这篇文章值得你继续看下去。

  [[425600]]

前言

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

安装所需依赖

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

初始化项目

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

yarn init -y 
  • 1.

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

初始化Vite

安装Vite。

yarn add vite -D 
  • 1.

初始化Vue2

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

yarn add vue 
  • 1.

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

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

yarn add vue-template-compiler -D 
  • 1.

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

yarn add vite-plugin-vue2 -D 
  • 1.

支持Composition-api

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

yarn add @vue/composition-api 
  • 1.

支持<script setup>语法

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

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

yarn add unplugin-vue2-script-setup -D 
  • 1.

了解更多,可以查看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 
  • 1.

支持TypeScript语法

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

yarn add typescript -D 
  • 1.

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

"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" 
} 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

搭建项目架构

首先,我先列出我自己搭建的项目文件目录,我是参照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 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

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

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> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

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" 
  } 
} 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.

ref-macros.d.ts

以d.ts后缀结尾的是TypeScript中的类型定义文件。我们知道自从引入 Composition API 以来,一个主要未解决的问题是 refs 与reactive的使用,到处使用 .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++ 
} 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

另外,这是一项实验性功能。实验性功能可能会改变补丁版本之间的行为。建议将您的 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<anyany> 
            | Set<any> 
            | WeakMap<anyany> 
            | 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 
} 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.

tsconfig.json

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

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

{ 
  "compilerOptions": { 
    "types": [ 
      "unplugin-vue2-script-setup/types" 
    ] 
  } 
} 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

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

{ 
  "compilerOptions": { 
    ... 
  }, 
  "vueCompilerOptions": { 
    "experimentalCompatMode": 2 
  }, 
} 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

最后,文件内容如下:

{ 
  "compilerOptions": { 
    "target""es2017", 
    "module""esnext", 
    "moduleResolution""node", 
    "esModuleInterop"true, 
    "strict"true, 
    "strictNullChecks"true, 
    "resolveJsonModule"true, 
    "types": [ 
      "unplugin-vue2-script-setup/types" 
    ] 
  }, 
  "vueCompilerOptions": { 
    "experimentalCompatMode": 2 
  } 
} 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

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, 
    }), 
  ], 
}) 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

介绍完这些文件,剩下的就是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'
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

shims-vue.d.ts

declare module '*.vue' { 
  import Vue from 'vue' 
  export default Vue 
} 
  • 1.
  • 2.
  • 3.
  • 4.

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" @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> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.

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> 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.

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

Foo.vue

<template> 
  <div>Foo</div> 
</template> 
  • 1.
  • 2.
  • 3.

Bar.vue

<template> 
  <div>Bar</div> 
</template> 
  • 1.
  • 2.
  • 3.

Async.vue

<template> 
  <div>Async Component</div> 
</template> 
  • 1.
  • 2.
  • 3.

结语

最后,我们启动下项目。

yarn dev 
  • 1.

如上图所示,启动成功。

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

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

https://github.com/maomincoding/viteVue2p 
  • 1.

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

本文转载自微信公众号「前端历劫之路」,可以通过以下二维码关注。转载本文请联系前端历劫之路公众号。

 

责任编辑:武晓燕 来源: 前端历劫之路
相关推荐

2021-03-22 05:58:22

Vite2TypeScript4Vue3

2020-09-19 21:15:26

Composition

2022-05-17 08:39:05

VueViteTypeScript

2021-07-06 07:02:41

Vue 2 Vite 开发工具

2022-02-18 09:39:51

Vue3.0Vue2.0Script Set

2021-07-26 10:00:55

script-setuAPI前端

2024-03-01 11:32:22

Vue3APIVue.js

2021-07-08 00:01:45

Vue2CompositionAPI

2024-10-18 10:49:03

Actions异步函数

2025-04-09 09:10:00

开发ViteVue

2022-07-13 10:07:31

vue3组件监听器

2021-09-15 07:56:32

TypeScriptVue项目

2021-12-15 08:23:42

Vue3 插件Vue应用

2021-08-11 08:31:42

前端技术Vue3

2021-05-24 08:04:03

script setuVue Vue 3

2011-09-02 14:35:32

UbuntuAndroidlinux

2023-04-27 11:07:24

Setup语法糖Vue3

2022-08-15 07:34:36

vite项目Vue3

2022-07-28 08:26:18

Vue3Uni-appVite

2022-07-27 08:40:06

父子组件VUE3
点赞
收藏

51CTO技术栈公众号