FIS 源码-增量编译与依赖扫描细节
In 未分类 on 2015年05月11日 by view: 950
0

前面已经提到了 fis release 命令大致的运行流程。本文会进一步讲解增量编译以及依赖扫描的一些细节。

首先,在 fis release 后加上--watch 参数,看下会有什么样的变化。打开命令行

不难猜想,内部同样是调用 release()方法把源文件编译一遍。区别在于,进程会监听项目路径下源文件的变化,一旦出现文件(夹)的增、删、改,则重新调用 release()进行增量编译。

并且,如果资源之间存在依赖关系(比如资源内嵌),那么一些情况下,被依赖资源的变化,会反过来导致资源引用方的重新编译。

下面扒扒源码来验证下我们的猜想。

watch(opt) 细节

源码不算长,逻辑也比较清晰,这里就不上伪代码了,直接贴源码出来,附上一些注释,应该不难理解,无非就是重复文件变化–>release(opt)这个过程。

在下一小结稍稍展开下增量编译的细节。

增量编译细节

增量编译的要点很简单,就是只发生变化的文件进行编译部署。在 fis.release(opt, callback)里,有这段代码:

opt.afterEach(file, ret)这个回调方法可以在 fis-command-release/release.js 中找到。归纳下:

  1. 对比了下当前文件的最近修改时间,看下跟上次缓存的修改时间是否一致。如果不一致,重新编译,并将编译后的实例添加到 collection 中去。
  2. 执行 deploy 进行增量部署。(带着 collection 参数)

关于 deploy ,细节先略过,可以看到带上了 collection 参数。

依赖扫描概述

在增量编译的时候,有个细节点很关键,变化的文件,可能被其他资源所引用(如内嵌),那么这时,除了编译文件之身,还需要对引用它的文件也进行编译。

原先我的想法是:

  1. 扫描所有资源,并建立依赖分析表。比如某个文件,被多少文件引用了。
  2. 某个文件发生变化,扫描依赖分析表,对引用这个文件的文件进行重新编译。

看了下 FIS 的实现,虽然大体思路是一致的,不过是反向操作。从资源引用方作为起始点,递归式地对引用的资源进行编译,并添加到资源依赖表里。

  1. 扫描文件,看是否有资源依赖。如有,对依赖的资源进行编译,并添加到依赖表里。(递归)
  2. 编译文件。

从例子出发

假设项目结构如下,仅有 index.htmlindex.cc 两个文件,且 index.html 通过 __inline 标记嵌入 index.css

index.html 内容如下。

假设文件内容发生了变化,理论上应该是这样

  1. index.html 变化:重新编译 index.html
  2. index.css 变化:重新编译 index.css,重新编译 index.html

理论是直观的,那么看下内部是怎么实现这个逻辑的。先归纳如下,再看源码

  1. 对需要编译的每个源文件,都创建一个 Cache 实例,假设是 cache。cache 里存放了一些信息,比如文件的内容,文件的依赖列表 (deps 字段,一个哈希表,存放依赖文件路径到最近修改时间的映射)。
  2. 对需要编译的每个源文件,扫描它的依赖,包括通过__inline 内嵌的资源,并通过 cache.addDeps(file)添加到 deps 里。
  3. 文件发生变化,检查文件本身内容,以及依赖内容 (deps) 是否发生变化。如变化,则重新编译。在这个例子里,扫描 index.html,发现 index.html 本身没有变化,但 deps 发生了变化,那么,重新编译部署 index.html

好,看源码。在 compile.js 里面,cache.revert(revertObj)这个方法检测文件本身、文件依赖的资源是否变化。

看看 cache.revert 是如何定义的。大致归纳如下,源码不难看懂。至于 infos.deps 这货怎么来的,下面会立刻讲到。

  1. 方法的返回值:缓存没过期,返回 true;缓存过期,返回 false
  2. 缓存检查步骤:首先,检查文件本身是否发生变化,如果没有,再检查文件依赖的资源是否发生变化;

依赖扫描细节

之前多次提到 deps 这货,这里就简单讲下依赖扫描的过程。还是之前 compile.js 里那段代码。归纳如下:

  1. 文件缓存不存在,或者文件缓存已过期,进入第二个处理分支
  2. 在第二个处理分支里,会调用 process(file)这个方法对文件进行处理。里面进行了一系列操作,如文件的 “标准化” 处理等。在这个过程中,扫描出文件的依赖,并写到 deps 里去。

下面会以 “标准化” 为例,进一步讲解依赖扫描的过程。

process 里,对文件进行了标准化操作。什么是标准化,可以参考官方文档。就是下面这小段代码

看下 standard 内部是如何实现的。可以看到,针对类 HTML、类 JS、类 CSS,分别进行了不同的能力扩展(包括内嵌)。比如上面的 index.html,就会进入 extHtml(content)。这个方法会扫描 html 文件的__inline 标记,然后替换成特定的占位符,并将内嵌的资源加入依赖列表。

比如,文件的<link href="index.css?__inline" /> 会被替换成 <style type="text/css"><<<embed:"index.css?__inline">>>

然后,在 content.replace 里面,将进入 embed 这个分支。从源码可以大致看出逻辑如下,更多细节就先不展开了。

  1. 首先对内嵌的资源进行合法性检查,如果通过,进行下一步
  2. 编译内嵌的资源。(一个递归的过程)
  3. 将内嵌的资源加到依赖列表里。

写在后面

更多内容,敬请期待。

文章: casperchen

原创文章转载请注明:

转载自AlloyTeam:http://www.alloyteam.com/2015/05/fis%e6%ba%90%e7%a0%81-%e5%a2%9e%e9%87%8f%e7%bc%96%e8%af%91%e4%b8%8e%e4%be%9d%e8%b5%96%e6%89%ab%e6%8f%8f%e7%bb%86%e8%8a%82/

发表评论