[转] 如何实现 React 写小程序-1

2,155 阅读3分钟

铺垫

随着大前端蓬勃发展, 冒出越来越多的端, 最火的当数最近出现的微信小程序. 但是无论是 微信小程序 , 还是 支付宝小程序, 或者 快应用 都有一个明显的缺点, 虽然他们还是按照一定的 js html css 标准作为开发方式, 但是他们都与当前所有主流技术有相当大的壕沟.

虽然小程序使用类似Vue, angular的模板渲染, 实现了类MVVM的开发方式.但是小程序的开发方式相当蛋疼. 以下是一个简单小程序的目录结构:

小程序目录

上述目录只包含页面内容, 开发过程中需要不断在不同文件中切换. 相比React的Component+css 和 Vue的单文件来看, 开发体验不太好. 并且很多小程序开发者都是vue、React、angular等等前端框架的使用者, 使用熟悉的开发栈对他们来说更容易上手.

小程序的本质

在开发一个工具前要理解运行载体的原理. 正如我们希望用React去开发小程序, 那么我们必须要了解小程序的原理.

因为小程序是闭源的, 我只能在自己的猜想上分析. 但是小程序的底层是Native 这是前提. 那么我猜想小程序的实现原理应该跟ReactNative类似, 通过js bridge搭建js和原生通信的桥梁, 由js及模板, 实现对页面的渲染描述.

但是小程序与ReactNative的不同点是, ReactNative对js层开放renderer api. 而小程序则对这层进行了封装. 这让我们无法通过重新实现React的renderer来使用React的一些特性(如vdom).

所以我的思路是通过语法转换, 把React文件转换成小程序工程文件. 并实现小程序的框架, 来对接小程序与react的生命周期方法.

期望

我希望能把React文件, 经过编译后, 变成可执行的微信小程序

import Page from '../wechat'
import './page.css'

class P extends Page {
  onClick(){
    
  }
  render() {
    return (
      <div className="app" onClick={this.onClick} style={{posistion:"relative"}}>
        威武
      </div>
    )
  }
}

开始我们的旅程

有了开发小程序的思路, 那我们就来动手. 我使用了babel作为语法转换的工具, 我们先开个头. 下面是转换的核心代码

function transform(code, sourcePath) {
  let output = {
    wxml:'',
    wxss:'',
    js:'',
    json:'',
    type:''//App||page||component
  }
  sharedState.sourcePath = sourcePath;
  const result = babel.transform(code, {
    babelrc: false,
    plugins: [
      '@babel/plugin-syntax-jsx', 
      transformPlugin, 
      '@babel/plugin-proposal-object-rest-spread',  
      ['@babel/plugin-proposal-decorators',{"legacy": true}] 
    ]
  })
  // tranform后, 结果都会写入sharedState.output
  output = sharedState.output;
  const obj = t.objectExpression(sharedState.methods);
  output.js = generate(obj).code;
  sharedState.reset();

  switch(output.type){
    case 'App':
      output.js = CodeWrapper('App', output.js);
      break;
    default: //Page
      output.js = CodeWrapper('Page', output.js);
      break;
  }

  return output;
}

该部分代码实际上就是通过babel 对React代码文件进行处理, 处理后把结果写入到output. 重点在于, 我们通过babel.transform这个方法, 把代码拆分成四块, 分别写入到sharedState.output中.

最终通过一些简单处理后, 返回output, 不难看出output中的wxss, js, json, wxml就是一个小程序页面/组件的代码文件.

其中 transformPlugin 是自定义的编译插件. 今天有点晚先到这里, 下期继续讨论插件开发思路.

项目代码: https://github.com/PepperYan/react-miniapp)

喜欢这篇文章的大佬, 点个赞和star, ٩(๑´0`๑)۶

该项目参考了mpvue, taro, weact等. babel-traverse和babylon babel

还有感谢 @方正 提点

原文链接: https://zhuanlan.zhihu.com/p/38102065