Flutter web 持續整合實踐

老虎不長牙發表於2020-06-11

引言

2018 年 12 月,Google 釋出了 Flutter 1.0 正式版,並在2019年9月在釋出Flutter 的最新穩定版本:Flutter 1.9,同時,宣佈將flutter web 合併到master。flutter web立志於開發人員可以使用相同的程式碼,更快地釋出功能,並確保其跨裝置(Android、iOS、Web)體驗的一致性。

然而就最新的Flutter1.9.x而言,Flutter Web還處於技術預覽版階段,離真正應用到生產環境中還是有一些距離的。官方也不建議將其運用在生產上,後期將會有很多的優化,而且很多flutter的庫還未相容web環境,實踐中也發現很多的坑。


目標

將Flutter web 的Demo用docker與Jenkins完成自動化部署。

www.laohubzy.cn:9527/


技術棧

Flutter Web

因為Flutter將web整合進專案當中,所以在建立web專案時,只要保證分支版本在1.5以上即可。

建立過程:

flutter channel beta
flutter upgrade
flutter config --enable-web
flutter create myapp
cd myapp
flutter run -d chrome複製程式碼

flutter config --enable-web

新增flutter對web的支援,可以使用Chrome

原理

image.png

為了使得一套程式碼可以共享到各個平臺,並且沒有差別,開發者保留最頂層的dart:ui,在瀏覽器用Web技術重新實現一次完整的dart:ui API。

將flutter專案編譯成web專案並且在瀏覽器中展示,一共分為三個階段:

  1. 建立Widgets
  2. 元素佈局
  3. 頁面繪製


建立Widgets

Widget的構建機制不依賴於應用程式執行的環境。該過程只需要例項化記憶體中的物件並跟蹤它們的狀態,當狀態改變時,計算佈局和繪畫所需的最小更新。將此部分移植到Web上非常簡單,當Dart團隊在dart2js中實現了super-mixin支援之後,編譯器將所有widget和widget框架編譯為JavaScript時幾乎沒有任何問題;

元素佈局

佈局系統有點棘手。最大的挑戰是文字佈局。其他所有Widget - Center,Row, Column, Stack, Scrollable, Padding, Wrap等 - 這些widget都由框架佈局,因此無需修改即可編譯到Web上執行。我們用來測量文字佈局屬性的技巧是讓瀏覽器將其佈局,然後從DOM元素中讀回相關屬性。

頁面繪製

通過HTML+CSS+Canvas的組合方法,我們將框架生成的圖片分類為使用HTML + CSS表達的圖片,以及使用Canvas 2D表達的圖片。然後,我們輸出結合了HTML,CSS和2D畫布的HTML DOM。

我們更喜歡HTML + CSS,因為它有瀏覽器的現實列表支援。這意味著我們可以優化圖片的光柵化在瀏覽器上的渲染引擎。這也意味著我們可以應用任意變換,尤其是旋轉和縮放,而不必擔心畫素化。我們將此畫布實現稱為“DomCanvas”。

如果我們無法使用HTML + CSS表達圖片,我們會回到畫布。




渲染結果 ⬇️


image.png

docker

概念

docker官方解釋是一個軟體容器平臺。douker中有幾個重要的概念。

  • Image 映象:映象是輕量級的,可獨立執行的軟體包。比如在伺服器上使用flutter來編譯專案時,傳統配置,我們需要下載Android sdk ,flutter sdk ,在沒有軟體的情況下,我們可能還需要java sdk,並且配置系統path等複雜的環境配置,如果換一套電腦,又需要重新配置環境。但是使用docker映象,只要在執行檔案中引入映象,就可以完成環境的配置。只要執行檔案不變,在任何一臺機器上面,都可以快速搭建相同的環境。
  • Container 容器:像是映象執行時的一個載體,在引入映象,並且使用映象進行一系列操作後,存放產物的“容器”,比如說編譯完成的網站。依託 Docker 的虛擬化技術,給容器建立了獨立的埠、程式、檔案等“空間”,Container 就是一個與宿機隔離 “容器”。

優勢

  • 在這次實踐中,明顯感覺到,傳統配置環境的複雜,並且複用性很差,遷移伺服器則需要重新配置。但是使用docker,只要執行檔案不變,就能保證環境的一致性。
  • 另外容器中的映象可以相互複用,但是容器與容器之間卻是相互隔離的,更加便於管理,不會出現環境衝突等問題。
  • 輕量。多個 Docker 容器可以共享這臺機器的作業系統核心,啟動迅速,佔用少量的記憶體空間。映象是通過檔案系統層進行構造的,並共享一些公共檔案。這樣就能儘量降低磁碟用量,並能更快地下載映象。

Jenkins

原理

持續整合

持續整合是一種軟體開發實踐,倡導開發者可以每天多次整合專案,每次的整合都是通過自動化的構建來驗證,包括合併程式碼、打包、測試和通知分發的一系列軟體工程開始的操作。

Jenkins

最流行的開源免費持續整合工具,由java語言開發,用於監控持續重複的工作,包括:持續的軟體版本釋出/測試專案,監控外部呼叫執行的工作。


⬇️Jenkins工作流程圖

image.png

實踐過程

環境搭建

準備一臺雲伺服器,我是用的騰訊雲 Linux.Centos7.6環境。但是,如果在遠端打包,最好是mac環境,linux版本的Flutter不支援build web。

安裝docker和Jenkins,並且設定Jenkins自動拉取程式碼。

參考⬇️(雖然是最後部署Vue,原理是一樣的)
juejin.im/post/5d369d…

大體過程

  1. 將程式碼部署在github上,本地打包完成之後,生成build/web 資料夾,將程式碼上傳github。
  2. 當master分支上傳專案時,會Jenkins的自動構建,拉取github上的專案。
  3. Jenkins拉取完成之後,執行專案中的構建指令碼檔案 setup.sh。
  4. 檔案中會執行docker命令,配置nginx伺服器,將build/web中的檔案放入指定目錄。

然後就可以通過網址訪問了。

相關配置檔案

(只留下關鍵程式碼,未做詳細配置)

setup.sh


#!/usr/bin/env bash
image_version=`date +%Y%m%d%H%M`;
# 設定映象
# 
docker build . -t flutter/web:$image_version;
# 執行容器
docker run -p 9527:80 -d --name flutter_web flutter/web:$image_version;
# 檢視日誌
docker logs flutter_web;複製程式碼


docker build 最後的 . 號,其實是在指定映象構建過程中的上下文環境的目錄,執行當前上下文中的Dockerfil檔案構建映象容器。將容器的80埠對映到伺服器的9527埠。之後可以通過 域名(IP地址):9527訪問


Dockerfile

FROM nginx
COPY conf.nginx /etc/nginx/nginx.conf
RUN mkdir /app
WORKDIR /app
COPY ./build/web /app/
EXPOSE 80
 複製程式碼

在Dockerfile中,主要是構建了一個nginx容器。因為Linux版本的Flutter專案並不支援build web, 所以只能本地打包,更改.gitignore檔案,將build出來的檔案也傳到gitlub上面。這邊的docker只是將檔案複製到nginx容器當中。


*若未來版本中支援Linux打包之後,Dockerfile可以直接拉取flutter與Android sdk映象,遠端打包生成build檔案。我在嘗試中,遠端是可以打包出apk檔案,但是無法打出web檔案


conf.nginx nginx的相關配置。

events {
  worker_connections  1024;
}

http {
  server {
    listen 80;

    location / {
        root   /app/;
        index  index.html index.htm;
        try_files $uri $uri/ /index.html;
    }
  }
}複製程式碼


執行之後,可以通過docker images來檢視生成的映象。映象是可以重複引用,提高構建效率。

image.png

docker ps -a來檢視當前所有執行中的容器。

image.png

只有up狀態的才表示正在執行中。如果執行失敗,可以通過檢視容器日誌來尋找錯誤。


使用Flutter web 優缺點

  1. 對於客戶端開發人員來說,特別是涉及到flutter開發的,可以零成本過渡到web專案的開發。對於現有的flutter專案,再剔除安卓特有的功能後,專案程式碼保持100%的可移植性。
  2. 各個端的表現差異不大,不必過於擔心適配問題。


  1. Linux版本不支援flutter build web, 無法在遠端打包,可能需要一臺mac伺服器專門部署專案。
  2. flutter外掛與映象支援web的數量過少,很多如傳送請求的外掛可能都需要自己進行封裝,目前只推薦做宣傳頁等邏輯偏少的靜態介面。
  3. 很主要的一點,專案打包體積過大。單純一個hello world 可以打包出2M的大小,直接導致白屏時間長。
  4. 由於web端一大部分由canvas進行繪製,當頻繁縮放螢幕等需要進行頁面重繪的操作時,很容易面臨效能的問題。
  5. 由於自身Flutter Web並沒有專門的開發者工具,而Chrome自帶的工具無法準確找到關鍵元素,導致後續開發除錯困難。

綜上所述,flutter web當前並不適用與生產環境,官方也不推薦,1.19.x版本還是處於技術預覽階段。但是其良好的分層設計,各個端的程式碼零成本移植還是有非常大的前景。Dart現如今幾乎只為flutter所服務,谷歌對Flutter投入也很大,期待其新版本技術的成熟。


相關文章