[Flutter翻译]如何管理你的Flutter单体库

767 阅读9分钟

本文由 简悦SimpRead 转码,原文地址 blog.codemagic.io

本文将特别关注Flutter/Dart的单体,它涉及到将你的应用程序分割成......。

在处理较大的代码库时,单体是非常有用的。但它们也会带来额外的管理成本。在这篇文章中,我们将通过使用Melos这样的工具来管理monorepo,并通过Codemagic为CI/CD设置我们的存储库的过程。

本文由Nils Reichardt撰写。

monorepos的介绍

现在,许多公司和项目都在使用monorepo的结构。几个例子包括Flutter本身,FlutterFire(一套用于Firebase的Flutter包),Riverpod,Flutter社区的PlusPlugins,以及Very Good Ventures在I/O Photo Booth等项目中。

但什么是monorepo?monorepo是一个单一的版本控制的仓库,可以存储许多不同的项目。

单库的优势

单版本库有一些有用的优势。

  • 代码重复使用。单版本库使你能够将你的代码库分割成独立的小包,这对代码重用和测试非常有利。
  • 更好的CI。有了monorepo,你可以在改变版本库中的其他东西时轻松触发CI(例如,你可以在改变后端时触发Flutter集成测试)。
  • 依赖性管理。你有本地包,而不需要依赖管理器,如pub.dev
  • 支持分层架构。你可以要求你自己和你的团队应用分层架构,将各层拆分成多个包
  • 让所有东西都存储在一个地方。新的开发者只需克隆monorepo,就可以把所有东西都放在一个仓库里。

单一项目库的缺点

就像生活中的一切一样,单库也有一些缺点。

  • 更多的开销。你需要设置工具来管理版本库。
  • 没有每个项目的访问控制: 当你把所有东西都放在一个版本库里时,每个有版本库访问权的人都可以访问所有东西。

注意: 这些只是单版本库的一些优点和缺点。在比较单库和多库的时候,还有很多东西需要考虑。

这篇文章的范围

现在你已经对monorepo有了基本的了解,让我们来设定本文的范围,因为monorepos是一个大话题。你可以把你的前端、后端、内部工具、网站等存储在monorepo中。谷歌以拥有世界上最大的代码库而闻名--他们在一个仓库中拥有一切。因此,在一篇文章中涵盖关于monorepos的所有内容将是太多了。

本文将特别关注Flutter/Dart monorepos,它涉及到将你的应用程序分割成独立的小包。

示例应用程序

为了提供一个实际的例子,我们正在使用Flutter计数器应用程序,并做了一些调整。

apps/
  counter_app
packages/
  counter_widgets
  counter_lint

apps中,我们有实际部署的应用程序。我们也可以有一个内部的应用程序,网站,等等。

packages中,我们有我们的本地包。

你可以查看完整的源代码这里

正如刚才提到的,工具对于管理你的monorepo是非常有帮助的。你将面临以下的挑战。

  • 获取所有软件包的依赖性
  • 检查所有软件包的提示性内容
  • 检查所有软件包的格式化
  • 运行所有软件包的测试
  • 在所有软件包中运行 "build_runner"。
  • 合并所有软件包的代码覆盖率

你可以写你自己的bash脚本或CLI来帮助管理这些任务。然而,这要花费你一些时间。为了更快地处理这些任务,你可以使用社区工具,比如MelosVery Good CLI,或者Sidekick。在这篇文章中,我们将使用Melos。Melos也被FlutterFireAWS Amplify (Flutter)FlamePlus Plugins等软件库所使用。

设置Melos

首先,你需要在终端运行以下命令来安装Melos。

dart pub global activate melos

为了配置Melos,我们需要创建一个顶级的melos.yaml文件。目前的结构是这样的。

apps/
  counter_app
packages/
  counter_widgets
  counter_lint
melos.yaml

现在,我们用一个基本配置来设置melos.yaml文件。

# The name of the project (required) is used for display purposes within IO environments and IDEs.
name: counter

# A list of paths to local packages that are included in the Melos workspace. Each entry can be a specific path or a glob pattern.
packages:
  - "apps/*"
  - "packages/**"

# Recommended option for projects with Dart 2.17.0 or greater.
#
# This enables a new mechanism for linking local packages, which integrates
# better with other tooling (e.g. dart tool, Flutter tool, IDE plugins) than the
# mechanism currently being used by default. Please read the documentation for
# usePubspecOverrides before enabling this feature.
#
# See https://melos.invertase.dev/getting-started#setup
command:
  bootstrap:
    usePubspecOverrides: true

设置完melos.yaml文件后,运行bootstrap命令,为你的项目初始化Melos。

melos bootstrap

Bootstrapping有两个主要作用。

  1. 安装所有的软件包依赖(内部使用pub get)。
  2. 在本地将任何软件包连接起来

melos.yaml中,我们也可以定义我们的命令,这些命令在我们定义的Melos工作区的每个Dart/Flutter包中执行。

scripts:
  analyze:
    run: melos exec -- "flutter analyze"
    description: Run `flutter analyze` in all packages
  
  format:
    run: melos exec -- "flutter format . --set-exit-if-changed"
    description: Run `flutter format .` in all packages

  test:
    # Only run the test command when the package has a test directory
    run: melos exec --dir-exists=test -- "flutter test"
    description: Run `flutter test` in all packages

现在我们能够用melos run SCRIPT_NAME执行我们的脚本。要在所有软件包中运行flutter analyze命令,我们可以使用这个命令。

melos run analyze

你可以在melos.yaml文件中添加任何你想要的脚本,如build_runner。查看Melos的文档以了解更多关于scripts配置的信息。

另外,看看melos-code,这是Melos的VS Code扩展,帮助你在Melos和VS Code中工作。

为 CI/CD 设置您的 Flutter 单一项目

您应该能够用 Melos 在本地管理您的 monorepo。然而,您可能需要配置您的CI/CD环境以完全支持您的monorepo。我们将使用Codemagic作为CI/CD提供者。

注册

我们的CI的范围

我们的CI管道应该对每个拉动请求执行以下检查。

  • 运行 "melos run analyze "命令
  • 运行 "melos run format "命令
  • 运行 "melos run test "命令
  • 上传失败的黄金测试的结果

为一个monorepo配置CI/CD

设置Codemagic

首先,你需要一个Codemagic账户。如果你还没有,你可以通过你的Git提供商注册Codemagic。用 Workflow Editorcodemagic.yaml 文件来设置Codemagic。如果你需要一个逐步的指导,你可以按照这篇文章来为Codemagic设置你的monorepo。

工作流编辑器对于一个基本的应用程序来说,使用起来很简单。然而,对于monorepo来说,最好使用codemagic.yaml,因为我们可以用Melos运行我们自己的命令。由于这个原因,这篇文章只涉及codemagic.yaml文件的设置。

为CI/CD设置Melos

在CI/CD中设置Melos与在你的本地机器上设置它相似。

  1. 运行dart pub global activate melos
  2. 运行melos bootstrap

让我们检查一下codemagic.yaml文件中的基本配置。

workflows:
  ci:
    name: CI
    instance_type: mac_mini
    # Setting the timeout for a build to 15 minutes.
    max_build_duration: 15
    environment:
      # Using the latest Flutter version.
      flutter: stable
    # This workflow should trigger when a new pull request opens or updates.
    triggering:
      events:
        - pull_request
    scripts:
      - name: Add Dart SDK to PATH
         script: |
           echo PATH="$PATH":"$FLUTTER_ROOT/.pub-cache/bin" >> $CM_ENV
           echo PATH="$PATH":"$FLUTTER_ROOT/bin" >> $CM_ENV           
      
      - name: Melos Bootstrap
         script: |
           dart pub global activate melos
           melos bootstrap           

如果你仔细看一下这个脚本,你会注意到这些行。

echo 'export PATH="$PATH":"$FLUTTER_ROOT/.pub-cache/bin"' >> $CM_ENV 
echo 'export PATH="$PATH":"$FLUTTER_ROOT/bin"' >> $CM_ENV 

我们需要将Dart SDK的路径添加到PATH中,以便能够运行dart命令。否则,我们会得到一个错误,如dart: command not found

运行Melos脚本

让我们把我们的Melos脚本添加到codemagic.yaml文件中。现在codemagic.yaml是这样的。

workflows:
  ci:
    name: CI
    instance_type: mac_mini
    # Setting the timeout for a build to 15 minutes.
    max_build_duration: 15
    environment:
      # Using the latest Flutter version.
      flutter: stable
    # This workflow should trigger when a new pull request opens or updates.
    triggering:
      events:
        - pull_request
    scripts:
      - name: Add Dart SDK to PATH
         script: |
           echo PATH="$PATH":"$FLUTTER_ROOT/.pub-cache/bin" >> $CM_ENV
           echo PATH="$PATH":"$FLUTTER_ROOT/bin" >> $CM_ENV           
      
      - name: Melos Bootstrap
         script: |
          dart pub global activate melos
          melos bootstrap          

      - name: Run Analyze
         script: melos run analyze

      - name: Run Format
         script: melos run format

      - name: Run Tests
         script: melos run test

获取失败的Golden测试的结果

通过Golden测试,您可以渲染一个小部件,并将其与屏幕截图进行比较。要了解更多关于Golden测试的信息,请查看这篇关于如何用Codemagic CI/CD运行Flutter Golden(Snapshot)测试的博客文章。如果你的Flutter repo中有Golden测试,你可能想访问失败的Golden测试的结果。当你使用monorepo时,你需要检查每一个包是否有失败的Golden测试结果。要做到这一点,你可以直接运行这个脚本。

...
- name: Run Tests
  script: |
    melos run test
    
    # Upload results of failed Golden tests if test command failed.
    if [ $? -ne 0 ]; then
      # Finds all "failures" folders and copies them to the export
      # directory. Therefore, we are able to view the results of the
      # failed Golden tests.
      #
      # The command will use the exit code 0 (success) even when there are
      # no failures folders.
      find * -path '**/failures' -execdir bash -c "cp -r failures $FCI_EXPORT_DIR" \;
      
      # Because we caught the exit code of the test command, we need to
      # set manually again.
      exit 1
    fi    

配置路径条件

目前,我们为每个拉动请求运行CI,不管这个拉动请求有什么变化,即使我们只是改变了文档文件或后端文件(假设我们的monorepo中也有我们的后端)。

然而,你正在使用不必要的Codemagic构建时间。

为了更有效地使用你的构建分钟,你可以设置路径条件。通过路径条件,你可以定义CI只在特定路径发生变化时运行。

只要使用when关键字来配置路径。

...
environment:
  # Using the latest Flutter version.
  flutter: stable
when:
  changeset:
    includes:
      # Only run the CI when a file in one of the following directories
      # changed.
      - "apps/**"
      - "packages/**"
      - "codemagic.yaml"
    excludes:
      # Don't run the CI when only .md files have changed.
      - "**/*.md"
# This workflow should trigger when a new pull request opens or updates.
triggering:
...

你也可以查看Codemagic关于有条件地运行构建和构建步骤的文档,了解更多关于有条件运行的信息。

结论

单核处理器对于较大的代码库是很好的。然而,正如你在这篇文章中注意到的,它们需要更多的努力来管理。尽管如此,你现在应该能够用Melos来管理你自己的Flutter monorepo并配置你的CI/CD。

你可以查看存储库的全部源代码这里

如果你在Codemagic遇到配置问题,只需在Codemagic Slack中寻求帮助。

本文作者Nils Reichardt是Sharezone的联合创始人,Sharezone是一个拥有30万注册用户的Android、iOS、Web和macOS的协作式学校计划器。从2018年3月的第一个测试版开始,他就爱上了Flutter。你可以在TwitterGitHubLinkedIn找到Nils。


www.deepl.com 翻译