工作原理

FIS3 是基于文件对象进行构建的,每个进入 FIS3 的文件都会实例化成一个 File 对象,整个构建过程都对这个对象进行操作完成构建任务。以下通过伪码来阐述 FIS3 的构建流程。

构建流程

  1. fis.release = function (opt) {
  2. var src = fis.util.find(fis.project.root);
  3. var files = {};
  4. src.forEach(function (f) {
  5. var file = new File(f);
  6. files[file.subpath] = fis.compile(file);
  7. });
  8. var packager = fis.matchRules('::package');
  9. var keys = Object.keys(packager);
  10. var ret = {
  11. files: files,
  12. map: {}
  13. };
  14. if (packager.indexOf('prepackager') > -1) {
  15. pipe('prepackager', ret);
  16. }
  17. if (packager.indexOf('packager') > -1) {
  18. pipe('packager', ret);
  19. }
  20. files.forEach(function (f) {
  21. // 打包阶段产出的 map 表替换到文件
  22. if (f._isResourceMap) {
  23. f._content = f._content.replace(/\b__RESOURCE_MAP__\b/g, JSON.stringify(ret.map));
  24. }
  25. });
  26. if (packager.indexOf('spriter') > -1) {
  27. pipe('spriter', ret);
  28. }
  29. if (packager.indexOf('postpackager') > -1) {
  30. pipe('postpackager', ret);
  31. }
  32. }

如上述代码,整个 FIS3 的构建流程大体概括分为三个阶段。

  1. 扫描项目目录拿到文件并初始化出一个文件对象列表
  2. 对文件对象中每一个文件进行单文件编译
  3. 获取用户设置的 package 插件,进行打包处理(包括合并图片)

其中打包处理开了四个扩展点,通过用户配置启用某些插件。

  • prepackager 打包前处理插件扩展点
  • packager 打包插件扩展点,通过此插件收集文件依赖信息、合并信息产出静态资源映射表
  • spriter 图片合并扩展点,如 csssprites
  • postpackager 打包后处理插件扩展点

单文件编译流程

  1. fis.compile = function (file) {
  2. if (file.isFile()) {
  3. if (exports.useLint && file.lint) {
  4. pipe('lint', file);
  5. }
  6. if (!file.hasCache) {
  7. process(file);
  8. } else {
  9. file.revertCache();
  10. }
  11. } else {
  12. process(file);
  13. }
  14. };
  15. function process(file) {
  16. if (file.parser) {
  17. pipe('parser', file);
  18. }
  19. if (file.preprocessor) {
  20. pipe('preprocessor', file);
  21. }
  22. if (file.standard) {
  23. standard(file); // 标准化处理
  24. }
  25. if (file.postprocessor) {
  26. pipe('postprocessor', file);
  27. }
  28. if (file.optimizer) {
  29. pipe('optimizer', file);
  30. }
  31. }

其中插件扩展点包括:

  • lint:代码校验检查,比较特殊,所以需要 release 命令命令行添加 -l 参数
  • parser:预处理阶段,比如 less、sass、es6、react 前端模板等都在此处预编译处理
  • preprocessor:标准化前处理插件
  • standard:标准化插件,处理内置语法
  • postprocessor:标准化后处理插件

预处理阶段一般是对异构语言等进行预编译,如 less、sass 编译为标准的 css;前端模板被编译为 js 等等

单文件阶段通过读取文件属性,来执行对应扩展点插件。

举个例子:

  1. fis.match('*.es6', {
  2. parser: fis.plugin('babel'),
  3. rExt: '.js' // 代码编译产出时,后缀改成 .js
  4. });

给后缀是 .es6 的文件配置了一个 parser 属性,属性值是启用了一个叫 babel 的插件,当执行到预处理阶段时,将 es6 编译为 es5,供浏览器执行。

其他插件扩展点亦然。

File对象

  1. function File(filepath) {
  2. var props = path.info(filepath);
  3. merge(props, fis.matchRules(filepath)); // merge 分配到的属性
  4. assign(this, props); // merge 属性到对象
  5. }

当一个文件被实例化为一个 File 对象后,包括一些文件基本属性,如 filename、realpath 等等,当这个文件被处理时,FIS3 还会把用户自定义的属性 merge 到文件对象上。

比如

  1. fis.match('a.js', {
  2. myProp: true
  3. });

这样 a.js 处理的时候就会携带这个属性 myPropmyProp 是一个自定义属性,FIS3 默认内置了一些属性配置,来方便控制一个文件的编译流程,可参考配置属性

可能你会问,自定义属性到底有什么用,其实自定义属性可以标注一些文件,提供插件来做一些特定的需求。