Flutter隨筆(二)——使用Flutter Web + Docker + Nginx打造一個簡單的Web專案

monkey1992發表於2021-10-17

前言

  Flutter作為一個跨平臺UI框架,功能十分強大,僅用一套程式碼便能編譯出Android、iOS、Web、windows、macOS、Windows、Linux等平臺上的應用,各平臺應用體驗高度一致,目測前途一片光明,形勢一片大好。

  Flutter支援Android和iOS已經很長一段時間了,相信很多同學對使用Flutter開發Android和iOS應用都已經駕輕就熟了,今天我們就來體驗一把Flutter Web。目標是建立一個簡單的Flutter Web專案,然後打包部署到伺服器,通過瀏覽器進行訪問。

1.建立Flutter工程

  首先我們需要建立一個Flutter工程。我使用了Android Studio來建立工程,如下:

  上圖中需要注意的地方是Platforms,在Platforms欄中我們要選擇程式執行的平臺,因為我們最終要打包出Web專案,所以我們務必勾選Web選項。
  工程建立好之後的目錄結果如下:

  除了我們熟悉的Android和iOS目錄外,還多了Web目錄,Web目錄下存放了Web專案所需要的全部檔案。

2.編寫flutter程式碼

  接下來,我們編寫flutter程式碼,程式碼非常簡單,僅實現了在主頁點選按鈕跳轉到對應子頁面的功能。
  主頁 main.dart 的程式碼如下:

import 'package:flutter/material.dart';
 
import 'ChildPage.dart';
 
void main() {
  runApp(MyApp());
}
 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'xy_flutter',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'xy_flutter'),
    );
  }
}
 
class MyHomePage extends StatelessWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
 
  final String title;
  final List<HomeMenu> menus = [
    HomeMenu('page1', '頁面1'),
    HomeMenu('page2', '頁面2'),
    HomeMenu('page3', '頁面3'),
  ];
 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: ListView.builder(
          itemCount: menus.length,
          itemBuilder: (context, index) {
            return ListTile(
              title: Text(menus[index].title),
              onTap: () {
                HomeMenu homeMenu = menus[index];
                String id = homeMenu.id;
                String title = homeMenu.title;
                if (id == 'page1') {
                  Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (context) => ChildPage(title: title)));
                } else if (id == 'page2') {
                  Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (context) => ChildPage(title: title)));
                } else if (id == 'page3') {
                  Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (context) => ChildPage(title: title)));
                }
              },
            );
          }),
    );
  }
}
 
class HomeMenu {
  String id;
  String title;
 
  HomeMenu(this.id, this.title);
}

  子頁面 child_page.dart 的程式碼如下:

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
 
class ChildPage extends StatefulWidget {
  final String title;
 
  const ChildPage({Key key, this.title}) : super(key: key);
 
  @override
  State<StatefulWidget> createState() {
    return _ChildPageState();
  }
}
 
class _ChildPageState extends State<ChildPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text(widget.title)), body: Text(widget.title));
  }
}

3.打包Web工程

  在工程根目錄下執行以下命令進行編譯打包:

flutter build web

  命令執行成功之後,編譯生成的檔案被輸出到了 工程根目錄/build/web/ 目錄下,如下:

4.上傳Web工程到伺服器

  通過檔案傳輸工具(例如FileZilla等)將編譯後生成的所有檔案上傳到伺服器。我上傳到伺服器的路徑為 home/ubuntu/docker/xy_flutter/web/home/ubuntu/docker/xy_flutter/web/ 目錄和工程編譯出來的web目錄對應,即 home/ubuntu/docker/xy_flutter/web/ 目錄下的檔案和工程編譯出來的web目錄下的檔案完全一致。

5.建立Nginx Docker容器

  接下來,我們在伺服器中建立一個Nginx的Docker容器,用來執行Web專案。
  如果伺服器還沒有安裝Docker,需要先安裝Docker,關於如何安裝Docker可以參考我之前整理的資料 Docker遊記1——安裝Docker 
  如果已經安裝好了Docker,但還沒有拉取Nginx的Docker映象,需要先拉取一下映象,可以通過如下命令拉取最新的Nginx Docker映象:

docker pull nginx:latest

  映象拉取下來之後,可以通過如下命令檢視當前所有已拉取下來的映象:

docker images

  得到的結果如下:

REPOSITORY     TAG       IMAGE ID       CREATED        SIZE
nginx          latest    87a94228f133   2 days ago     133MB

  我們可以看到已經有Nginx的映象了。
  接著我們利用拉取下來的映象建立一個容器,執行以下命令:

docker run --name xy_flutter -p 8088:80 -d nginx

  這行命令表示使用Nginx映象建立並持續執行一個名為xy_flutter的容器,並將伺服器的8088埠對映到容器的80埠。建立好之後,可以通過以下命令檢視建立好的容器:

docker ps

  結果如下:

CONTAINER ID   IMAGE               COMMAND                  CREATED         STATUS         PORTS                                       NAMES
0c6f697a8e0c   nginx               "/docker-entrypoint.…"   5 seconds ago   Up 3 seconds   0.0.0.0:8088->80/tcp, :::8088->80/tcp       xy_flutter

  容器建立好之後,我們就可以通過瀏覽器訪問容器對應的Nginx服務了,因為我的伺服器地址IP地址是 http://49.234.163.66/ ,容器對映的伺服器埠是8088,所以訪問地址是 http://49.234.163.66:8088/ ,訪問後跳轉的頁面如下:

  已經看到Nginx在歡迎我們了!

6.部署Web工程

  我們通過瀏覽器訪問Nginx服務時,跳轉的頁面其實是容器中的 /usr/share/nginx/html/index.html 檔案,我們可以進入容器檢視。
  執行以下命令進入容器:

docker exec -it {容器ID} /bin/bash

  進入容器後,我們通過`cd`命名訪問 /usr/share/nginx/html/ 目錄,目錄中的檔案如下:

  要部署Web工程,把Web工程中的所有檔案複製到容器的 /usr/share/nginx/html/ 目錄就可以了,Web工程中的index.html會覆蓋 /usr/share/nginx/html/index.html 檔案。我們通過如下命令把伺服器本地的檔案複製到容器中:

docker cp {伺服器中Web工程目錄下的所有子檔案} {容器ID}:/usr/share/nginx/html

  我的伺服器中Web工程目錄下的所有子檔案是 home/ubuntu/docker/xy_flutter/web/. ,容器ID是 0c6f697a8e0c ,所以我執行的命令是:

docker cp home/ubuntu/docker/xy_flutter/web/. 0c6f697a8e0c:/usr/share/nginx/html

7.部署完成

  在上述步驟中,我們已經將Web工程拷貝到容器中的指定位置了,到這裡部署工作其實也就完成了,我們再次在瀏覽器中輸入 http://49.234.163.66:8088/ 訪問,可以看到已經可以開啟我們的Web工程了,如下:

  至此,我們就完成了從建立Flutter Web專案到部署至伺服器的整個流程!

最後奉上專案地址

相關文章