携手创作,一起成长!这是我参加「日新计划 8 月更文应战」的第1天,点击检查活动详情
前语
对于Flutter开发者来说,build_runner 能够说并不是一个陌生的东西,很多package中就要求调用build_runner 来主动生成处理代码,比如说json_serializable;
但正如其描绘中所述的那样,其是经过 Dart Build System来完成的,build_runner 和其又是一个什么关系,接下来就来学习一下dart的build体系
dart 的 build 体系
组成
dart 的 build体系,由 build_config、 build_modules、build_resolvers、 build_runner、 build_test、 build_web_compilers 一起组合、完成了dart 的 build 体系;
- build_config 便是解析那个build.yaml文件,用来装备build_runner,没什么好说的,具体的功用后边再细说;
- build_modules 如同是解析module级别信息的一个库
- build_resolvers 从自述文件中分析,如同是一个给build_runner 每步提供所需信息的解析器?
- build_runner 整个build体系的中心部分,其他部分都是为了拓展和完成此功用而存在的;
- build_test 字面意思,一个测验库;
- build_web_compilers 用于web端的build体系;
效果
Flutter的build体系其实便是生成代码,对标的应该是JAVA的APT这块的东西;
另外,对于 dart 的 build 体系,官方是有这么一段介绍:
Although the Dart build system is a good alternative to reflection (which has performance issues) and macros (which Dart’s compilers don’t support), it can do more than just read and write Dart code. For example, thesass_builderpackage implements a builder that generates
.css
files from.scss
and.sass
files.
也便是说dart build理论上是能够来做很多人心心念念的反射的;
根本运用
假如仅仅是运用方面来说,build_runner 的运用非常简单;比如说我们最常用的一条指令便是:
flutter pub run build_runner build
也能够装备build.yaml来修正装备信息,生成契合需求的代码;
不过在输入上面那句build_runner build之后发生了什么,像build_config之类的在这个过程中各自起了什么效果,这就需求追寻一下;
build_runner 都干了什么
依据日志信息,build_runner 的流程根本遵循这样一个套路:
接下来就看下这些编译脚本、输入环境、资源等不知所云的东西,到底是什么;
生成和预编译build脚本
生成部分:
首要来到build_runner的main函数部分,前面一大片对参数检测的拦截判别,真实履行指令的当地放在了最终:
在这个办法中最先做的事便是生成build脚本
其内容也很简单,说白了便是输出一个文件罢了:
至于这个文件内容是什么,有什么用,先放到后边再说;现在先重视于全体流程;
那么现在能够得知,这步会在scriptLocaton这个途径上生成一个build脚本;而这个途径也不难得到:
其实便是 .dart_tool/build/entrypoint/build.dart 这个文件;
预编译部分:
在上面贴的generateAndRun办法中,生成文件之后就会履行一个 _createKernelIfNeeded
办法,其效果也正如其名,检测是否需求就创立内核文件;
而这个内核文件,也便是后缀为build.dart.dill 文件
同时,在这儿也说到了一个新的概念:assetGraph
,不过这些也是后边再细看的东西;
处理输入环境和资源
在编译完build脚本生成内核后,下面便是履行这个内核文件;在这儿新开了一个isolate去履行这个文件:
接下来就该看下这个内核文件到底是什么……但是呢,内核文件这东西,原本就不是给人看的………………所以呢,能够从另一方面考虑下,比如说,既然内核文件看不了,那我就看内核文件的从哪编译来的,反正逻辑上也是大差不差,彻底能够参阅;
正好内核文件的来历,也便是那个build脚本,其方位在上面也说到过了;在我测验代码中,它最终是这样的:
其间的这个_i10,正是build_runner……看来兜兜转转又回来了?
应该说回来了,但没彻底回来,上面说到的build_runner是bin目录下的;这次的build_runner是lib目录下的,进口还是不一样的;
在这儿,build_runner build中的build这个参数才真实辨认并开端履行;前面都是前戏;而履行这个build指令的是一个名为BuildCommandRunner
的类,其内部内置了包括build在内的诸多函数指令:
由于测验的指令参数为build,所以命中的commend为 BuildCommand
;而 BuildCommand 所做的事也根本会集在 src/generate/build.dart 这个文件中的build办法中了;自此开端真实去履行build_runner对应Builder中要求做的事;
其build办法所做的事还是比较简单看懂的:
- 装备环境(包括输入输出装备)
- 装备通用选项(build时分的装备项目)
- 调用BuildRunner.create创立Builder和生成所需数据,最终调用run履行;
而这部分所说的处理输入环境和资源就在 BuildRunner.create
这部分中;其会调用 BuildDefinition.prepareWorkspace
办法;
而在这儿就呈现了上面说到的assetGraph
,这儿便是其创立和运用的当地:
所以,最终总结一下,处理输入环境和资源 这个环节所做的事便是依据装备生成输入输出、build过程中所需的各种参数,提供assetGraph这个东西;
具体这些装备进口在哪,从何而来,assetGraph又是什么东西,有什么效果,后边再看;
正式履行builder生成代码
这部分便是刚才说到的调用run办法的当地;
它的run办法咋看如同也不难明的样子,主要是各种新名词有点多:
不过现在只跟随build流程来说的话,中心应该事其间的_safeBuild
办法:
其所做的事,除了各种心跳log之外,应该便是更新assetGraph;履行_runPhases
;另外究竟事safeBuild嘛,所以新开了一个zone来处理;
_runPhases
所做的事便是真实去履行build所做的事,生成代码之类的;比如说json_serializable中的build,就会走_runBuilder
部分并最终调用runBuilder
中的builder.build
,也便是自定义Builder中需求自己完成的部分;
对了,关于像json_serializable的自定义Builder从何而来的问题,答案是一开端就已经集成进来了,在builder.dart中已经呈现了其身影:
不过为什么build.dart 能得知具体有哪些builder?比如说json_serializable中的builder,是怎么加入到build.dart中的,那也是后边要看的东西;
缓存信息
再次回到 _safeBuild
这块,缓存信息的部分紧贴着run部分:
如同就写了一下文件,没了?
结语
这篇大体粗略的过了一下build这个指令都干了什么;不过像生成的文件内部结构、效果;装备信息来历,如何解析之类的问题还未解决;在后边会依次看看;
最终尝试完成一份自己的自定义Builder;