我正在开发一个 Flutter 应用程序,并且想编写一个构建脚本来将某种原始文件(CSV 格式)转换为格式化的 JSON 文件以作为 Flutter 资产包含在内。
通过使用像json_serializable
和jaguar_serializer
我了解的库build_runner
,所以看起来我自己编写Builder
并通过调用它build_runner
是一种明智的方式。
由于有关编写我们自己的构建脚本的资源非常有限,我首先修改了此处找到的示例。但是我在尝试更改输入输出文件的路径时卡住了:当我运行时flutter pub pub run build_runner build
,结果发现Dart只搜索[project_dir]/web
目录中匹配的文件,并且只允许我将文件写入该web
目录。所以这段代码
buildStep.writeAsString(new AssetId(buildStep.inputId.package, 'assets/resources/foo.json'), '[]');
Run Code Online (Sandbox Code Playgroud)
将产生以下异常:
UnexpectedOutputException: myapp|assets/resources/foo.json
Expected only: {myapp|web/.json}
[SEVERE] Failed after 24.4s
Run Code Online (Sandbox Code Playgroud)
json_serializable
并且jaguar_serializer
可以在任何地方自由生成代码这一事实似乎表明我的配置有问题。但是我web
在我的代码和build.yaml
文件中的任何地方都找不到这个东西,所以这真的很令人费解。
FWIW,这是我的builder.yaml
文件的内容:
builders:
jsonBuilder:
import: "package:myapp/builder.dart"
builder_factories: ["jsonFileBuilder"]
build_extensions: {"source.csv": [".json"]}
build_to: source
auto_apply: root_package
Run Code Online (Sandbox Code Playgroud)
这是builder.dart
文件
import 'dart:async';
import 'package:build/build.dart';
Builder jsonFileBuilder(BuilderOptions options) => new JsonFileBuilder();
class JsonFileBuilder implements Builder {
@override
Future build(BuildStep buildStep) async {
await buildStep.writeAsString(
new AssetId(buildStep.inputId.package, 'assets/resources/foo.json'),
'hello');
}
@override
final buildExtensions = const {
'source.csv': const ['.json']
};
}
Run Code Online (Sandbox Code Playgroud)
提前致谢!
Edm*_*Tam 11
好吧,看来这个问题实际上是双重的。
我的问题是,如果我将源 CSV 文件放在某个任意目录(如offline
)下,由于找不到匹配的文件,我的构建脚本将无法运行。但是当我将文件放在web
(如示例中)下时,脚本会被调用。这给了我一种错觉,即文件扫描仅限于web/
. 事实是,有一个硬编码文件/目录白名单列表:
const List<String> _defaultRootPackageWhitelist = const [
'benchmark/**',
'bin/**',
'example/**',
'lib/**',
'test/**',
'tool/**',
'web/**',
'pubspec.yaml',
'pubspec.lock',
];
Run Code Online (Sandbox Code Playgroud)
如果我将 CSV 文件放在lib/
.
要将我的非白名单文件附加到列表中,我必须将以下部分添加到build.yaml
.
targets:
$default:
sources:
# Need to replicate the default whitelist here or other build will break:
- "benchmark/**"
- "bin/**"
- "example/**"
- "lib/**"
- "test/**"
- "tool/**"
- "web/**"
- "pubspec.yaml"
- "pubspec.lock"
# My new source
- "offline/source.csv"
Run Code Online (Sandbox Code Playgroud)
我的问题是我无法写入任意目录,构建系统一直抱怨我只能写入web/
. 所以我认为文件写入被锁定到web/
. 同样,这并不完全正确,因为文件写入实际上被锁定在输入文件的目录中。这意味着我只能offline/
在构建运行程序成功识别此目录中的文件后才能写入。
文件写入权限的检查由以下方法build_step_impl.dart
控制:
void _checkOutput(AssetId id) {
if (!_expectedOutputs.contains(id)) {
throw new UnexpectedOutputException(id, expected: _expectedOutputs);
}
}
Run Code Online (Sandbox Code Playgroud)
这_expectedOutputs
是buildExtensions
我的构建器类的地图的展平值。所以如果我真的想写信给assets/resources/foo.json
我,我必须这样写:
@override
final buildExtensions = const {
'source.csv': const ['/../../assets/resources/foo.json']
};
Run Code Online (Sandbox Code Playgroud)
build.yaml
必须进行类似的调整:
build_extensions: {".csv": ["/../../assets/resources/foo.json"]}
Run Code Online (Sandbox Code Playgroud)
这基本上解决了我的大部分问题,但仍有一些问题:
首先,我计划编写一个构建脚本来读取单个文件并写入多个文件。文件的数量及其文件名取决于源文件的内容。鉴于检查代码,这似乎不是受支持的功能。不是拦截器,但有点不方便。
第二个是关于输出文件路径。您可以看到我的源文件重新加载[projectDir]/offline
并且我想写入[projectDir]/assets
,但输出文件名读取/../../assets/...
,这是两个级别。这是因为原始文件名(没有扩展名)被添加到输出路径中,这就是为什么会.g.dart
在生成 Dart 代码的构建器配置中看到的原因。我需要这样写/../../assets
,我的文件的完整输出路径将变成[projectDir]/offline/source/../../assets
使其解析为所需的输出文件路径。但是默认行为给我的印象是构建系统不希望我的脚本写入当前文件目录之外的任何地方,而我正在做的是对系统的黑客攻击或滥用。
归档时间: |
|
查看次数: |
1213 次 |
最近记录: |