最初是2年前的一个现有项目创建的。随着时间的推移,代码量暴涨到近万个文件,但工程也慢慢到了无法维护的地步。想给他一个大改,但是侵入式的代码配置太多了。。。最后折衷的引入了TypeScript,结合Api,vueuse来完善项目。工程标准化程度,整个过程让我感觉挺一般的,记录一下。首先配置一些TypeScript相关库的安装配置。由于webpack的版本还是3.6,我几次尝试升级到4和5,但是因为大量的配置和侵入性的代码修改工作而放弃了,所以我直接找到了下面的库npmi-Dts-loader@3.5.0tslint@6.1.3tslint-loader@3.6.0fork-ts-checker-webpack-plugin@3.1.1接下来就是更改webpack的配置,修改main.js文件为主。ts,并在文件的第一行添加//@ts-nocheck,让TS忽略检查这个文件,相应的将webpack.base.config.js的入口改成webpack.base.config中的main.ts。在jsresolve的扩展中添加.ts和.tsx,在别名规则中添加'vue$':'vue/dist/vue.esm.js'添加插件选项到webpack.base.config.js添加fork-ts-checker-webpack-plugin将tscheck的任务放到一个单独的进程中,以减少开发服务器的启动时间在webpack.base.config.js文件的规则中添加两个配置和fork-ts-checker-webpack-插件配置{test:/\.ts$/,exclude:/node_modules/,enforce:'pre',loader:'tslint-loader'},{test:/\.tsx?$/,loader:'ts-loader',exclude:/node_modules/,options:{appendTsSuffixTo:[/\.vue$/],transpileOnly:true//禁用类型检查器-我们将在fork插件中使用它}},,//...plugins:[newForkTsCheckerWebpackPlugin()],//独立进程处理ts-checker,缩短webpack服务冷启动和热更新时间https://github.com/T在ypeStrong/ts-loader#faster-builds根目录下添加tsconfig.json文件补充相应配置,并添加vue-shim.d.ts声明文件tsconfig.json{"exclude":["node_modules","static","dist"],"compilerOptions":{"strict":true,"module":"esnext","outDir":"dist","target":"es5","allowJs":true,"jsx":"preserve","resolveJsonModule":true,"downlevelIteration":true,"importHelpers":true,"noImplicitAny":true,"allowSyntheticDefaultImports":true,"moduleResolution":"node","isolatedModules":false,"experimentalDecorators":true,"emitDecoratorMetadata":true,"lib":["dom","es5","es6","es7","dom.iterable","es2015.promise"],"sourceMap":true,"baseUrl":".","paths":{"@/*":["src/*"],},"pretty":true},"include":["./src/**/*","typings/**/*.d.ts"]}vue-shim.d.tsdeclaremodule'*.vue'{importVuefrom'vue'exportdefaultVue}路由配置改进原创路由配置通过配置路径,name,component,在开发和维护的过程中存在一些不足:在使用的时候,path或者name的使用可能不规范,不统一。文件不方便手动避免路由名称和路径与其他路由冲突。路由路径根据业务分为不同的枚举。在枚举中定义可以防止路由路径冲突,也可以更加语义化地定义枚举的key。也可以借助Typescript的类型推断能力快速完成。在查找单个文件对应的路由时,可以一步完成。为什么不用name,因为name只是这条路由的语义标识。当我们使用枚举类型的路径时,枚举Key就足以充当语义路径。path的name属性只是没有存在的必要,我们在声明路由的时候不需要声明name属性,我们只需要path和component字段demoexportenumROUTER{home='/xxx/home',About='/xxx/about',}exportdefault[{path:ROUTER.Home,component:()=>import(/*webpackChunkName:'Home'*/'views/Home')},{path:ROUTER.About,component:()=>import(/*webpackChunkName:'About'*/'views/About')}]我们项目中的常量和枚举也通过将所有常量提取到services/const中来管理。现在集成Typescript之后,我们之后,项目可以在services/constant中管理常量,在services/enums中管理枚举。比如普通接口返回的code可以声明为一个枚举,这样使用的时候就不需要写类似if(res.code===200)的判断,直接通过declared获取即可RES_CODEenumeration所有接口返回码类型//services/enums/index.ts/**RES_CODEEnum*/exportenumRES_CODE{SUCCESS=200//xxx}比如我们可以在services/constant/storage中声明存储key。ts/**userInfo-storageKey*/exportconstUSERINFO_STORE_KEY='userInfo'/**用户相关的key可以通过构造一个带有业务属性参数的纯函数来声明*/exportconstUserSpecialInfo=(userId:string)=>{return`specialInfo-${userId}`}类型声明文件规范全局类型声明文件统一维护在根目录的typings文件夹中(可复用数据类型)相对于业务中组装数据过程中的类型,直接在component类型封装请求库可以维护接口中的类封装逻辑(不易复用的数据结构)。在utils文件夹下添加一个requestWrapper.ts文件,然后所有request基类方法封装都可以在这个文件中维护'//请求参数在后面打包的时候是特定于某个类型的。这里使用unknown语句返回值是一个泛型类型S,使用导出函数时填写具体类型PostWrapper(url:string,data:unknown,timeout?:number){return(request({url,方法:'post',data,timeout})asAxiosResponse['data'])asBASE.BaseResWrapper//BASE是在typings中定义的命名空间,后面会有代码说明}在具体业务层进行封装使用在api/user新建一个index.ts文件,与之前的比较即可done够简洁了,还能提供类型提示,知道请求是什么,传参的参数和返回值这个接口在注释里,我们不需要用注释来标识我们需要什么类型的参数,TS会帮我们完成,我们只需要填写请求参数的类型和返回参数的类型约束使用请求方法/**获取用户信息*/exportfunctiongetUserInfo(query:User.UserInfoReqType){returnPostWrapper
