微信购物入口「京喜」首页跨端开发与优化实践

2019-12-04 admin

Taro 是一套遵循 React 语法规范的多端开发解决方案。

现如今市面上端的形态多种多样,Web、React-Native、微信小程序等各种端大行其道,当业务要求同时在不同的端都要求有所表现的时候,针对不同的端去编写多套代码的成本显然非常高,这时候只编写一套代码就能够适配到多端的能力就显得极为需要。

使用 Taro,我们可以只书写一套代码,再通过 Taro 的编译工具,将源代码分别编译出可以在不同端(微信/百度/支付宝/字节跳动/QQ 小程序、快应用、H5、React-Native 等)运行的代码。

选它有两个原因,一来是 Taro 已经成熟,内部和外部都有大量实践,内部有京东 7FRESH、京东到家等,外部有淘票票、猫眼试用等多个案例,可以放心投入到业务开发;二来团队成员都拥有使用 Taro 来开发内部组件库的经验,对业务快速完成有保障。

组件库

开发实录

由于首页改版的开发排期并不充裕,因此充分地复用已有基础能力(比如像请求、上报、跳转等必不可少的公共类库),能大量减少我们重复的工作量。话虽如此,但在三端统一开发过程中,我们仍遇到不少问题同时也带来解决方案,以下我们一一阐述。

H5 篇

我们所有的页面都依赖现有业务的全局公共头尾及搜索栏等组件,这就不可避免的需要将 Taro 开发流程融入到现有开发和发布流程中去。同时公共组件都是通过 SSI 的方式引入和维护的,为了能在运行 npm run dev:h5 时预览到完整的页面效果,需要对 index.html 模版中的 SSI 语法进行解析,index.html 模版文件代码结构大致如下:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
  <title>京喜</title>
  <!--#include virtual="/sinclude/common/head_inc.shtml"-->
</head>
<body>
  <div id="m_common_header" style="display:none;"></div>
  <!--S 搜索框-->
  <div id="search_block" class="search_block"></div>
  <div id="smartboxBlock" style="display:none;"></div>
  <!--E 搜索框-->
  <div id="app" class="wx_wrap"></div>
  <!--#include virtual="/sinclude/common/foot.shtml"-->
</body>
</html>

可以看到模版中存在很多类似 <!--#include virtual="..." --> 格式的代码,这些就是通过 SSI 方式引入的 H5 公共组件,它的 virtual 属性指向的文件不存在于本地而是存在于服务器上的,所以我们遇到的第一个问题就是在本地解析这些文件,确保能预览到完整的页面效果,不然开发调试起来就非常的低效。好在 Taro 有暴露出 webpack 的配置,我们可以通过引入自定义加载器(这里就叫 ssi-loader)来解析这些代码的路径,然后请求服务器上的文件内容并进行替换即可,要实现这个功能只需在项目的 config/dev.js 中加入如下代码即可:

module.exports = {
  h5: {
    webpackChain(chain, webpack) {
      chain.merge({
        module: {
          rule: {
            ssiLoader: {
              test: /\.html/,
              use: [
                {
                  loader: 'html-loader'
                },
                {
                  loader: 'ssi-loader',
                  options: {
                    locations: {
                      include: 'https://wqs.jd.com'
                    }
                  }
                }
              ]
            }
          }
        }
      })
    }
  }
}

这样就解决了本地开发调试难点,然后开开心心的进行页面开发。

当页面开发完成之后,接下来遇到的问题就是如何将前端资源部署到测试和生产环境。由于现有开发和发布流程都是基于内部已有的平台,我们临时定制一套也不太现实,所以需要将它融入到 Taro 的流程中去,这里我们引入了 gulp 来整合各种构建和发布等操作,只要构建出符合发布平台规范的目录即可利用它的静态资源构建、版本控制及服务器发布等能力,这样我们就打通了整个开发和发布流程。

这套拼凑起来的流程还存在不少的问题,对于新接手的同学有一点小繁琐,有着不少改善的空间,这也是接下来的重点工作方向。另外 Taro 的 H5 端之前是基于 SPA 模式,对于有着多页开发需求的项目来说不太友好,当时反馈给 Taro 团队负责 H5 的同学,很快得到了响应,目前 Taro 已支持 H5 多页开发模式,支持非常迅速。

小程序篇

由于开发完 H5 版之后,对应的业务逻辑就已经处理完了,接下来只需要处理小程序下的一些特殊逻辑(比如分享、前端测速上报等)即可,差异比较大的就是开发和发布流程。

这里讲一下如何在一个原生小程序项目中使用 Taro 进行开发,因为我们的 Taro 项目跟已有的原生小程序项目是独立的两个项目,所以需要将 Taro 项目的小程序代码编译到已有的原生小程序项目目录下,第一步要做的就是调整 Taro 配置 config/index.js,指定编译输出目录以及禁用 app 文件输出防止覆盖已有文件。

const config = {
  // 自定义输出根目录
  outputRoot: process.argv[3] === 'weapp' ? '../.temp' : 'dist',
  // 不输出 app.js 和 app.json 文件
  weapp: {
    appOutput: false
  }
}

由于京喜以前是主购小程序的一个栏目,后面独立成了独立的小程序,但是核心购物流程还是复用的主购小程序,所以这让情况变得更加复杂。这里还是通过 gulp 来进行繁琐的目录文件处理,比如我们的小程序页面和组件都需要继承主购小程序的 JDPageJDComponent 基类,所以在进行文件复制之前需要进行代码替换,代码如下:

// WEAPP
const basePath = `../.temp`
const destPaths = [`${basePath}/pages/index/`, `${basePath}/pages/components/`]
const destFiles = destPaths.map(item => `${item}**/*.js`)

/*
 * 基类替换
 */
function replaceBaseComponent (files) {
  return (
    gulp
      .src(files || destFiles, { base: basePath })
      .pipe(
        replace(
          /\b(Page|Component)(\(require\(['"](.*? "'"")\/npm\/)(.*)(createComponent.*)/,
          function(match, p1, p2, p3, p4, p5) {
            const type =
              (p5 || '').indexOf('true') != -1 ||
              (p5 || '').indexOf('!0') != -1
                ? 'Page'
                : 'Component'
            if (type == 'Page') p5 = p5.replace('))', '), true)') // 新:page.js基类要多传一个参数
            const reservedParts = p2 + p4 + p5
            // const type = p1
            // const reservedParts = p2
            const rootPath = p3

            const clsName = type == 'Page' ? 'JDPage' : 'JDComponent'
            const baseFile = type == 'Page' ? 'page.taro.js' : 'component.js'

            console.log(
              `🌝 Replace with \`${clsName}\` successfully: ${this.file.path.replace(
                /.*?wxapp\//,
                'wxapp/'
              )}`
            )
            return `new (require("${rootPath}/bases/${baseFile}").${clsName})${reservedParts}`
          }
        )
      )
      .pipe(gulp.dest(basePath))
  )
}

// 基类替换
gulp.task('replace-base-component', () => replaceBaseComponent())

还有很多类似这样的骚操作,虽然比较麻烦,但是只需要处理一次,后续也很少改动。

RN 篇

对于 RN 开发,也是第一次将它落地到实际的业务项目中,所以大部分时候都是伴随着各种未知的坑不断前行,所以这里也友情提示一下,对于从未使用过的技术,还是需要一些耐心的,遇到问题勤查勤问。

由于京喜 APP 是复用京东技术中台的基础框架和 JDReact 引擎,所以整个的开发和部署都是遵循 JDReact 已有的流程,画了一张大致的流程图如下:

京喜开发发布流程

JDReact 平台是在 Facebook ReactNative 开源框架基础上,进行了深度二次开发和功能扩展。不仅打通了 Android/iOS/Web 三端平台,而且对京东移动端基础业务能力进行了 SDK 级别的封装,提供了统一、易于开发的 API。业务开发者可以通过 JDReact SDK 平台进行快速京东业务开发,并且不依赖发版就能无缝集成到客户端(android/iOS)或者转换成 Web 页面进行线上部署,真正实现了一次开发,快速部署三端。

由于京喜 APP 的 JDReact 模块都是独立的 git 仓库,所以需要调整我们 Taro 项目配置 config/index.js 的编译输出路径如下:

rn: {
  outPath: '../jdreact-jsbundle-jdreactpingouindex'
}

这样,当我们运行 yarn run dev:rn 进行本地开发时,文件自动编译到了 JDReact 项目,接下来我们就可以用模拟器或者真机来进行预览调试了。当我们在进行本地开发调试的时候,最高效的方式还是推荐用 Taro 官方提供的 taro-native-shell 原生 React Native 壳子来启动我们的项目,详细的配置参照该项目的 README 进行配置即可。

由于 React Native 官方提供的 Remote Debugger 功能非常弱,推荐使用 React Native Debugger 来进行本地 RN 调试,提供了更为丰富的功能,基本接近 H5 和小程序的调试体验。

React Native Debugger 界面

这样我们就拥有了一个正常的开发调试环境,接下来就可以进行高效的开发了,由于我们前面在 H5 和小程序版本阶段已经完成了绝大部分的业务逻辑开发,所以针对 RN 版本的主要工作集中在 iOS 和安卓不同机型的样式和交互适配上。

在样式适配这块,不得不提下 Taro 针对我们常见的场景提供了一些最佳实践,可以作为布局参考:

  • 固定尺寸(按钮、文字大小、间距):写 PX / Px / pX
  • 保持宽高比(比如 banner 图片):Image 组件处理
  • 间距固定,内容自适应(比如产品卡片宽度):使用 flex 布局
  • 按屏幕等比缩放:使用 px 单位,编译时处理(scalePx2dp 动态计算)

Taro RN 最佳实践集锦

在实际开发过程中也遇到不少兼容性问题,这里整理出来以供大家参考:

  • 文本要用 <Text> 标签包起来,因为 RN 没有 textNode 的概念;

  • 使用 Swiper 时在外面包一个 View,否则设置 margin 后会导致安卓下高度异常;

  • Cannot read property 'x' of undefined,Swiper 底层使用的 react-native-swiper 导致的问题,Disable Remote JS Debug 就不会出现。

  • 图片默认尺寸不对,RN 不会自动帮助设置图片尺寸,而是交给开发者自己处理,故意这样设计的;

  • Image 组件上不可以设置 onClick

  • 实现基线对齐:vertical-align: baseline,用 <Text> 把需要基线对齐的组件包住即可。

    <Text>
      <Text style={{ fontSize: 20 }}>abc</Text>
      <Text style={{ fontSize: 40 }}>123</Text>
    </Text>
    
  • 尽量避免使用 line-height ,在安卓和 iOS 下表现不一致,而且即使设置为与 fontSize 相同也会导致裁剪;

  • android 调试生产环境的 bundle,摇手机,选 Dev Setting,取消勾选第一项 Dev 即可;

  • iOS 调试生产环境的 bundle,AppDelegate.m 中增加一行语句关闭 dev 即可:

      [[RCTBundleURLProvider sharedSettings] setEnableDev:false];
      // 找到这行,并在它的上面增加上面这行
      jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
    
  • <Text><View> 支持的 style 属性不相同。

    > [Text Style Props](https://facebook.github.io/react-native/docs/text-style-props "Text Style Props") & [View Style Props](https://facebook.github.io/
    
    

    react-native/docs/view-style-props)

  • render 方法中不要返回空字符串

    下面的代码在 android 下会报错(empty_string 内容为空字符串)

    <View>
      {empty_string && <Text></Text>}
    </View>
    

    因为 `empty_string && <Text>

[转载]原文链接:https://segmentfault.com/a/1190000021189368

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-80403.html

文章标题:微信购物入口「京喜」首页跨端开发与优化实践

相关文章
HTML5游戏2015年的开发趋势
在互联网行业中,一个行业从零到成熟,开发者生态也是对应的,我们今年看到很多大公司,包括像微软和Google,也参与到了HTML5 开发者生态的建设当中。关于HTML5移动游戏的开发和盈利生态的走向又该去往何处?下面我们来试着讨论一下。 《围...
2015-11-12
Html5 是否适合移动应用开发
HTML5最近这几年声誉鹊起,而基于HTML5技术的产品也风生水起。感觉现在你的产品要是不和HTML5沾点边,都不好意思和客户打招呼!移动应用开发中,HTML5更是不可或缺的角色,市面上不少移动应用中间件产品都号称支持HTML5,例如APP...
2015-11-12
2015 Web 2.0和AJAX如何做好优化
2015如何让做好web2.0和ajax的优化?JavaScript中文网总结当下提出以下四大优化意见,旨在帮助W前端开发人员有效利用APM解决上述问题。 随着Web应用程序速度与效率快速增长,网站已经成为企业与其客户进行交互的第一途径——...
2015-11-12
node.js调用C++开发的模块实例
如何用C++和node交互,在node的程序中,如果有大数据量的计算,处理起来比较慢,可以用C++来处理,然后通过回调(callback的形式),返回给node。先回顾一下正统的用 C++ 开发 native 模块的方法 #include ...
2017-03-25
javascript教程:关于if简写语句优化的方法
UglifyJS是一个对javascript进行压缩和美化的工具,在它的文档说明中,我看到了几种关于if语句优化的方法。尽管我还没使用它去做一些尝试性的测试,但从这里可以看到它的确对js作了美化的工作。也许有人认为if语句就那么简单,能优化...
2015-11-12
微信公众号实现无限制推送模板消息!可向指定openID群发
微信认证的服务号才有推送模板消息接口 所以本文需要在认证服务号的情况下学习 以上就是模板消息,只有文字和跳转链接,没有封面图。 在服务号的后台添加功能插件-模板消息即可。 模板消息,都是在后台选择一个群发模板的,然后获取模板ID,根据这...
2018-01-14
关于Ajax应用开发需要注意的事项
接触Ajax,那时候的Ajax支持还不是很好,都要涉及底层,没有现成的框架给你调用。现在把常见的问题列举如下。 [b]1、编码问题[/b] 注意AJAX要取的文件是UTF-8编码的。GB2312编码传回BROWSE后中文会乱码。如果用VBS...
2015-11-11
移动端网页设计经验与心得
智能手机发展确实很迅速,像今年,我的大部分工作就都在移动端网页上。 再往前些年,看到的手机版/移动版网页,限制于浏览器与手机性能,2g网络速度等 网页设计无非是蓝、黑、白,界面单调,并且要尽可能的设计简单。 现在情况就大不相同了,软件上we...
2015-12-23
VSCode配置react开发环境的步骤
vscode 默认配置对于 react 的 JSX 语法不友好,体现在使用自动格式化或者粘贴后默认缩进错误,尽管可以通过改变 language mode 缓解错误,但更改 language mode 后的格式化依然不够理想。 通过搭配使用 ...
2017-12-28
HTML5移动应用开发的12大特性
1.离线缓存为HTML5开发移动应用提供了基础 HTML5 Web Storage API可以看做是加强版的cookie,不受数据大小限制,有更好的弹性以及架构,可以将数据写入到本机的ROM中,还可以在关闭浏览器后再次打开时恢复数据,以减少...
2015-11-11
回到顶部