[Flutter翻譯]探索Dart的新構建系統

Sunbreak發表於2020-07-22

原文地址:medium.com/@john.p.rya…

原文作者:medium.com/@john.p.rya…

釋出時間:2019年1月9日 - 5分鐘閱讀

[Flutter翻譯]探索Dart的新構建系統

如果你曾經做過一個web應用程式,你可能使用過一個構建系統。Webpack、Gulp或Grunt都是構建系統。 Dart 1使用了一個叫Barback的系統,但是Dart 2使用了一個新的系統,叫pack:build。那麼有什麼變化,為什麼?

什麼是構建系統?

構建系統的一個快速定義是一個程式,它接受一組輸入檔案並生成輸出檔案。這些輸出檔案通常是可執行檔案或網路的 "捆綁"。在Dart中,提供了一個開發伺服器,因此,任何對你的程式碼的改變都會立即被構建並在HTTP埠上提供。

Dart的新構建包增加了一個額外的要求:輸出必須能夠靜態地確定。例如,如果一個名為post.md的檔案被輸入到Markdown構建器中,構建系統應該知道輸出將是post.html檔案。它必須在前期就知道這一點。

Goodbye Transformers

考慮這個Markdown變換器:

import 'dart:async';

import 'package:barback/barback.dart';
import 'package:markdown/markdown.dart';

class Markdown extends Transformer {
  Markdown();
  String get allowedExtensions => ".md .markdown .mdown";
  Future apply(Transform transform) async {
    var content = await transform.primaryInput.readAsString();
    var id = transform.primaryInput.id.changeExtension(".html");
    var newContent = markdownToHtml(content, extensionSet: ExtensionSet.gitHub);
    transform.consumePrimary();
    transform.addOutput(new Asset.fromString(id, newContent));
  }
}
複製程式碼

這個變換器接收以.md.markdown.mdown結尾的檔案,並將原始檔案替換為使用package:markdown生成的.html標籤。請注意,原始檔案被替換了,而構建系統在前期無法知道這個變換器將.md檔案轉換為.html檔案。它只是簡單地執行這個變換器。執行這個變換器呼叫告訴構建系統寫入新的.html檔案(Barback稱之為Asset),並消耗原始檔案。

由於輸出檔案對構建系統來說是不透明的,Markdown變換器可以自由地生成額外的檔案而不告訴構建系統。另一個構建步驟可能會選擇將多個.md檔案合併成一個.html檔案。

你也可能已經注意到,沒有建立或銷燬任何顯式檔案。Barback在記憶體中執行變換器。它不會將檔案寫入磁碟。

我們已經看到,Barback:

  1. 在構建執行之前,它不知道輸入和輸出的情況。
  2. 通過一個抽象的介面執行構建步驟。Barback可以執行這些構建步驟,而不需要將檔案寫入磁碟。
  3. 在執行下一個構建步驟之前,可以刪除輸入。

Hello,Builders

讓我們看看使用package:build實現的同樣的Markdown構建步驟:

import 'package:build/build.dart';
import 'package:markdown/markdown.dart';

Builder markdownBuilder(_) => MarkdownBuilder();

class MarkdownBuilder implements Builder {
  Future build(BuildStep buildStep) async {
    var inputId = buildStep.inputId;

    var outputId = inputId.changeExtension(".html");
    var contents = await buildStep.readAsString(inputId);
    var markdownContents = markdownToHtml(contents);

    await buildStep.writeAsString(outputId, markdownContents);
  }

  Map<String, List<String>> get buildExtensions => {
        '.md': [".html"]
      };
}
複製程式碼

請注意,allowExtensions已經被buildExtensions取代。Builder必須明確地定義它的輸入和輸出。另外一個步驟是更新 build.yaml 檔案。

metadata_stripped
  markdown:
    import: "package:my_builders/markdown_builder.dart"
    builder_factories:
      - markdownBuilder
    build_extensions:
      .md:
        - .html
    auto_apply: root_package
    required_inputs:
      - .md
複製程式碼

如果Builder向AssetId寫入一個不在buildExtensions中的副檔名,就會丟擲一個UnexpectedOutputException

注意,這個時候:

  1. 構建系統已經知道了輸入和輸出的資訊
  2. 檔案的輸入和輸出仍然是通過一個抽象的介面來完成的。
  3. 不能通過構建步驟刪除輸入

一個例子。升級Tavern,一個靜態網站生成器。

Tavern是一個Dart的靜態網站生成器。它現在已經基本支援使用Dart 2和包構建。你可以在 github.com/johnpryan/t… 找到新版本。

Tavern的目標是成為一個類似於Jekyll的工具。它還可以通過結合它的Builders和官方的Dart builders,自動構建Dart指令碼在你的靜態網站上執行。

它支援寫部落格文章,格式如下。

---
title: "Markdown Basics"
tags: ['code', 'dart']
---

# this is markdown

Here is some code about {{title}}

Tags:

{{#tags}}
<li>{{.}}
{{/tags}}


`` `
hello world!
`` `
複製程式碼

為此,它依次應用多個變換器。例如,上面的檔案post.md可能會經歷以下轉換:

  1. Metadata變換器提取檔案頂部的 "後設資料 "YAML,並寫入兩個檔案post.md(去掉後設資料)和post.metadata.json
  2. Markdown變換器消耗post.md檔案並輸出post.html檔案。
  3. Template變換器執行並接收兩個輸入,post.htmlpost.metadata.json,並將post.html替換為一個新的資產,並應用post.metadata.json中的後設資料進行Mustache模板化。

Tavern 2需要採取不同的方法。構建步驟不能再替換具有相同id的資產。相反,必須為下一個構建步驟編寫新的檔案。

但是Metadata構建步驟如何從post的頂部提取YAML呢?post.md不能再簡單地替換為新版本。

構建步驟需要更加明確:

  1. Metadata構建步驟提取YAML,並寫出兩個檔案post.contents(包含去掉頂部部分的markdown)和post.metadata(包含模板步驟的JSON檔案)。
  2. Markdown生成器現在接收一個.contents檔案並輸出一個.html_template檔案。
  3. 模板生成器接收一個.html_template檔案和一個.metadata檔案,並輸出最終的.html檔案。
  4. 執行一個名為CleanupBuilder的PostProcessBuilder來刪除所有.md、.contents、.metadata和.html_template_files,只留下最後的html檔案。

構建步驟可以這樣佈局:

[Flutter翻譯]探索Dart的新構建系統

等等,但為什麼?

強制構建步驟遵守更嚴格的規則,可以讓構建系統更好地與Bazel合作,並在某些情況下智慧地跳過構建步驟。例如,如果我們的應用使用了Sass,那麼一個Sass構建器可以和我們上面定義的管道一起執行。當Sass檔案發生變化時,構建系統將只執行構建該CSS檔案所需的步驟。

總結

一個具有自定義構建器的高效構建系統,一直是Dart SDK的核心功能。現在,它通過新的語義進行了更多的優化,但仍然對自定義構建規則有很大的支援。

參考文獻


通過www.DeepL.com/Translator(免費版)翻譯

相關文章