[轉] 如何實現 React 寫小程式-1

神煩it狗發表於2018-06-15

鋪墊

隨著大前端蓬勃發展, 冒出越來越多的端, 最火的當數最近出現的微信小程式. 但是無論是 微信小程式 , 還是 支付寶小程式, 或者 快應用 都有一個明顯的缺點, 雖然他們還是按照一定的 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

相關文章