有一种说法是 9102 年作 Node 后台开发还不上 Typescript 不是太懒惰就是太菜了,其实假如你使用 Egg.js, 他们已经对基于 ts 开发作了许多支持,在项目里引入 ts 并无那么困难,且对减小开发过程当中的低级错误很是有帮助。
在这里记录一下我的在 Egg.js 项目里引入 ts 的一些约定,其实都在官方文档、文章和 Github issue 里了。javascript
web 开发不是瀑布流,定了需求闭门开发几个月上线,每每是基于线上运行的 js 项目,要改形成基于 ts,前提是不能中断服务,初步设想有如下三种方案:html
第一种方式在定义 .d.ts 文件时很是繁琐且会有一些坑,如很难推断函数返回类型,且在使用一些 es 原生方法时覆盖类型会有坑;前端
第二种方式须要实现一种流量切换的方式,如加入 haproxy 中间层,经过 header 或是 path 等方式来识别新老接口流量。碰到的主要问题是在新老项目一个服务每每要改动多个公共文件,很难保持同步,会有矛盾发生;java
第三种方式是最后采用的方式,从 js 代码中切出一个新分支,写了脚本批量替换文件后缀,花了大约 2-3 天完成迁移,期间在旧 js 代码中添加的新功能,须要确认在新 js 代码中也实现一遍。
过程当中也是发现了一些坑,举例:node
entries(o: {}): [string, any][];` 假如传入的参数类型是某种字符串字面量,这里变到 s 以后类型就成了 stringgit
参考 该文章github
在本地开发时,使用 egg-bin dev 命令启动应用,egg-bin 自带 ts-node,能够直接运行 ts 代码,无需编译过程;web
发布到线上时,egg 官方建议是仍是使用 Node + js 原生代码,使用 egg-script start 启动,因此须要将 ts 代码编译成 js 的过程。docker
在后端开发时能够主动升级 Node 版本,使用一些先进的 es 语法新特性,不像前端为了编译成浏览器广泛能兼容的 es5 代码会使用不少 polyfill 的技巧,因此 ts 代码编译成 js 后其实并无太难懂(tsconfig.json 里 compilerOptions => target -> es2017)。尽管如此使用编译后的 js 代码仍是须要映射回 ts 代码,以便线上报错时能有比较清晰的提示,ts 采用的方案是 sourceMap (tsconfig.json => compilerOptions =>inlineSourceMap -> true)。
关于 sourceMap 的原理能够参考阮一峰的这篇文章。typescript
egg-bin 在加载文件时,若是识别到同目录下的 .ts 文件和 .js 文件,会优先加载 .js 文件。
真实环境下,为了不把 .ts .js 文件同时托管在 git 上,形成混乱,最好是引入 ci 层完成编译的工做,这时就可使用单独的 dist 目录来托管编译后的 js 代码,无需上述 egg-ts-helper 操做,设置 tsconfig.json => compilerOptions => outDirs -> ./dist 便可。
egg 扩展了 koa 的application、context 对象,挂载了 controller、service、model 等对象在上面,然而你本身定义的 controller 文件 ts 没法感知他们和 egg 的关系,因此 egg 提供了 egg-ts-helper 工具来完成来自动生成 .d.ts 文件,放在 typings 目录。参考文章
因为 model 目录并非 egg 默认约定会使用的目录,只是大多数开发者的一个通识,因此针对 model 目录 egg-ts-helper 并不会主动生成 .d.ts 文件,你须要主动提供 tshelper.js 文件,利用 egg-ts-helper 提供的 api 来 watch model 目录。
启用 egg-ts-helper 的方式很简单,老的方式是 egg-bin dev -r egg-ts-helper/register 新的方式是设置 package.json => egg => declarations -> true
线上使用 ci 负责编译工做,ci 服务器须要下载所有依赖(包括 dependencies 和 devDependencies),获得编译产物后,再发布到 staging 服务器,staging 服务器只运行 npm install --production, 打包成 docker 镜像再发布