FIS 插件机制
FIS 插件机制
author: @TiffanysBear
当我们使用 FIS 插件的时候,有没有想过自己也开发一个基于 FIS 的插件,参与 FIS 打包编译的整个流程;那么问题就来了:
- FIS 的编译过程运行原理是怎样的呢?
- FIS 编译打包的过程有哪些?
- 怎么参与FIS 的打包编译过程?
- 怎么实现一个基于FIS的插件?
- FIS 是怎么引入自定义插件的?
基于以下的问题,从原理再进行慢慢分析,了解 FIS 编译的基本流程和原理,以及如何自己自定义一个 FIS 插件。
编译过程运行原理
fis的编译过程可以分为两个阶段: 单文件编译 和 打包。处理流程如下图,图片来自 FIS 官网:
[图片上传失败...(image-e08187-1566795911500)]
单文件编译过程
从图上可以看出,单文件编译过程都是通过pipe管道进行的,并且在最初都建立有缓存,以提升编译效率,在单文件的处理过程中,又主要分为了以下的几个步骤:
- parser(编译器):将其他语言编译为标准js、css,比如将前端模板、coffee-> script编译为js,将less、sass编译为css。
- preprocessor(标准预处理器):在fis进行标准化处理之前进行某些修改,比如 支持image-set语法的预处理插件
- standard(标准化处理):前面两项处理会将文件处理为标准的js、css、html语法,fis内核的标准化处理过程对这些语言进行 三种语言能力 扩展处理。这也就意味着,使用less、coffee等语法在fis系统中一样具备 资源定位、内容嵌入,依赖声明 的能力。该过程 不可扩展。
- postprocessor(标准后处理器):对文件进行标准化之后的处理,比如利用依赖声明能力实现的 js包装器插件,可以获取js文件的依赖关系,并添加define包装。
- lint(可选)(校验器):代码校验阶段,使用 fis release命令的 --lint 参数会调用该过程。
- test(可选)(测试器):自动测试阶段,使用 fis release命令的 --test 参数会调用该过程。
- optimize(可选)(优化器):代码优化阶段,使用 fis release命令的 --optimize 参数会调用该过程。fis内置的fis-optimizer-uglify-js插件和fis-optimizer-clean-css插件都是这类扩展。
打包过程
如果是文件的简单合并,可以使用 __inline 进行简单的内容嵌入,如果嵌入的内容中需要实时嵌入动态变量,可以考虑使用 bdtmpl 进行前端模块的编译和转换。
打包的原理是通过 FIS 的pack 配置,对文件资源进行合并等操作,最后产出关于文件打包信息到 map.json 文件中,并产生相应的打包文件。所以 FIS 的打包结果并 不会再嵌入到某个文件内,而是利用map.json中的数据进行运行时打包信息查询。
一、 在fis-conf.js中配置:
fis.config.merge({
pack : {
'aio.js' : ['a.js', 'b.js', 'c.js']
}
});
二、 执行命令 fis release --pack --dest ./output
三、 进入output目录,查看map.json文件,得到内容:
{
"res" : {
"a.js" : {
"uri" : "/a.js",
"type" : "js",
"pkg" : "p0"
},
"b.js" : {
"uri" : "/b.js",
"type" : "js",
"pkg" : "p0"
},
"c.js" : {
"uri" : "/c.js",
"type" : "js",
"pkg" : "p0"
}
},
"pkg" : {
"p0" : {
"uri" : "/aio.js",
"type" : "js",
"has" : ["a.js", "b.js", "c.js"]
}
}
}
四、 将map.json交给某个前端或后端框架,当运行时需要“a.js”资源的时候,该框架应该读取map.json的信息,并根据一定的策略决定是否应该返回“a.js”资源所标记的“p0”包的uri。
因此也可以看出,FIS 团队强调的一点,打包只是资源的备份。
fis系统的打包过程提供了4个可扩展的处理过程,它们是:
- prepackager(打包预处理器):在打包前进行资源预处理。
- packager(打包处理器):对资源进行打包。默认的打包器就是收集资源表,建立map.json的过程
- spriter(csssprite处理器):对css进行sprites化处理
- postpackager(打包后处理器):打包之后对文件进行处理,通常用来将map.json转换成其他语言的文件,比如php
插件调用机制
fis的插件也是一个npm包,利用fis.require函数来加载。当我们在fis系统中加载一个插件的时候,会利用 nodejs的require向上查找机制 从 fis-kernel 模块出发,向上查找所需模块。
fis插件系统巧妙的利用了nodejs的require机制来实现其扩展机制。这意味着,要想扩展fis可以有 三种途径 :
1、使用fis的用户,自己需要某种插件,可以在fis安装目录的 同级,安装自己扩展的插件。比如: npm install -g fis npm install -g fis-parser-coffee-script
2、使用 FIS 内置的插件,目前已经内置的插件包括:
- fis-kernel:fis编译机制内核
- fis-command-release:fis release命令的提供者,处理编译过程,并提供文件监听、自动上传等功能
- fis-command-install:fis install命令的提供者,用于从fis仓库下载组件、配置、框架、素材等资源
- fis-command-server:fis server命令的提供者,用于开启一个本地php-cgi服务器,对项目进行预览、调试。
- fis-optimizer-uglify-js:fis的优化插件,调用uglify-js对文件内容进行js压缩。
- fis-optimizer-clean-css:fis的优化插件,调用clean-css对文件内容进行css压缩。
- fis-postprocessor-jswrapper:fis的后处理器插件,用于对js文件进行包装,支持amd的define包装或者匿名自执行函数包装。
3、开发一个依赖于fis模块的npm包,并在这个包里定制所需要的插件。这种方式与上一条类似,也是将插件安装在fis的同级目录下。
可扩展时机
在整个编译流程可以扩展的点有以下,也就说说我们自己自定义的插件可以在下列的时机进行自己需求的定制,通过回调获取该阶段编译的结果,进行自定义配置。
编译阶段:
- parser
- preprocessor
- postprocessor
- lint
- test
打包阶段:
- prepackager
- packager
- spriter
- postpackager
自定义插件
自定义插件需要的,需要封装一个npm包,结合上面的可扩展时机,命名规则一般为:fis-[需要插入的时机名称]-[自定义插件名],例如:fis-parse-my-css;
编译阶段插件
1、在自定义插件的index.js中:
/*
* fis
* http://fis.baidu.com/
*/
'use strict';
var sass = require('node-sass');
module.exports = function(content, file, settings) {
// content: 内容
// file: 文件
// settings: 现在的配置
var opts = fis.util.clone(settings);
opts.data = content;
return sass.renderSync(opts);
};
2、插件配置调用
在fis-config.js中调用格式如下:
// vi fis-conf.js
// 文件后缀 .scss 的调用插件 my-sass 进行解析
fis.config.set('modules.parser.scss', 'my-sass');
fis.config.set('settings.parser.my-sass', {
// my-sass 的配置
});
fis.config.set('roadmap.ext.scss', 'css'); // 由于 scss 文件最终会编译成 css,设置最终产出文件后缀为 css
3、发布npm包,这个可以参考我之前写过的一个文档,从0到1发布一个npm包
打包阶段插件
1、插件接口如此:
/**
* 打包阶段插件接口
* @param {Object} ret 一个包含处理后源码的结构
* @param {Object} conf 一般不需要关心,自动打包配置文件
* @param {Object} settings 插件配置属性
* @param {Object} opt 命令行参数
* @return {undefined}
*/
module.exports = function (ret, conf, settings, opt) {
// ret.src 所有的源码,结构是 {'<subpath>': <File 对象>}
// ret.ids 所有源码列表,结构是 {'<id>': <File 对象>}
// ret.map 如果是 spriter、postpackager 这时候已经能得到打包结果了,
// 可以修改静态资源列表或者其他
}
以prepackager插件为例。prepackager即打包前需要对文件做某些处理,比如想在所有的html注释里面插入编译时间。
2、插件开发
我们为这个插件取名叫 append-build-time
<npm/global/path>/fis-prepackager-append-build-time
<npm/global/path>/fis-prepackager-append-build-time/index.js
在其 index.js 中:
module.exports = function(ret, conf, settings, opt) {
fis.util.map(ret.src, function(subpath, file) {
if (file.isHtmlLike) {
var content = file.getContent();
content += '<!-- build '+ (new Date())+'-->';
file.setContent(content);
}
});
};
3、配置使用
// vi fis-conf.js
fis.config.set('modules.prepackager', 'append-build-time'); // packager阶段插件处理所有文件,所以不需要给某一类后缀的文件设置。
fis.config.set('settings.prepackager.append-build-time', {
// settings
})
4、发布npm包,这个可以参考我之前写过的一个文档,从0到1发布一个npm包
小提示:
当然为了更快速的搞定一些小需求,可以把插件功能直接写到配置文件 fis-conf.js 中;
// vi fis-conf.js
fis.config.set('modules.postprocessor.js', function (content) {
return content += '\n// build time: ' + Date.now();
});
注意:配置使用插件时,同一个扩展点可以配置多个插件,比如;
// 调用 fis-prepackager-a, fis-prepackager-b ...插件
fis.config.set('modules.prepackager', 'a,b,c,d');
// or
fis.config.set('modules.prepackager', ['a', 'b', 'c', 'd']);
// or
fis.config.set('modules.prepackager', [function () {}, function () {}])
具体的原理和封装步骤就讲到这么多,具体封装解决方案可以见 FIS 的官网 —— 封装解决方案
本文参考文档:
1、插件扩展点列表 http://fex-team.github.io/fis-site/docs/more/extension-point.html
2、插件调用机制 http://fex-team.github.io/fis-site/docs/more/how-plugin-works.html
3、编译过程运行原理 http://fex-team.github.io/fis-site/docs/more/fis-base.html
FIS 插件机制的更多相关文章
- 【学】jQuery的源码思路6——增加each,animaion,ajax以及插件机制
each() 插件机制 animation ajax //each() //这里第一个参数指定将this指向每次循环到的那个元素身上,而第三个参数element其实就是this本身所以和第一个参数是一 ...
- ImitateLogin新增插件机制以及又一个社交网站的支持
我的文章里已经多次介绍 imitate-login ,这是我最近一直在维护的一个使用c#模拟社交网站登录的开源项目,现在新增了对插件的支持以及一个新的网站(由于某种原因,会在文章结束部分介绍:而且仅会 ...
- Maven生命周期和插件机制
Maven中的一个非常重要的概念是生命周期和插件,这篇文章重点介绍下Maven的生命周期. Maven的生命周期是抽象的,具体的功能是有具体的插件来完成的,Maven有相当多的功能插件,以至于Mave ...
- php中的钩子(hook插件机制)
对"钩子"这个概念其实不熟悉,最近看到一个php框架中用到这种机制来扩展项目,所以大概来了解下. hook插件机制的基本思想: 在项目代码中,你认为要扩展(暂时不扩展)的地方放置一 ...
- winform插件机制学习
这两天在看自定义控件,原来有太多知识没有掌握.今天看到插件机制,心里突然一亮,这个东西听了不少次,就是不知道是啥回事.这次有幸书里包含一个案例,我就跟着它一步步来.终于知道是什么回事了.这个应该在软件 ...
- [转]仿World Wind构造自己的C#版插件框架——WW插件机制精简改造
很久没自己写东西啦,早该好好总结一下啦!一个大师说过“一个问题不应该被解决两次!”,除了一个好脑筋,再就是要坚持总结. 最近需要搞个系统的插件式框架,我参照World Wind的插件方式构建了个插件框 ...
- WordPress 插件机制的简单用法和原理(Hook 钩子)
WordPress 的插件机制实际上只的就是这个 Hook 了,它中文被翻译成钩子,允许你参与 WordPress 核心的运行,是一个非常棒的东西,下面我们来详细了解一下它. PS:本文只是简单的总结 ...
- 微信开发学习日记(八):7步看懂weiphp插件机制,核心目标是响应微信请求
又经过了几个小时的梳理.回顾,截至目前,终于对weiphp这个框架的机制搞明白了些.想要完全明白,自然还需要大把的时间.第1步: 配置微信公众号,http://weiphp.jiutianniao ...
- typecho流程原理和插件机制浅析(第二弹)
typecho流程原理和插件机制浅析(第二弹) 兜兜 393 2014年04月02日 发布 推荐 1 推荐 收藏 14 收藏,3.7k 浏览 上一次说了 Typecho 大致的流程,今天简单说一下插件 ...
随机推荐
- vijos p1304 回文数
N进制下的加法 2/10/16进制下,char到int的转换 #include<iostream>#include<string>using namespace std;str ...
- C#程序从Excel表格中读取数据并进行处理
今天做了一个Excel表格数据处理的事情,因为数据量表较大(接近7000条)所以处理起来有点麻烦,于是写了一个程序, 先将程序记下以便将来查找. using System; using System. ...
- webstorm mac 版破解
一.打开终端,输入: sudo vim /etc/hosts 回车后输入密码,编辑 hosts 文件,如图: 二.进入编辑模式(按 i 键),在最后一行添加如下代码: 0.0.0.0 account. ...
- 如何实现Excel多人共享与协作
1.写在前面的话 本人从事信息化工作多年,对Excel等电子表格的多人共享与协作接触较早,帮助客户实施的方案也较多,因此有些体会和认识.正好看到网上这方面的讨论较多,但都不完整,我就进一步做了专题调研 ...
- java往文本文件中写入信息并修改
题目要求: 1.可以往一个文本文档中写入员工信息:name,id和详情 2.可以更改name package FanCQ.Xue.practice; import java.io.*;import j ...
- PHP验证身份证格式
互联网公司对身份证验证的需求越来越多,然而普通的小公司是无法对接公安部门的身份认证系统的.几乎都是在网上买一些大的互联网公司的一些认证服务.即使是便宜一些的认证价格也达到了10万次/万元.也就是一角钱 ...
- 接口测试时遇到 java 代码加密请求数据,用 python 的我该怎么办?
前言 自动化测试应用越来越多了,尤其是接口自动化测试. 在接口测试数据传递方面,很多公司都会选择对请求数据进行加密处理. 而目前为主,大部分公司的产品都是java语言实现的.所以加密处理也是java实 ...
- Java编程思想之十七 容器深入研究
17.1 完整的容器分类方法 17.2 填充容器 import java.util.*; class StringAddress { private String s; public StringAd ...
- Windows下安装python2与python3以及分别对应的virtualenv
第三次装python2与python3 除此之外还学会了如何在命令行复制代码1.单击右键2.菜单中选择标记3.按住左键选中需要复制的内容4.松开左键5.单击右键 全局中python版本为python2 ...
- (转)Linux LVM逻辑卷配置过程详解(创建、扩展、缩减、删除、卸载、快照创建)
一.预备知识 LVM全称为Logical Volume Manager 逻辑卷管理器,LVM是Linux环境中对磁盘分区进行管理的一种机制,是建立在硬盘和分区之上.文件系统之下的一个逻辑层,可提高磁盘 ...