探索Dart的新构建系统

如果您曾经使用过Web应用程序,则可能使用过构建系统。 Webpack,Gulp或Grunt都是构建系统。

Dart 1使用称为Barback的系统,但Dart 2使用称为package:build的新系统。 那么,发生了什么变化?为什么?

什么是构建系统?

构建系统的快速定义是一个程序,它接收一组输入文件并生成输出文件。 这些输出文件通常是可执行文件或Web的“捆绑包”。 在Dart中,提供了一个开发服务器,以便您对代码所做的任何更改都可以立即构建并通过HTTP端口提供。

Dart的新构建包增加了一个附加要求:输出必须能够静态确定。 例如,如果将名为post.md的文件输入到Markdown构建器中,则构建系统应该知道输出将是post.html文件。 它必须预先知道这一点。

再见变形金刚

考虑一下这个Markdown变压器:

  导入 'dart:async'; 

导入 'package:barback / barback.dart';
导入 'package:markdown / markdown.dart';

Markdown 扩展了 Transformer {
Markdown();
字符串get allowedExtensions =>“ .md .markdown .mdown”;
将来套用(转换转换) 异步 {
var content = 等待 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知道此转换器将.md文件转换为.html文件。 它只是运行此变压器。 运行此转换器调用将告诉构建系统写入新的.html文件(Barback将此文件称为资产),并使用原始文件。

由于输出文件对构建系统而言是不透明的,因此Markdown转换器可以自由生成其他文件而无需告知构建系统。 另一个构建步骤可以选择将多个.md文件合并为一个.html文件。

您可能还注意到没有创建或销毁任何显式文件。 Barback在内存中运行变压器。 它不会将文件写入磁盘。

我们已经看到了Barback:

  1. 在构建运行之前不知道输入和输出
  2. 通过抽象界面运行构建步骤。 Barback可以运行这些构建步骤,而不必将文件写入磁盘。
  3. 在执行下一个构建步骤之前,可以删除输入

你好建设者

让我们看一下使用package:build实现的Markdown构建步骤:

  导入 'package:build / build.dart'; 
导入 'package:markdown / markdown.dart';

生成器markdownBuilder(_)=> MarkdownBuilder();

MarkdownBuilder 实现了 Builder {
将来的build(BuildStep buildStep) 异步 {
var inputId = buildStep.inputId;

var outputId = inputId.changeExtension(“。html”);
var contents = 等待 buildStep.readAsString(inputId);
var markdownContents = markdownToHtml(contents);

等待 buildStep.writeAsString(outputId,markdownContents);
}

Map <String,List > get buildExtensions => {
'.md':[“。html”]
};
}

注意, allowedExtensions已替换为buildExtensionsBuilder必须明确定义其输入和输出。 另一步骤是更新build.yaml文件:

  metadata_stripped 
降价:
导入:“ package:my_builders / markdown_builder.dart”
builder_factories:
-markdownBuilder
build_extensions:
.md:
-.html
auto_apply:root_package
required_inputs:
-.md

如果生成器使用AssetId中没有的扩展名写入buildExtensions ,则抛出UnexpectedOutputException

注意这次:

  1. 构建系统预先知道输入和输出
  2. 文件输入和输出仍然通过抽象接口执行
  3. 输入不能通过构建步骤删除

示例:升级Tavern(静态站点生成器)

Tavern是Dart的静态网站生成器。 现在,它具有使用Dart 2和程序包构建的基本支持。 您可以在https://github.com/johnpryan/tavern2中找到新版本。

Tavern的目标是成为与Jekyll类似的工具。 通过将其Builders与官方Dart Builders结合使用,它还自动构建Dart脚本以在您的静态站点上运行。

它支持以以下格式编写博客文章:

  --- 
标题:“ Markdown基础知识”
标签:['code','dart']
---

这是降价促销

这是有关{{title}}的一些代码

标签:

{{#tags}}
  • {{。}}
    {{/ tags}}


    ```
    你好,世界!
    ```
  • 为此,它顺序应用了多个变压器。 例如,上面的文件post.md可能经历了以下转换:

    1. 元数据转换器提取文件顶部的“元数据” YAML,并写入两个文件post.md (已删除元数据)和post.metadata.json
    2. Markdown转换器使用post.md文件并输出post.html文件
    3. 模板转换器运行并接受两个输入post.htmlpost.metadata.json并使用post.html的元数据的胡须模板将新的资产替换为post.metadata.json

    小酒馆2需要采取不同的方法。 构建步骤无法再用相同的ID替换资产。 相反,必须为下一步构建写入新文件。

    但是元数据构建步骤如何从帖子顶部提取YAML? post.md不能再简单地替换为新版本。

    需要对构建步骤进行更好的定义:

    1. 元数据构建器提取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文件。

    构建步骤可以这样布置:

    等一下,为什么呢?

    强制构建步骤遵守更严格的规则,可以使构建系统与Bazel更好地配合,并在某些情况下智能地跳过构建步骤。 例如,如果我们的应用程序使用Sass,则可以在我们上面定义的管道旁边运行sass构建器。 当Sass文件更改时,构建系统将仅运行构建该CSS文件所需的步骤。

    摘要

    具有自定义构建器的高效构建系统一直是Dart SDK的核心功能。 现在,它已通过新的语义进行了优化,但仍对自定义构建规则提供了强大的支持。

    参考文献

    • 淡褐色
    • 编写一个构建器
    • 巴巴克的设计
    • 背影
    • 酒馆
    • 小酒馆2