全栈算力,加速行业AI落地 了解详情
写点什么

基于 TypeScript 的 Weex 优化实践

  • 2020-08-02
  • 本文字数:4274 字

    阅读完需:约 14 分钟

基于 TypeScript 的 Weex 优化实践

一、背景

Weex 作为一种成熟的跨平台程序框架被运用到许多产品中,有赞也不例外。有赞零售移动端团队从 2018 年就开始使用 Weex 构建页面,据不完全统计,有赞零售移动端有超过 300 个页面使用到了 Weex 开发!显然,这是一个巨大的开发工程,同时我们也发现基于 JavaScript 的 Weex 开发给我们带来了诸多痛点:


  • 缺少类型约束,编程时代码提示全凭记忆,要拓展新功能也束手束脚。

  • 手误写错某个变量名,只能在联调、测试阶段才能发现。

  • 面对复杂业务逻辑,代码层面可控性、扩展性较差。

  • 总会遇到 xxxisundefined 的空指针问题。


这些问题我们都在 TypeScript 找到了答案。

二、什么是 TypeScript

TypeScript 是微软开源的编程语言,它建立在 JavaScript 的基础上,是 JavaScript 的超集,可以编译成 JavaScript。它有以下特点:


1.始于 JavaScript,归于 JavaScript


TypeScript 从今天数以百万计的 JavaScript 开发者所熟悉的语法和语义中拓生而来,所使用的是通用的 JavaScript 代码,包括流行的 JavaScript 库,从 JavaScript 代码中调用 TypeScript 代码轻而易举。TypeScript 可以编译出纯净、 简洁的 JavaScript 代码,并能运行在任何支持 ES3 及以上的 JavaScript 引擎中。


2.强大的工具构建


类型允许 JavaScript 开发者在开发 JavaScript 应用程序时使用高效的开发工具和常用操作,比如静态检查和代码重构。类型是可选的,类型推断让一些类型的注释与你的代码的静态验证有很大的不同。类型让你能自主定义软件组件之间的接口和洞察现有 JavaScript 库的行为.


3.进阶的 JavaScript


TypeScript 提供最新的和不断发展的 JavaScript 特性,包括那些来自 ES2015 和未来提案中的特性,比如异步功能和装饰器,以帮助建立健壮的组件。

三、为什么要使用 TypeScript

1. 降低维护成本,提升健壮性、稳定性

1)代码即文档,好的接口、函数定义可直接代替文档,代码可读性更高。


2)静态类型检查,提早发现问题代码。

2. 提高开发效率

1)对代码重构和补全提示友好。


2)多人协作降低沟通成本,不再需要频繁阅读文档或细究实现细节。


3)类型可选,让你在不编写额外代码的情况下获得很多功能。


4)有很多先进的高级特性可以使用。

3. 成熟度高

1)编辑器或 IDE 集成度高。


2)社区庞大,周边工具丰富。


3)最受欢迎的编程语言排行榜中已跃升至第 10 名,话题度高。


4)多个团队全面使用 TypeScript 重构代码(Vue、React 、Angular),甚至连 Facebook 自家的产品(Jest、Yarn 等等)都在从 Flow 向 TypeScript 迁移。


4. 接入成本低

1)几乎没有接入成本,对当前工程改造小。


2)可以和 JavaScript 混合开发、编译成 JavaScript 在各端运行。


3)支持多种工具链。

5. 学习成本低

几乎没有学习成本,移动端各自开发的语言本身就有类型系统,并且 Swift、kotlin 也有可选类型,语法也和 TypeScript 类似。

四、如何使用 TypeScript 进行 Weex 开发

随着 Vue2.x 对 TypeScript 的支持,Weex 也能快速接入 TypeScript。同时 Vue3.0 将使用 TypeScript 重写,重写后的 Vue3.0 更能发挥 TypeScript 的特点。

1.接入 TypeScript

虽然市面上关于 Weex 支持 TypeScript 的资料比较少,但关于 Vue 如何接入 TypeScript 的文章铺天盖地,这里做个简单总结:


  • 添加 TypeScript 依赖,根据所需升级相关依赖或者有影响的包(当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能)。

  • ts-loader 可选,如果之前的项目工程对 Babel 依赖比较重,可以保留 babel-loader(Babel>=7)。Babel 已和 TypeScript 官方展开了合作,解决了部分之前不能被正常编译的问题。或者通过使用两个编译器,搭配 ts-loaderbabel-loader 来接入 TypeScript。

  • 添加 tsconfig.json ,并加入相关你需要的自定义配置。

  • 官方对 ESLint 做了支持,提供了解析 TypeScript 代码的编译器,可以把语法树转成 ESLint 所期望对 ESTree,使用 @typescript-eslint 即可。

  • 添加必要的声明文件,Weex 目前还没有官方的声明文件,大家可按需添加。

2.声明文件

Weex 官方目前没有对 TypeScript 提供优秀的支持,需要自行添加声明文件。


比如:


const platform = weex.config.env.platform
复制代码


在 TypeScript 中,编译器并不知道 Weex 是什么东西。这时我们需要对其声明


声明文件必需以 .d.ts 为后缀。一般来说,TypeScript 会解析项目中所有的 *.ts 文件,当然也包含以.d.ts结尾的文件。


例:weex.d.ts


declare interface IWeexGlobal {    config: {        platform: 'Android' | 'iOS' | 'Web'    }}declare const weex: IWeexGlobal
复制代码


Typescript 默认不能识别 .vue 文件,导致在引用时,会提示加载错误。所以需要自己新建一个 .d.ts 声明文件文件添加以下内容。这是为了告诉 Typescript 以 .vue 结尾的导入的任何东西都与 Vue 构造函数本身具有相同的形状。注意引用 vue 组件时需要补全 .vue


例:vue.d.ts


declare module '*.vue' {    import Vue from 'vue'    export default Vue}
复制代码


关于声明文件详细内容,具体可参考官方文档。

3.类组件

要让 TypeScript 正确推断 Vue 组件选项中的类型,需要使用类组件。在 Vue 2.x 中,通常使用基于 Vue Class Component 装饰器来用使用类组件。


Vue Class Component 对 Vue 组件进行了一层封装,让 Vue 组件语法在结合了 TypeScript 语法之后更加扁平化,代码可读性更高。


使用组类组件有以下差异:


  • @Component 修饰符注明了此类为一个 Vue 组件

  • 初始数据可以直接声明为实例的 property

  • 计算属性可以直接使用 getter / setter

  • 组件方法也可以直接声明为实例的方法

  • 所有 Vue 生命周期也可以直接声明为实例方法,但是你不能在实例本身上调用它们。声明自定义方法时,应避免使用这些保留名称

  • 其他接口描述对象可以传递给装饰器函数或者 Vue.extend



其他接口描述对象在类组件的使用:



TypeScript 的类组件和 JavaScript 的接口描述组件导出有些差异:


  • 类组件导出的是 Vue 类

  • 接口描述组件导出的是 ComponentOptions接口


所以在入口文件对 Vue 进行初始化上也会有些区别:


4.装饰器

TypeScript 支持装饰器这一特性,Javascript 里的装饰器目前处在建议征集的第二阶段。若要使用装饰器特性,需要在 tsconfig.json 里启用 experimentalDecorators 编译器选项。装饰器的好处如下:


1)使语法更加扁平化。


2)对业务代码无侵入。


3)解耦业务逻辑、辅助功能逻辑。


除了上节提到的 @ComponentVue Property DecoratorVuex Class 提供了更多的装饰器用于使用。装饰器可以用于修饰类、方法和属性等。

Vue Property Decorator

  • @Prop

  • @PropSync

  • @Model

  • @Watch

  • @Provide

  • @Inject

  • @ProvideReactive

  • @InjectReactive

  • @Emit

  • @Ref

  • @Component (由 vue-class-component 提供)


对常用对 @Prop@Watch 举个例:



关于其他装饰器如何使用,具体参考官方文档。

Vuex Class

  • @State

  • @Getter

  • @Action

  • @Mutation


关于如何使用,具体参考官方文档。

开发工具

1) Visual Studio CodeWeb Storm 都能做到开箱即用,不需要装配额外的插件。


2)对 ZWeex ToolKit 扩展能力,目前已经支持了创建 TypeScript 的页面

五、落地 TypeScript 提升系统稳定性

我们来对之前遇到的问题做个拆解,看看 TypeScript 是如何帮我们解决痛点。

1.减少 Bug

1)类型错误

TypeScript 的类型保护、联合类型、类型推导等特性,可以避免发生低级类型错误问题。比如在开发中约定函数的参数是 number 数字类型,如果使用时不慎使用了 string 类型的参数,那么 IDE 会有 error 警告并会在编译时报错。



2)空指针

TypeScript 会进行严格非空检查可以帮助我们避免空指针问题。


比如函数的参数定义是允许出现空指针的情况,那么在使用这些不安全的参数时,IDE 和编译器都会提醒你这块儿地方注意了,如果没有处理边界会给予提示。




添加了判断空指针进行处理异常边界之后,可以通过编译。


3)原生 module 类型约束

有赞零售使用有近 20 个原生 module,在之前开发过程中因为没有类型约束出现过不少写错 module/方法/参数名、使用错参数类型的情况。使用 TypeScript 的类型声明可以解决这些问题。


举个例子,有以下几个原生 module,我们对其类型声明


declare interface IWeexNativeModules {    foo: {        fun(a: number, b?: string): void    }
foo1: { oops(): void }
foo2: { oops(): void }}
复制代码


使用时,IDE 会有代码补全提示。如果写错 IDE 和编译器同样报错提示。



调用方法和参数时也会有类型约束。



通过使用 TypeScript 有效的避免了类型问题,减少 Bug 量。一篇伦敦大学和微软研究院联合署名的论文中提到:


通过对 Github 上开源项目的公开 Bug 统计发现:15% 的 Bug 都可以通过 TypeScript 来规避。

2.增强架构设计

TypeScript 比 JavaScript 多了接口、抽象类、范型、访问权限等,可以方便的落地架构设计。


面向接口(协议)编程在移动端应用是非常广泛的,使用 TypeScript 之后也可以进行一些架构设计。


之前我们在使用 Weex 进行开发时,往往会把所有逻辑代码往组件内部塞,使得组件后续维护起来非常麻烦。我们引入了和原生一样的规范:增加 Model、Service 层,通过工具自动生成相应目录结构,在开发中得到了非常好的约束。


效果

我们在 Q2 完成了 TypeScript 的迁移,开发效率显著提升、系统稳定性明显提高。


在对供应链单据页模版化的项目中,使用 TypeScript 进行了大范围的重构。我们发现联调期间的沟通显著减少,不需要频繁查阅接口文档,代码可读性更高了,节省了很多 debug 成本。在测试环节仅出现 个位数 的 Bug,发布线上之后也没问题发生。

六、平滑迁移 TypeScript

迁移工程不需要一蹴而就,你可以先用 JSDoc 注释现有的 JavaScript,然后迁移几个文件交由 TypeScript 检查,随着时间的推移,当你的代码库准备好了之后,代码库迁移到 TypeScript 自然就水到渠成了。

参考链接


本文转载自公众号有赞 coder(ID:youzan_coder)。


原文链接


https://mp.weixin.qq.com/s?__biz=MzAxOTY5MDMxNA==&mid=2455761139&idx=1&sn=a4cde112969fb5d3737ca4032bf12a53&chksm=8c6876d6bb1fffc05cb047840c618cb30e105442bd35bd06a765a045dc9698cc9a0f769e943c&scene=27#wechat_redirect


2020-08-02 14:042189

评论 2 条评论

发布
用户头像
巨大反馈
2020-08-02 16:45
回复
坚实的时刻
2020-08-02 16:45
回复
没有更多了
发现更多内容

关爱2700多万听障者,手语服务助力无声交流

HMS Core

手语

Http轮询分为长查询和短查询总结

知识浅谈

HTTP 9月月更

openEuler资源利用率提升之道 03:rubik混部引擎简介

openEuler

Linux 开源 cpu 操作系统 openEuler

架构实战营-模块一作业

Geek_92ba6f

算法基础(四)| 前缀和算法及模板详解

timerring

算法 9月月更

leetcode 669. Trim a Binary Search Tree 修剪二叉搜索树 (简单)

okokabcd

LeetCode 算法与数据结构

开发者有话说|如何写出更加优雅的代码

海风极客

个人成长

面向深度神经网络的特定领域架构

俞凡

深度学习 架构 TPU

每日算法刷题Day1-隐式转换与精度丢失

timerring

算法题 9月月更

深入了解之链接器与加载器

邱学喆

加载器 链接器 ELF文件结构

SpringBoot初识

十八岁讨厌编程

Java 后端开发 9月月更

[SpringBoot]配置文件格式、yaml配置及读取

十八岁讨厌编程

Java 9月月更

死锁检测实现

C++后台开发

后台开发 线程 多线程 死锁 C++开发

探索AI技术应用场景

felix

产业落地 AI探索 API接口 模型管理

【jvm】通过JDBC为例谈谈双亲委派模型的破坏

石臻臻的杂货铺

JVM 9月月更

Serverless遇到 FinOps: Economical Serverless

华为云开发者联盟

云原生 后端 企业号九月金秋榜

开发者有话说|一名普通大专学历开发者的成长

彭发红

NestOS应用案例:容器化部署OpenStack

openEuler

架构 openEuler 开源操作系统 OpenStack

闲着刷题

吉师职业混子

9月月更

跟着卷卷龙一起学Camera--内存池浅析01

卷卷龙

ISP 9月月更

清览题库--C语言程序设计第五版编程题解析(2)

吉师职业混子

9月月更

关于 Angular 应用 tsconfig.json 中的 lib 属性

Jerry Wang

typescript 前端开发 angular web开发 9月月更

Code For Better 谷歌开发者之声——Google Cloud谷歌云

Fire_Shield

云原生 Google Cloud 9月月更

[SpringBoot]多环境配置,配置文件分类

十八岁讨厌编程

Java 后端开发 9月月更

物联网实践分享

彭发红

如何在笔记本上安装openEuler 22.03 LTS

openEuler

开源 操作系统 openEuler 安装部署

跟我学Python图像处理丨带你掌握傅里叶变换原理及实现

华为云开发者联盟

Python 人工智能 企业号九月金秋榜

融云员工服务台,跟“干不完”说再见

融云 RongCloud

IT职场

流程图布局在项目中的实践

相续心

工赋开发者社区 |【数智化】数字化工厂规划与建设方案

工赋开发者社区

基于微服务的应用性能监控方案

穿过生命散发芬芳

9月月更 微服务监控

基于 TypeScript 的 Weex 优化实践_开源_周佳敏_InfoQ精选文章