React项目从Javascript到Typescript的迁移经验总结
抛转引用
现在越来越多的项目放弃了javascript,而选择拥抱了typescript,就比如我们熟知的ant-design就是其中之一。面对越来越火的typescript,我们公司今年也逐渐开始拥抱typescript。至于为什么要使用typescript?本文不做深入探讨,对这方面有兴趣的小伙伴们可以去看一下这篇文章:
TypeScript体系调研报告
这篇文章比较全面地介绍了TypeScript,并且和Javascript做了一个对比。看完上面这篇文章,你会对TypeScript有一个比较深入的认识,另外在TypeScript和Javascript的取舍上,可以拿捏得更好。
开始迁移
在开始迁移之前,我要说点题外话,本篇文章仅是记录我在迁移过程中遇到的问题以及我是如何解决的,并不会涉及typescript的教学。所以大家在阅读本篇文章之前,一定要对typescript有一个基础的认识,不然你读起来会非常费力。
环境调整
由于Typescript是Javascript的超集,它的很多语法浏览器是不能识别的,因此它不能直接运行在浏览器上,需要将其编译成JavaScript才能运行在浏览器上,这点跟ES6需要经过babel编译才能支持更多低版本的浏览器是一个道理。
tsconfig.json
首先我们得装一个typescript,这就跟我们在用babel前需要先装一个babel-core是一个道理。
yarn global add typescript
这条命令是将typescript安装在全局,其实我个人建议是装在项目目录下的,因为每个项目的typescript版本是不完全一样的,装在全局容易因为版本不同而出现问题。但是后面我要执行tsc命令,所以我装在了全局。最好的情况就是全局和项目都装一个,但是如果你把tsc命令放在package.json中的script中去用的话,那么在项目里装就够了。接下来我们执行如下命令生成tsconfig.json,这玩意就跟.babelrc是一个性质的。
tsc --init
执行完之后,你的项目根目录下便会有一个tsconfig.json这么一个东西,但是里面会有很多注释,我们先不用管他的。
webpack
安装ts-loader用于处理ts和tsx文件,类似于babel-loader。
yarn add ts-loader -D
相应的webpack需要加上ts的loader规则:
module.exports = { //省略部分代码... module: { rules: [ { test:/\.tsx?$/, loader:'ts-loader' } //省略部分代码... ] } //...省略部分代码 }
之前用javascript的时候,可能有人不使用.jsx文件,整个项目都是用的.js文件,webapck里面甚至都不配.jsx的规则。但是在typescript项目中想要全部使用.ts文件这就行不通了,会报错,所以当用到了jsx的用法的时候,还是得乖乖用.tsx文件,因此这里我加入了.tsx的规则。
删除babel
关于babel这块,网上有不少人是选择留着的,理由很简单,说是为了防止以后会使用到JavaScript,但是我个人觉得是没有必要留着babel。因为我们整个项目里面基本上只有使用第三方包的时候才会用到javascript,而这些第三方包基本上都是已经编译成了es5的代码了,不需要babel再去处理一下。而业务逻辑里面用javascript更是不太可能了,因为这便失去了使用typescript的意义。综上所述,我个人觉得是要删除babel相关的东西,降低项目复杂度。但是有一个例外情况:。
当你用了某些babel插件,而这些插件的功能恰巧是typescript无法提供的,那你可以保留babel,并且与typescript结合。
文件名调整
整个src目下所有的.js结尾的文件都要修改文件名,使用到jsx语法的就改成.tsx文件,未使用的就改成.ts文件,这块工作量比较大,会比较头疼。另外改完之后文件肯定会有很多标红的地方,不要急着去改它,后面我们分类统一去改。
解决报错
webpack入口文件找不到
由于我们在做文件名调整的时候,把main.js改成main.tsx,因此webpack的入口文件要改成main.tsx。
module.exports = { //省略部分代码... entry: { app: './src/main.tsx' }, //省略部分代码... }
提示不能使用jsx的语法
这个解决很简单,去tsconfig配置一下即可。
{ "compilerOptions":{ "jsx": "react" } }
jsx这个配置项有三个值可选择,分别是"preserve","react-native"和"react"。在preserve和react-native模式下生成代码中会保留JSX以供后续的转换操作使用(比如:Babel)。另外,preserve输出文件会带有.jsx扩展名,而react-native是.js拓展名。react模式会生成React.createElement,在使用前不需要再进行转换操作了,输出文件的扩展名为.js。
模式 | 输入 | 输出 | 输出文件扩展名 |
---|---|---|---|
preserve | <div /> | <div /> | .jsx |
react | <div /> | React.createElement("div") | .js |
react-native | <div /> | <div /> | .js |
webpack里面配置的alias无法解析
module.exports = { //省略部分代码... resolve: { alias:{ '@':path.join(__dirname,'../src') } //省略部分代码... }, //省略部分代码... }
这里需要我们额外在tsconfig.json配置一下。
{ "compilerOptions":{ "baseUrl": ".", "paths": { "@/*":["./src/*"] } } }
具体如何配置,请看typescript的文档,我就不展开介绍了,但是要注意的是baseUrl和paths一定要配合使用。
https://www.tslang.cn/docs/ha...
无法自动添加拓展名而导致找不到对应的模块
原先我们在webpack里是这么配置的:
module.exports = { //省略部分代码... resolve: { //省略部分代码... extensions: ['.js', '.jsx', '.json'] }, //省略部分代码... }
但是我们项目里所有.js和.jsx的文件都改成了.ts和.tsx文件,因此配置需要调整。
{ //省略部分代码... resolve: { //省略部分代码... extensions: ['.ts','.tsx','.js', '.jsx', '.json'] }, //省略部分代码... }
Could not find a declaration file for module '**'
这个比较简单,它提示找不到哪个模块的声明文件,你就装个哪个模块的就好了,安装格式如下:
yarn add @types/**
举个