vite-----TypeScript

Vite 天然支持引入 .ts 文件。

Vite 仅执行 .ts 文件的转译工作,并  执行任何类型检查。并假设类型检查已经被你的 IDE 或构建过程接管了(你可以在构建脚本中运行 tsc --noEmit 或者安装 vue-tsc 然后运行 vue-tsc --noEmit 来对你的 *.vue 文件做类型检查)。

Vite 使用 esbuild 将 TypeScript 转译到 JavaScript,约是 tsc 速度的 20~30 倍,同时 HMR 更新反映到浏览器的时间小于 50ms。

$ pnpm create vite
# 输入项目名称 vite-basics-vue-ts
$ cd vite-basics-vue-ts
$ pnpm i
$ pnpm run dev

下面仔细观察一下 项目下的一些文件,发现多了一个ts的配置tsconfig.json,同时还多了一个tsconfig.node.json的配置,他两是有关联的。

另外打开src,发现我们的入口 main.js 变成了 main.ts,这就说明我们可以执行ts的文件了。

刚才我们说过vite可以天生的支持.ts这样的文件,我们可以做个试验,下面在src下创建一个新的文件,取名为test.ts,在这里我们可以写入一些ts的代码

// src/test.ts
interface Person {
  name: string
}

let person: Person = {
  name: 'felix',
  age: 19
}

接下来我们可以通过interface定义一个Person这样的一个接口,在这里定义一个属性name,它的类型是string,然后我们在外侧再定义一个变量person,它的类型是Person类型,它的值是一个对象,里面有name这个属性,比方说我们定义为felix,接下来我们再定义一个属性age,它的值为19,大家发现我们现在已经通过所谓的IDE,也就是vscode,帮助我们检查出是有问题的,腻味我们再 interface里并没有定义age这个属性。但是我们也说了,vite只是帮我们ts的编译,并不做类型的检查,那这个检查的工作是由IDE完成的。那就意味着我们代码只要基本上能够编译,它就能够帮助我们的开发环境里运行。

我们可以做个实验,

// src/test.ts
interface Person {
  name: string
}

let person: Person = {
  name: 'felix',
  age: 19
}

export {
  person
}


// src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
import { person } from './test'
console.log(person.age)

createApp(App).mount('#app')

下面呢我们可以在 main.ts 里边,去引入我们 test.ts,这个模块里边暴露的接口,那我们可以暴露一下,比如说我们执行一下 export,暴露一下 person,然后我们打开 main.ts,来去引入这个模块,注意这里有个问题,大家不要在这里边加入.ts 这样的扩展名,不然这情况下呢,我们在 VScode 里边会报,告诉我们不要以 .ts 扩展名结束,因为这里面呢,我们将来在浏览器上运行我们模块的时候呢,它是不能够支持 .ts 这样的扩展名的。所以呢我们就让 Vite 来做,给我们做编辑就好了,所以这个扩展名我们就不要加了,然后我们要导入一个 person,接下来呢我们可以去在控制台上面,打印一下person 对向下面的 age,我们看能不能正常打印出来哈,那事实上呢,在我们的 VScode 的里边已经告诉我们,这个 age 是有问题的,因为我们的 person,是不存在 age 这个属性的,但是事实上呢,我们的 Vite 也是帮助我们编译了,我们可以保存一下,打开控制台,我们看一下19正常的打印出来了,那如果是我们这个错误,不想在我们的生产环境下面去运行的话,那我们可以在编译的时候加一些参数 ,让我们的 Vite来帮助我们把这些错误拦截下来。当然了我们也可以在Vs的环境下面,通过它给我们的提示,来去解决这些问题,比方说我们打开 test.ts,我们可以把这句话注掉,这样的话呢就不存在这个问题了。

// src/test.ts
interface Person {
  name: string
}

let person: Person = {
  name: 'felix',
  // age: 19
}

export {
  person
}

那我们如果是在开发的时候写入了这样的代码,可以在 build 的时候来去检查。那我们现在来看一下,在 package.json 的时候

{
  "name": "vite-basics-vue-ts",
  "private": true,
  "version": "0.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc --noEmit && vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "vue": "^3.2.25"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^2.2.0",
    "typescript": "^4.5.4",
    "vite": "^2.8.0",
    "vue-tsc": "^0.29.8"
  }
}

我们有一个 build ,就是所谓的构建的命令,在这个构建脚本里边呢,它跟我们使用的是 vue-tsc --noEmit,那前提是我们到现在环境下,得需要安装 vue-tsc,很显然我们的这个脚手架已经帮助我们把这个vue-tsc 给装好了,所以呢,我们直接可以在去编译的时候呢,帮助我们检查这个错误,--noEmit表示当我们这个代码一旦出现错误的时候呢,编译是不通过的,它就会在控制台上面给我们打印个错误,我们来去运行一下,打开终端我们按住 ctrl c 先跳出我们的服务,执行一下pnpm run build,好等待我们命令的执行

哎我们发现呢,现在给我们报这个 age:19 这样的错误,这个编译是失败了的,当然了如果是你不使用 vue-tsc,比方说在 React 或者是其它的环境下面,你可以使用tsc --noEmit也是可以的,由于我们现在的项目环境呢是 Vue 环境,所以呢,我们就使用 Vue 给我们提供的 vue-tsc --noEmit

接下来呢我们来看 ts 的一个重要选项,叫做isolatedModules,因为在 ts 里边,它都是使用 esbuild 的来去进行 ts 编译的,而 esbulid 是指执行没有类型信息的转移,而且呢它也只能支持单个模块的转移,因此如果我们使用一些不支持的特性,比如说像什么枚举啊,隐式类型啊等等。或者是我们一个模块引入了另外一个模块,在编译过程中,它不能够进行多个模块之间的编译,所以呢我们必须在tsconfig.json 的compilerOptions 里面设置这个isolatedModules 这个选项,并且把它设置为 true,这样的话呢,ts 就会警告我们不要使用类似于isolatedModules,也就是隔离的一些转移的功能了,我们来演示一下

返回代码,我们重新启动一下我们这个项目,执行一下pnpm run dev,我们在浏览器上打开这个项目, 然后接下来我们做一件事情,把 test.ts 里边的这个类型,给作为一个模块给导出出去,然后接下来我们在 src 下面定义一个新的 ts 文件,比方说我们叫 types.ts,然后把这个模块放到这,然后呢我们可以执行一下 export,把 person这个类型导出,这在我们 ts 编写代码的时候呢是非常常见的,然后我们在test.ts 里边再把这个类型给导入进来,我们执行一下 import { Person } from './types',这样的话呢我们这个代码呢仍旧是没有问题。

// src/types.ts
interface Person {
  name: string
}

export {
  Person
}


// src/test.ts
import { Person } from './types'
let person: Person = {
  name: 'felix',
  age: 19
}

export {
  person
}

那我们来验证一下在浏览器上面是否能正常的运行呢。我们可以打开终端,然后这个19啊,我们可能怀疑是它第一次打印的,所以呢,我们现在先退出我们这个服务啊,再重新的启动一下,然后我发现 19仍旧被打印出来了,因为这个19的错误呢,不是我们当前考虑的问题,那很显然我们把一个单独的模块给导出出去以后,我们再导入是没有问题的,因为这个时候呢,Vite 会把我们这个模块进行正常的导入,因为这个模块,只有我们当前的这个 test.ts 去使用的,那如果我们在这个模块里边,再次导出这个 Person,

// src/test.ts
import { Person } from './types'
let person: Person = {
  name: 'felix',
  age: 19
}

export {
  person,
  Person
}

好,我们发现现在浏览器上面就报错了,它说 The requested module 就是你请求的src 下的 types.ts,does not provide an export named person,也就是说它没有提供一个导出的名字 person,这是为什么呢,因为我们的,beat 是使用 esbuild 的来进行 ts编译的,它只支持单个模块的编译,如果是我们这个模块,又导出到其它的模块里使用,那么很显然,在浏览器上面就会有问题了,因 Vite 不支持这种功能,而我们在开发过程中并不知道这个问题,因为它没有给我们报出错误来。

那我们得需要去加一个配置选项,所以呢,我们在 tsconfig. json 里边加一个新的配置,像叫 isolatedModules,

// tsconfig.json
{
  "compilerOptions": {
    "target": "esnext",
    "useDefineForClassFields": true,
    "module": "esnext",
    "moduleResolution": "node",
    "strict": true,
    "jsx": "preserve",
    "sourceMap": true,
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "lib": ["esnext", "dom"],
    "isolatedModules": true
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

把它设置为 true 好保存一下,那么接下来,我们在浏览器上面仍旧看到这个问题,因为这问题仍然存在,那我们在 type.ts 里边呢 ,我们看到这里就给我们画上一个红色的波浪线了,那很显然,当前呢我们这个问题呢,应该在开发的时候就发现了。

在 vite 的 esbulid 的里边,除了我们的这个模块的关联的导入导出,它不支持以外,其它的有一些 ts 的特性也不支持,比如像枚举,那我们举个例子,现在我们把 person 给注释掉,让我们的页面恢复正常,然后我们在上边呢通过 declare,来去定义一个枚举的类型

// src/types.ts
interface Person {
  name: string
  age: number
}

export {
  Person
}


// src/test.ts
import { Person } from './types'
declare const num Age {
  age1 = 18,
  age2 = 19
}
let person: Person = {
  name: 'felix',
  age: Age.age1
}

export {
  person,
  // Person
}

我们可以定一个常量,它是一个枚举的类型,比方说我们定一个 age,这样的枚举类型我们可以定义一个 age1,这是等于号啊等于18,然后我们再定一个 age2,它的值呢我们可以定义成19,好中间呢我们可以加一个逗号,定义完了以后呢,接下来我们就可以,把我们这个 age 的值,变成一个 age1 了,但这里边呢有另外一个错误,因为我们在 person 里边,并没有定义age 这个属性,我们可以在 type 里边把它定义上,在 types.ts 里边,我们再加一个新的属性,比方说我们定义一个 age 属性,它的类型是 number,这样的话我们在 test.ts 里边呢,就可以去定义我们 age 这个属性了,但是这里边给了我们一个新的提示,我们来看一下这个提示呢告诉我们,我们用了这个 isolatedModules,无法访问环境中的常量枚举,它是不支持的,那我们可以在开发环境中呢能够看到这个问题,那我们运行一下看看呢,这里告诉我们 Age 是没有定义的。

关于这个配置选项呢还有一点,这一点的话呢一般情况下我们只有在做一些特殊的代码编写的时候呢,才能遇得到,比方说我们在 src 里面创建一个新的文件叫做 no-export.ts,我们在里面呢 ,我们定义一个常量const ,比方说定一个a等于100,我们发现这里有一个新的错误了,它说这里加了isolatedModules这个选项,那它编译这个no-export.ts的时候,被视为全局脚本,让我们使用导入导出来去让他正常编译。那其实事实上我们不需要什么工作,我们只需要来一个export { a }就可以了,只要我们有导出的动作,或者是我们没有导出,我们直接来一个导入,比方说我们在这个模块里,import { Person } from './types',当然这个Person暂时没什么用,但是他也不会出现什么问题了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值