面试官:回答我!在tsconfig配置了别名你为啥要在vite再配置一遍?嗯?

在一个月黑风高的夜晚,面试官看到我简历上的:熟悉typescript,轻蔑一笑:"你说你熟悉ts,那我问你,你配置的tsconfig里moduleResolution的node选项和classic选项有何区别?你都在tsconfig配置了别名,为什么要在vite.config.js里的resolve.alias又配置一遍?

回想起create-vite-app一路回车的爽感,回想起Vite + Vue3上手就开发的便利,我滴下了一滴冷汗。开始疯狂的头脑风暴

各位朋友,其实答案很简单,甚至各个前端er有手就会,只要稍微多想想。

Ts是什么,有什么用?

追根溯源,首先简略回想一下ts是个什么东西

  • js的超集,js被ts包含,所有js代码都是有效的ts代码
  • 静态类型检查,规避弱类型语言js可能发生的各种运行时错误
  • 增加代码感知,编程时获得属性提示
  • ...

可惜,浏览器他实在太专一了,他只认低级的ES5语法(不绝对,有些浏览器也支持ES6)。ts想在浏览器上运行还得经过一层编译,或者说转译,从ts转为js,再由babel将高级js语法转为低级js语法

Ts如何转为js?

当我们想要使用ts的时候,我们可以用pnpm add typescript为我们的项目加上ts依赖库。装上之后在node_modules/.bin文件夹就可以看到tsc可执行文件。这个时候我们可以利用npx tsc xxx来将ts文件转为js文件

为何要用tsconfig.json?

如果你仅需要编译一两个ts文件,直接用npx tsc或许是不错的选择,但当你的项目中包含了上百个ts文件,写一个集中的配置tsconfig或许是更明智的选择。

当你命令行输入tsc / npx tsc 的时候,tsc就会从执行的目录开始逐级向上找tscongig.json找到后按配置执行

中场休息

回想到这里,我已向面试官露出了微笑,tsconfig的别名、moduleResolution的设置,当然是帮助tsc运行的。vite.config.js的别名当然是帮助vite运行的,你说两者他搭嘎吗?他都不搭嘎,我设置两次别名很奇怪吗?

就在我胸有成竹,喷薄欲出的时候,面试官的冷笑让我冷静下来:我就这么说合适吗?合适吗?他会满意吗?还得说说原理吧...最好还要说说怎么能给他一次配置,两边通用吧...

我咬着牙,进行了第二次头脑风暴...

tsc相关的运行机制

首先我们想到,vite不仅仅是一个单纯的打包工具,他能编译ts、js,能处理scss、less,能处理静态文件,能启动本地服务...

换句话说,tsc只是vite play中的一环,而tsc只负责将ts转为js(影响范围可用include、exclude配置)

moduleResolution这个属性也很有意思,他的node策略模拟了 Node.js 的 CommonJS require() 解析算法,帮助代码找到他们的依赖项,而classic策略可以说是历史遗留问题,这是早期的策略,据我模糊不真实的记忆,设置classic之后再想要引用第三方库只能写../../node_modules/xxx 这种形式,实在过于反人类。至于为什么还能保留这个选项,大概是历史遗留的代码太多,直接弃用太痛了

别名其实也就是将设置的@替换成baseUrl + 'src' 然后tsc根据moduleResolution的策略寻找依赖项而已

至此,我们可以总结:tsconfig的别名和moduleResolution的作用其实就是

  1. 别名:将你设置的类似@ 的别名替换成baseUrl + 'src'
  2. moduleResolution:使用设定的策略,定义tsc寻找依赖文件的方式

二者都是用自己不同的方式帮助tsc寻找到正确的依赖文件

需要注意的是,tsc在编译时,即使找到了依赖项,也仅负责ts转为js的部分,并不会进行路径的改写,也就是说:你写的 import xxx from '@/xxx' 还是保留原样

vite相关的运行机制

tsc把ts一编译就直接原封不动的丢来了import xxx from '@/xxx' ,但是作为老妈子的vite 可不能这么不负责任,因为vite编译后的代码可是要在浏览器上运行的。浏览器知道什么,他太单纯了,不可能会认识 '@/' 这样子妖艳的 '码' 的,他只认识 './' 码 和 '../' 码。所以经过vite编译后的代码,才真正消除了'@'别名

与此相对应的,tsc是根据moduleResolution的策略来寻找三方库的,vite呢?

在node_modules下面有这样的目录:.vite/deps,这是vite利用esbuild进行预构建之后生成的第三方依赖代码,vite会将引用第三方库,比如lodash,直接改成写成引用node_modules/.vite/deps/lodash.js 这样一种形式,来帮助浏览器找到正确的依赖文件

tsconfig别名与vite别名同步

回忆至此,我早已了然。甚至于悠然回想起写过的一个vite小插件,帮助同步两个别名,原理很简单

利用node的fs模块读取项目中tsconfig的配置,当然也可以用load-tsconfig这个第三方库来帮助读取,读取之后提取paths属性,在插件的config钩子函数中根据paths属性生成vite规则定义的对应的alias别名,然后

return { resolve: { alias } }

等会儿就说给这个面试官听,让他也知道知道我的厉害

总结

  1. moduleResolution的node策略模拟了 Node.js 的 CommonJS require() 解析算法,可以通过require('axios')的方式直接找到第三方库,而classic策略则只能通过../../node_modules的方式
  2. tsconfig所定义的别名仅起作用在tsc的编译阶段,将别名替换成对应的路径,帮助tsc寻找到正确的依赖,编译后的文件并未进行别名替换,且无法直接运行于浏览器
  3. 而vite所定义的别名起作用在dev/build 阶段,也就是启动本地服务和打包的阶段,编译后的文件会直接进行别名替换改写,且直接运行于浏览器
  4. vite会进行依赖预构建,且在找寻第三方依赖时会将路径改写到node_modules/.vite/deps目录下
  5. tsconfig和vite的别名其实各不相关,仅在各自的阶段各司其职,但是由于开发的候的观感,让人以为其有联系
  6. tsconfig和vite的别名确实在很多情况下完全一致,可以利用vite插件来进行同步,仅配置一次tsconfig别名,同步到vite别名上
  7. 如有错误,还请指出,本小白立刻改正!

面试官:?请问你在做什么?怎么发了这么久的呆,还一脸痴汉笑?不想过面试了?

相关推荐
太阳上的雨天3 小时前
与 TRON (波场) 区块链进行交互的命令行工具 (CLI): tstroncli
typescript·区块链·交互·tron·trx·trc20
前端拿破轮4 小时前
HomeBrew创始人都写不出来的翻转二叉树到底怎么做?
前端·算法·typescript
趣多多代言人7 小时前
20分钟学会TypeScript
前端·javascript·typescript
pimkle1 天前
LC 135 分发糖果 JavaScript ts
leetcode·typescript
烛阴2 天前
深入浅出,教你用JS/TS轻松搞定Excel与XML互转
前端·javascript·typescript
cxr8282 天前
Vercel AI SDK 3.0 学习入门指南
前端·人工智能·学习·react.js·typescript·npm·reactjs
irises2 天前
插件化埋点采集sdk设计与实现
前端·typescript
AndyGoWei2 天前
TypeScript 基本原理和使用方法,看这篇文章就够了
javascript·typescript
東南3 天前
typescript之前端系列,知其然,知其所以然
面试·typescript