淺看小程式

狒狒神48k發表於2019-03-04

2017年1月份小程式正式登場,我也和社團小夥伴們一起做了一些小程式,也有一些經驗的積累。小程式本身以便捷輕量、貼近native使用體驗為核心,成為了微信新的流量領地。從wepy到mpvue,也有多種小程式開發框架孕育而生,這些框架的誕生也意味著,微信小程式本身的開發體驗並不能滿足開發者的實際開發需求。本文也不是去介紹如何高效開發,亦或是去介紹這些框架,只是記錄一下自己肉眼可見的對小程式的探索(要是有不完善的地方求指出)。

小程式你好!

  1. 從目錄結構來看:
  • index.js
  • index.json
  • index.wxml
  • index.wxss

註定這是一個為前端開發者所設計的開發flow,wxml對於html,wxss對於css。

  1. 從偵錯程式來看

淺看小程式

也代表了這是一個前端專案,唯一肉眼可見的不同之處是標籤名不同。

從開發的角度推測小程式的架構

  • UI層、邏輯層分離

淺看小程式

小程式總體分為邏輯層和檢視層,也就是說小程式框架本身就將邏輯層和檢視層分開來了,而不是純web開發,檢視層和邏輯層混合,Vue和React之類的框架實際上也是做的這樣的事情,檢視層只需要去關心UI檢視,邏輯層去處理資料以及使用者的操作狀態等等。

微信為什麼要這麼幹呢?引用開發指南中的話:

  • 快速的載入
  • 更強大的能力
  • 原生的體驗
  • 易用且安全的微信資料開放
  • 高效和簡單的開發

在小程式之前,微信就提供過JS SDK去幫助開發者更高效的開發接近原生體驗的應用,但是光憑SDK無法徹底解決靜態資源離線、UI執行緒阻塞、頁面切換卡頓等問題。

產生這些問題的原因大多是因為瀏覽器本身的限制,也就是UI執行緒和JS執行緒衝突,React 16中的Fiber排程也在一方面是解決此類的問題。孕育而生的就是小程式中的雙執行緒模型,將邏輯層和檢視層分離。

我們常常在開發小程式的過程中會遇到,模擬器正常但是真機不正常的情況,主要是因為下面這個表格:

淺看小程式

  • 元件化系統

    • 小程式的元件化之路

    現代前端開發,已經進入了元件化開發的時代,無論是三大框架還是新Web標準中的Web Componnents,元件化會大大提高開發效率。小程式也是在後面的更新中才提出了利用Component構造器去實現元件化,在此之前,在小程式中是通過template模板渲染來實現元件化的。

    那麼有了template還為什麼要引入Component呢?

    1. 模板無法維護自身的狀態。模板本身的資料需要通過頁面傳入data去渲染,這就讓資料維護變得很複雜,無法實現真正的元件化,雖然我們在用三大框架開發的時候也會提出Container的概念,Container所做的是資料注入,但是模板不僅僅是被資料注入,哪怕是最基本的狀態也需要被注入,wepy的元件化就是基於template的,所以wepy無法解決迴圈元件公用狀態的問題,也就是一旦一個子元件的狀態發生改變,另一個相同的子元件的狀態也會發生改變;
    2. 模板沒有自身的生命週期,熟悉三大框架的同學自然知道元件生命週期的重要性,我們可以完全控制元件在什麼階段應該做什麼事,這對於非同步資料處理是必要的,舉個例子:基於template的wepy,當元件層數較深,渲染需要依賴非同步資料的時候,我們無法知道什麼時候存在有效資料的,甚至會因為非同步資料是undefined而出現報錯,tempalte的渲染是在渲染層,是和主頁面渲染同步進行的。

    小程式開發團隊可能注意到了這一點,於是引入了Component構造器,從小程式層面支援了真正的元件化開發,無論是properties還是onReady又或者是behaviors,都解決了上述的痛點。

    • 小程式元件化的實現

    Web開發中,類似Vue之類的框架是通過VDOM或者DocumentFragment之類的去作為Component建構函式的render模板。然後每一個Component類去維護自己的狀態、資料等等。

    這都不是我們這裡的重點,因為相比於這些render模式,小程式本身並不能去通過Javascript直接去控制渲染層的,而且小程式在渲染層的模式是:wxml + wxss。

    那麼小程式是怎麼實現元件化呢?

    我們在開發者工具裡來看一下,當我渲染一個元件的時候,會如何渲染呢?

    我建立了一個List-Item元件,並在index頁面引入,我們在開發者工具看下小程式是怎麼渲染的:

    淺看小程式

    顯而易見的,#shadow-root首先進入我的視線範圍,這是個什麼東東呢?查閱一下相關資料,瞭解到,一個重要的概念——Shadow DOM,現在它已經進入了新版Shadow DOM v1 規範,從屬於Web Components,順手大膽的預測一下,Web開發的元件化最終可能是由Web Component來實現的。因為Web Component已經支援區域性作用域、slot插槽等等現有框架所提供的元件化方法,學習Web Component也是我接下來自己學習的目標之一,應該也會寫部落格來記錄一下。

    微信開發指南中對元件化系統的實現是這麼說的:

    Exparser的元件模型與WebComponents標準中的ShadowDOM高度相似。Exparser會維護整個頁面的節點樹相關資訊,包括節點的屬性、事件繫結等,相當於一個簡化版的Shadow DOM實現。

    也就是說其實小程式的元件就是模仿ShadowDOM,從而實現元件化。

從Source來看小程式架構

在web開發中,我們通常可以從Source panel中看到當前正在執行的指令碼檔案,小程式開發者工具同樣可以,指南中是這樣說的:

Sources panel 用於顯示當前專案的指令碼檔案,同瀏覽器開發不同,微信小程式框架會對指令碼檔案進行編譯的工作,所以在 Sources panel 中開發者看到的檔案是經過處理之後的指令碼檔案,開發者的程式碼都會被包裹在 define 函式中,並且對於 Page 程式碼,在尾部會有 require 的主動呼叫。

我們看下截圖:

淺看小程式

當開啟ES6轉ES5的開關之後,每個js檔案會生成一個同名的[name].js[sm],這個檔案是轉換前的初始檔案,而[name].js就被替換成了ES5版本的程式碼。

進一步的,我們看到這個應用執行在本地51516埠,這個埠其實是每次重啟開發者工具,隨機分配的一個閒置埠。我們在瀏覽器中開啟127.0.0.1:51516,可以看到:

淺看小程式

簡單分析一下這個html檔案。

  • 開啟第一個script標籤,顯而易見,小程式的前端程式碼也是通過webpack打包的;

淺看小程式

  • 淺看小程式

    在這個script中,定義了的全域性變數包括路由、當前檔案、Component的建構函式、外掛等等。我們順手在控制檯列印一下此時的window物件:

    淺看小程式

    可以發現,此時window物件上已經被掛載了很多額外的屬性,這也就使得我們去直接呼叫wx、Page、Component等方法成為了可能,與此同時,我們點開WeixinJSBridge來看:

    淺看小程式

    這個JSBridge主要承擔的責任就是去連線JS Core和Native層,是一個典型的事件註冊、監聽、釋出、訂閱的行為。

  • 淺看小程式

從這段程式碼可以看出幾點:

  1. 小程式的渲染層確實是基於html的,也就是說wxml最終轉化成的就是html,這個非常類似於VDom的另一種表達形式,只是進一步的,;
  2. 這個__wxConfig是將所有頁面對應的json檔案以及預設配置取了並集,然後生成的一個配置物件。
  • 淺看小程式

    這個__devtoolsConfig顯而易見得是使用者資訊以及wx這個物件上所掛載的去呼叫Native層服務的方法,以及需要授權時的提示資訊等,比較讓人意外的是,我在清除所有授權之後,這裡仍然能看到我的openid以及個人敏感資訊,但是在實際開發中這些敏感資訊其實大多都是通過前端獲取code,然後從後端解密獲取的,所以這一塊是否存在安全問題,還需要進一步的研究。

  • 淺看小程式

    這段程式碼可以看出,一開始定義的__wxRouteBegain這個變數就是去檢測頁面載入是否成功的。

總結

在開發小程式的過程中,可能會因為很多限制因素,而導致開發體驗並不是非常友好,比如複雜的檔案結構,明明可以官方支援通過loader去做成類似Vue的template的開發模式又或者是jsx之類,更貼近現在前端開發的體驗;更比如說邏輯層和渲染層的分離導致渲染延遲,無法有效操作dom節點之類的問題。

但是,個人覺得,有機會還是可以深入小程式底層實現,明白它為什麼要這麼設計,也可以幫助我們成長。相信小程式也會變得越來越好,更符合開發直覺~~~

相關文章