首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >实践总结:基于Kbone使用React同构开发小程序

实践总结:基于Kbone使用React同构开发小程序

作者头像
极乐君
发布2020-09-24 10:21:43
1.1K0
发布2020-09-24 10:21:43
举报
文章被收录于专栏:极乐技术社区极乐技术社区

据官方介绍,Kbone 是一个致力于微信小程序和Web端同构的解决方案。具体来说,因为微信小程序的底层模型和 Web 端不同,所以如果我们想直接把 Web 端的代码挪到小程序环境内执行是不可能的。

Kbone 的诞生就是为了解决这个问题,它实现了一个适配器,在适配层里模拟出了浏览器环境,让Web端的代码可以不做什么改动便可运行在小程序里。

因为 kbone 是通过提供适配器的方式来实现同构,所以微信表示其优势有以下几点:

  • 大部分流行的前端框架都能够在Kbone上运行,比如Vue、React、Preact 等。
  • 支持更为完整的前端框架特性,因为 Kbone 不会对框架底层进行删改(比如 Vue 中的 v-html 指令、Vue-router 插件)。
  • 提供了常用的 dom/bom 接口,让用户代码无需做太大改动便可从 Web 端迁移到小程序端。
  • 在小程序端运行时,仍然可以使用小程序本身的特性(比如像 live-player 内置组件、分包功能)。
  • 提供了一些 Dom 扩展接口,让一些无法完美兼容到小程序端的接口也有替代使用方案(比如 getComputedStyle 接口)。

官方宣传的优点——提供了常用的 DOM/BOM 接口,让用户代码无需做太大改动便可从 Web 端迁移到小程序端。下面是我这几次尝试总结下来的几个要点与问题。

1

配置

这个按照官方文档配置,问题不大。需要注意以下几个问题:

  • 如果在小程序中不想把全部内容都在一个页面的渲染的话,webpack 需要配置多入口;
  • eval 相关的 devtool 不能用,例如 cheap-module-eval-source-map;
  • css 样式必须抽离出 css 文件。

axios 在微信小程序中使用

使用对应的 adapt,问题不大。使用以下代码解决:

DOM/BOM 接口的兼容性问题

官方提供了 DOM/BOM 的拓展接口,问题不大。此次遇到了以下两个问题:

  • 兼容性。例如 Event 对象以浏览器提供接口并不完全一致,使用以下代码兼容(只是举例说明,并未做完全的兼容测试):
  • 某些接口需要自己实现,例如:

样式

迁移应用到小程序,最大的问题应该就是样式。这个也是由于微信小程序自身的限制。除非小程序本身支持,否则框架也是无能为力的。主要有以下几个问题:

  • 不支持「属性选择器」以及其他微信小程序不支持的选择器;
  • 小程序端某些组件的样式问题,例如,input 组件在渲染成 view + 自定义组件,样式需做特殊处理;
  • 部分 css-in-js 框架不支持抽离 css 文件,无法在小程序上使用。

页面鉴权

由于小程序端的页面模版是前端渲染的,无法通过后端对页面鉴权,也无法 redirect。

2

框架选择

目前使用React构建小程序的方案大都使用静态编译的方式实现,例如taro,nanachi。

这种静态编译方式只是让我们使用React和JSX的语法来编写小程序代码,然后通过语法分析工具把代码翻译成小程序模板。

由于 JSX 并非模板语言,要将其翻译成小程序模板,则必须要牺牲一些 JS 的动态特性,这也就是为什么这种方案在编写上有很多限制,其本质缺陷在于语法分析是静态的,而 JS 是动态的。

此外,这种方案实际运行时并非“真 React ”,因此对于跟进 React 特性来说,无法做到与官方同步。

至于Kbone ,它能够支持完整的React和 JSX 语法,是因为它把 React 给完整引入进来,而对于 React 底层依赖了的 dom/bom 接口,它提供一套轻量的小程序适配层接口。

正是因为通过提供适配器的方式来仿造出 Web 环境,所以我们可以在任意位置任意方式书写 React 和 JSX,而无须担心是否不支持某些新特性。

3

React-Kbone-Miniprogram 过程

从 kbone-template-react 官方例子来看,React代码使用Kbone构建出小程序,其流程是基于 Webpack 来实现的,它使用Babel转换React 代码并通过mp-webpack-plugin在构建Web端代码后追加Kbone和小程序相关的文件到小程序工程。

  • package.json、pages/、app.、project.config.json等文件由 mp-webpack-plugin 插件生成的小程序工程文件。
  • miniprogram-renderminiprogram-element是Kbone两个核心模块:仿造接口和自定义组件,它们通过小程序npm包安装。
  • common目录包含业务样式、业务代码和第三方库(React 相关),是由 Babel 转换并打包输出的。

从上图看,例子主要是以新项目出发,通过 webpack.mp.config.js 配置生成完整的小程序工程,但对于现存的小程序工程来说,其实我们并不需要 app.* 、project.config.json 等文件,同时更多时候我们希望是在现有的 H5 项目中书写代码和复用代码,然后生成小程序页面输出到现有小程序工程中

4

接入现有工程

礼包课程领取页主要涉及到两个现存的工程:

  • m-core:是腾讯课堂H5 页面,技术栈是 Webpack 4 + Babel 7+ React ^16.8 + Typescript
  • weapp-ke:是腾讯课堂小程序,技术栈是小程序原生框架

为了优先保证H5能够正常运行,我们将新页面的代码放到 m-core 项目,接着增加webpack.mp.config.js 配置,由于同构生成的小程序页面依赖 Kbone的适配层库,为避免原小程序工程主包过大,我们需要构建生成分包页面.

同时上面说到 mp-webpack-plugin 会生成额外的小程序工程文件,所以我们要么在其构建结束后移除这部分文件,要么修改该插件仅生成必要的文件。

我们暂时采用后一种方案,相对灵活一些,并已反馈给微信同学以支持生成单一页面代码到指定目录。

4.1 构建配置

我们基于 kbone-template-react 提供的 webpack.mp.config.js 来修改,以支持项目中使用的React、Typescript、PostCSS、条件编译、Tree Shaking 等特性,还有与小程序代码复用。

4.1.1 Babel

以下是 H5 和小程序代码转换的公用规则,依据 isMp 来区分不同的转换处理

同构小程序使用的 babel-loader 配置与一般 H5 使用的配置有些不同,对于小程序我们可以不加 @babel/preset-env,是因为小程序开发者工具本身提供 ES6 转 ES5 的代码编译能力和增强编译能力。

至于插件**请不要使用@babel/plugin-transform-runtime@babel/plugin-transform-modules-commonjs **插件。

这两个插件在 h5 中比较常见,但在这里 @babel/plugin-transform-runtime会导致小程序开发者工具运行报错,@babel/plugin-transform-modules-commonjs会影响Webpack的Tree Shaking。

此外,我们使用到webpack-strip-block,目的就是根据环境移除不必要的代码块,配合 DefinePlugin 和 Tree Shaking 一起使用。

4.1.2 Tree Shaking

由于小程序对包大小有严格限制,因此我们需要尽可能地减少包大小。Tree Shaking 是一种代码优化技术,它可以消除那些无用的代码。

Webpack中要使用Tree Shaking,我们必须保证:

  • 使用 ES2015 模块语法。
  • 确保没有编译器将ES2015模块语法转换为CommonJS模块。
  • 在项目package.json文件中添加一个sideEffects属性或在module.rules配置选项中设置 sideEffects。
  • 使用productionmode配置选项启用各种优化插件,包括 Minification 和 Tree Shaking。

4.2 代码编写

4.2.1 小程序、H5 公共库适配

由于原本的 H5和小程序项目是分开的,暂时没有统一的模块管理。尤其是涉及两端特有 api 的库无法共用。

需要注意的是有副作用的库,有些库中会除了 export 方法外会有一些自执行逻辑,若是其中逻辑涉及到 wx API,或 Web API,会导致另一端上抛出异常,需要注意分别在两端中剔除无关的库。

因此可以考虑抽出一个适配层,抹平两端公共库的差异,如request、上报组件、统一路由跳转等。

举个例子,由于同构的代码在 H5 项目中,我们将小程序的 request 方法向 H5 的 request 方法对齐入参和返回值,进行适配。

4.2.2 open-type button的回调函数

React有一套自己的事件系统,用事件委托的方法,在document对事件进行监听。因此我们在JSX中所传入的若不是React支持的DOM事件,DOM上是获取不到我们传入的回调方法的。

而在小程序中,对于部分设置open-type的button,小程序支持设置回调来获取一些用户授权的信息,我们从回调中获得解密用户手机号码的参数。这些都不是React中支持的回调函数。

因此这些方法需要被手动绑定到 DOM 上,才能被 Kbone 获取并触发到。我们可以另外封装一个 WxButton 组件,对这种特殊的回调做处理:

4.2.3 小程序组件boolean类型的属性

小程序组件有时候需要传递boolean类型的参数,如 <image> 的 lazy-load属性,直接在JSX中书写<imglazy-load/>,属性也无法被 Kbone读取到,可以换种方式,通过类型转换来传递boolean 类型的属性:

<img lazy-load={1} />

5

总结

就目前 Kbone 实现的同构小程序效果来看还是不错的:

  • 开发体验:低成本接入现有H5项目,并只需要针对 process.env.isMiniprogram 做小程序端特有的逻辑,其他完全与开发 H5 无异。
  • 性能质量:由于实践的页面结构相对简单,所以流畅性基本可以与原生开发一样。后续实践将会针对结构复杂的页面研究其性能。

从上面开发实践来看,虽然已实现 H5 和小程序同构,但仍有一些可以改进优化的地方,例如 webpack-strip-block 这个 loader.

它通过注释包裹的方式来区分 H5 端和小程序端的依赖引入(import),在 vscode 下可能会自动修正依赖引入的顺序,导致注释包裹内的依赖乱掉并影响到程序正常的运行,所以后续需要通过另外一种方式来优化这一部分。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-09-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 极乐技术社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • axios 在微信小程序中使用
  • DOM/BOM 接口的兼容性问题
  • 样式
  • 页面鉴权
  • 4.1 构建配置
    • 4.1.1 Babel
      • 4.1.2 Tree Shaking
      • 4.2 代码编写
        • 4.2.1 小程序、H5 公共库适配
          • 4.2.2 open-type button的回调函数
            • 4.2.3 小程序组件boolean类型的属性
            相关产品与服务
            云开发 CloudBase
            云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档