草庐IT

携程小程序生态之Taro跨端解决方案

携程前端框架 2023-03-28 原文
​作者|携程前端框架团队,为携程集团各业务线提供优秀的Web解决方案,当前主要专注:新一代研发模式探索,Rust构建工具链路升级、Serverless应用框架开发、在线文档系统开发、低代码平台搭建、适老化与无障碍探索等。

一、摘要

随着携程接入小程序平台类型的增加,前端需要负责的端越来越多,研发成本也随之成倍增加。为了解决一套代码多端运行的诉求,携程小程序框架不断调整、升级,逐渐形成了携程Taro跨端解决方案。

二、背景

2.1 小程序现状

近几年业界推出了各种小程序平台,每个小程序平台都会提供一个专属的原生小程序DSL, 这些DSL之间或多或少存在一些差异,这意味着使用某一类型小程序DSL编写的代码,无法直接复用到其他小程序平台上,造成开发和维护成本成倍增加。

2.2 业务现状

目前携程支持的小程序业务涉及多个小程序平台,如果全部只使用平台自身的DSL开发,开发人员至少需要同时开发及维护5个活跃版本,开发任务繁重,代码维护困难。此外,每新增一类小程序入口,开发人员必须将原有业务逻辑重写一遍,不仅工作内容重复,而且严重影响业务落地速度。为此,一套代码多端运行的诉求迫在眉睫。

值得注意的是,携程已经接入了多个平台的小程序,使用多端统一开发框架从零开始开发小程序代码既浪费研发资源又不现实。我们需要考虑如何在携程当前已有的小程序代码的基础上使用跨端框架开发新业务、逐步切换原有代码,实现多端统一开发方案的平滑接入。

2.3 解决方案

为了解决上述问题,我们研发了携程Taro跨端解决方案,开发者只需使用Taro框架书写一套代码,便可获得在多个平台皆运行良好的小程序项目。此外,该方案还提供了仓库管理、辅助脚手架、编译功能扩展及过程优化等功能。

三、Taro跨端解决方案设计

3.1 技术选型

为了在保留原有代码的前提下实现一套代码多端运行,我们对市面上的跨端开发框架进行了调研,最终决定使用Taro 3 作为携程小程序的跨端框架。主要是考虑到Taro 3具有以下4项优点:

  • 框架稳定性高
  • 支持的平台种类多
  • 支持使用React 语法规范进行开发
  • 支持Taro和原生混合开发

3.2 整体架构设计

携程小程序随着业务的发展、多平台化趋势和跨端技术的不断演进,逐渐形成了一套多平台复用的Taro跨端解决方案。

图1 项目工程架构图

携程小程序的项目工程架构图如图1所示。上半部分是跨端复用层,这一层的项目代码是基于Taro框架进行开发的,多个Taro模块可以灵活组合成一个完整的Taro项目;从下半张图可以看出,Taro项目是完整小程序项目的其中一个模块,Taro项目的运行需要依赖小程序原生壳工程。整个Taro项目是依据插件化的设计思想组织代码的,由多个独立的Taro模块和一个Taro基础壳工程构成。

3.3 Taro模块的插件化设计

首先,携程小程序是由多个团队协同开发的项目,跨团队协作开发时常常会出现代码冲突、文件覆盖等问题。因此,需要思考如何通过合理的项目架构从根本上解决这些问题,保证多团队并行开发的效率。考虑到可以采用模块化的概念,根据业务线类型将项目代码拆解成多个子模块,并约定文件放置以及引用规则,从而确保各个子模块的源码文件能够完全隔离。

然而,使用模块化开发方案,得到的Taro项目几乎不具有扩展性,Taro模块也无法快速便捷的被复用。怎样才能提高Taro模块的灵活性,使得任取一个或多个Taro模块进行组合都能得到一个完整的Taro项目,且合并到小程序原生壳工程中能够正常运行?为解决以上问题,我们进一步将插件化的设计思想应用在Taro跨端解决方案上,提供了定制化的Taro基础壳工程以及一套开发规范。

开发者需使用Taro基础壳工程作为开发模版,并遵循规范进行业务开发,所有Taro模块在本地开发或发布时按照统一的标准进行编译、融合,从而达到在不破坏原有项目结构的前提下灵活组合使用的目标。下面我们将从项目构成与开发规范、仓库管理、开发架构,运行方案等方面详细讲解Taro跨端解决方案。

3.4 项目结构与开发规范

Taro基础壳工程是由Taro官方的模版项目拓展而来,内部增加了定制化的编译配置、Plugins和基础组件类。如图2所示,Taro基础壳工程内仅包含与公共基础功能相关的文件,这些文件可抽象成3类内容:编译配置文件、用于扩展编译过程的Plugins,以及页面基类。

图2 Taro基础壳工程结构示意图

开发Taro模块时,开发者需要关注3块内容(扩展配置、项目文件、页面文件,参见图2),并遵守以下几项规范进行开发:

1)主包的大小直接影响着小程序启动性能,为此我们提出“非必要不打入主包”原则:除小程序启动时需要用到的文件、tabBar页面及公共基础文件外,其他文件应全部拆入分包中。Taro模块也须遵循该原则,开发者应将业务代码全部放置在自己的分包目录下,项目文件app.config.js中只增加分包页面配置。

2)为了避免合并项目时出现业务线之间文件相互覆盖或页面路径冲突,统一约定分包页面路径的前缀为“pages/业务线英文缩写”,结合“非必要不打入主包”原则使用,可以有效隔离各业务线的源码文件。

3)为确保Taro模块的业务相关内容(包括依赖包)完全放置在分包路径下,不占用主包的大小,我们提供了commonModule方案:在引用第三方依赖包前,需要开发者本地进行预编译操作,将需要引用的内容打包成放置在分包中的一个或多个commonModule文件,随后从预编译产物(commonModule)中引用所需的模块。除此之外,还可以通过commonOrigin方案获取依赖包的源码,此时会将所需依赖包的原样复制到开发者指定的文件夹目录下。

3.5 仓库管理

首先,Taro项目采用分仓开发的模式,将每个业务线的Taro模块存放在一个单独的git仓库中。将Taro模块分别存放在不同的仓库,可以保持各个业务仓库提交代码操作的独立。

其次,我们借助gitsubmodule 工具将各个Taro模块所在的仓库以及Taro基础壳工程仓库作为子目录包含到整个Taro项目的发布仓库中,为发布仓库和多业务仓建立起父子仓库的关联。建立仓库间的关联后,Taro项目可以借助git submodule 的获取子模块功能快速克隆自己所需的Taro模块源码,并且可以随时拉取各个业务仓库的最新代码。

再次,由于gitsubmodule允许一个仓库作为多个仓库的子目录,这意味着可以选取不同的Taro模块,将他们的仓库组合成新的发布仓库,结合携程小程序管理平台中各个小程序所需Taro模块的配置一起使用,可实现根据配置动态引入Taro模块的效果。

随后,通过对多个Taro模块进行组合,可以快速获得各种包含多个业务线的Taro项目,从而提高Taro模块在不同场景中的复用。

图3 仓库管理及模块复用

然后,将Taro项目作为完整小程序的一个bundle,将Taro项目的编译产物与小程序原生壳项目进行合并,即可获取到Taro混合开发的完整小程序代码。

如图3所示,通过组合Taro模块可以获取到包含不同功能的Taro项目,接着将Taro项目与不同类型的小程序原生壳项目结合,便可以轻松获取多个Taro混合开发的小程序项目。

3.6 开发及运行架构

开发者只需安装miniTools脚手架并执行初始化命令行,即可快速获取Taro模块的开发模版和小程序原生壳工程,完成项目初始化。开发Taro模块时,开发者需要遵循开发规范,在分包目录下添加文件并编写业务代码。编写过程中,只需执行编译指令,便可将本地开发的源码编译并融合到小程序原生壳工程中,得到包含Taro模块内容的完整小程序代码了。

图4 本地开发过程

结合上述本地开发过程,Taro跨端解决方案具体提供的功能以及优化工作说明如下:

1)Taro模块直接引用小程序原生壳项目内的模块。提供@/miniapp标识符,用于指代小程序完整项目根目录。同时,编译过程中会识别代码中的标识符,动态计算并修改引用路径。开发Taro模块时只需使用@/miniapp拼接文件的相对路径,便可以直接引用小程序完整项目根目录内的文件。

2)扩展页面配置项,提供设置自定义组件嵌套层级的功能。开发者可以在页面配置文件中增加自定义组件的嵌套层级配置,编译时将检索页面配置文件的内容,汇总并设置Taro项目用到的自定义组件的嵌套层级。

3)根据分包路径,动态生成splitChunks。为了防止公共文件被打到主包中(占用主包的大小),编译时会读取Taro模块配置的分包路径,动态生成splitChunks。该方案可以将分包用到的公共文件单独抽离到分包中,随后为分包中的所有页面添加对分包公共文件的引用即可。

4)提供扩展配置文件,允许自行添加alias和externals 配置,便于开发者自定义目录别名以及不需要打包的依赖。

5)提供模块分析功能,开发者可以更加便捷地查看每个chunk内包含哪些文件

6)使用混合模式进行打包,随后自动将编译产物移动到小程序原生壳工程中,同时将分包配置添加到小程序项目配置内。这一步是为了将Taro项目编译产物与携程原有的小程序代码合并成一个完整的Taro混合小程序项目。在开发规范的作用下,Taro模块的分包路径是根据各业务线隔离的,每个Taro模块的文件都严格放置在自己的分包路径内,因此只需将公共基础文件放置到项目根目录,分包内容迁移至各自的分包目录下,便可顺利完成代码合并。

3.7 项目发布

我们利用webhooks 实现Taro项目的流水线式迭代开发,当Taro模块提交修改时,会触发Taro项目发布仓库的pipeline。Taro项目发布仓库pipeline的主要工作流程如下:

首先,Taro项目会拉取所有子仓库的最新代码。接着,将从小程序管理平台获取当前Taro项目使用的Taro模块列表及相应的发布版本号,并据此按需将各个Taro模块的发布代码拉取到docker中。至此,Taro项目所需发布的所有源码已经获取完毕。

图5 自动化CI/CD

接下来,将进行Taro项目的合并工作:将各个Taro模块的代码切换至指定版本,获取各个Taro模块中配置的分包路径,并将相关配置文件和分包目录下业务代码合并到Taro壳工程中。

Taro项目合并完成后,便会编译成指定小程序类型的代码。值得一提的是,Taro基础壳工程既是Taro项目壳又是开发模版,它提供了统一的Taro项目结构和编译方式,也是Taro模块能灵活组合的原因所在。

最后,将Taro项目的编译产物与相应类型的小程序原生代码进行合并,即可获得完整的Taro小程序项目。将项目代码上传到小程序后台,则标志着一整套项目发布流程的顺利完成。

四、总结

目前,Taro跨端解决方案已支持一套代码运行在5类小程序(微信、支付宝、字节跳动、百度、快手)平台。使用此方案进行开发的Taro小程序项目灵活度和复用性很高,可以按需选用Taro模块组合成一个完整的Taro项目。

此外,我们还提供了配套的脚手架工具、仓库管理、版本管理以及pipeline自动化方案,极大提升了小程序的开发、测试和发布效率。今后我们将继续完善小程序生态系统,为解决业务痛点不断孵化出更多的解决方案。

有关携程小程序生态之Taro跨端解决方案的更多相关文章

  1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  2. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  3. ruby - 在 Ruby 中编写命令行实用程序 - 2

    我想用ruby​​编写一个小的命令行实用程序并将其作为gem分发。我知道安装后,Guard、Sass和Thor等某些gem可以从命令行自行运行。为了让gem像二进制文件一样可用,我需要在我的gemspec中指定什么。 最佳答案 Gem::Specification.newdo|s|...s.executable='name_of_executable'...endhttp://docs.rubygems.org/read/chapter/20 关于ruby-在Ruby中编写命令行实用程序

  4. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  5. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  6. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  7. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

  8. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  9. ruby - 检查是否通过 require 执行或导入了 Ruby 程序 - 2

    如何检查Ruby文件是否是通过“require”或“load”导入的,而不是简单地从命令行执行的?例如:foo.rb的内容:puts"Hello"bar.rb的内容require'foo'输出:$./foo.rbHello$./bar.rbHello基本上,我想调用bar.rb以不执行puts调用。 最佳答案 将foo.rb改为:if__FILE__==$0puts"Hello"end检查__FILE__-当前ruby​​文件的名称-与$0-正在运行的脚本的名称。 关于ruby-检查是否

  10. ruby-on-rails - 如何在 Gem 中获取 Rails 应用程序的根目录 - 2

    是否可以在应用程序中包含的gem代码中知道应用程序的Rails文件系统根目录?这是gem来源的示例:moduleMyGemdefself.included(base)putsRails.root#returnnilendendActionController::Base.send:include,MyGem谢谢,抱歉我的英语不好 最佳答案 我发现解决类似问题的解决方案是使用railtie初始化程序包含我的模块。所以,在你的/lib/mygem/railtie.rbmoduleMyGemclassRailtie使用此代码,您的模块将在

随机推荐