作为前端开发,或多或少都会接触很多前端构建工具,最近的业务使用到了百度FIS团队的fis3,想和大家分享下我所理解的fis3。FIS3-前端工程构建工具官网
一.安装fis3
①.你需要安装node和npm:参考node安装
②.使用npm install -g fis3命令安装fis3
③.安装完成后执行 fis3 -v
判断是否安装成功,如果安装成功,则显示类似如下信息:
表示安装成功。
然后我们可以通过fis3 release -w来对代码进行监听。
注:fis3默认内置了fis3-command-release插件,提供了文件监听和浏览器自动刷新功能,在release的时候添加-w或-L参数就可以,这样可以很方便的部署代码。
当你需要使用插件的时候,可以用fis3 install -g 插件名 进行安装。
与其他构件工具一样,fis3也需要配置fis-conf.js文件。
添加MD5戳以及资源的合并压缩(配置useHash: true即可添加MD5戳)
//4.资源压缩:对文件进行压缩
// 清除其他配置,只保留如下配置
fis.match('*.js', {
// fis-optimizer-uglify-js 插件进行压缩,已内置
optimizer: fis.plugin('uglify-js')
});
fis.match('*.css', {
// fis-optimizer-clean-css 插件进行压缩,已内置
optimizer: fis.plugin('clean-css')
});
fis.match('*.png', {
// fis-optimizer-png-compressor 插件进行压缩,已内置
optimizer: fis.plugin('png-compressor')
});
CssSprite图片合并
//5.雪碧图
//(1)配置fis中使用csssprites
fis.config.set('modules.spriter','csssprites');
//(2)启用插件
fis.match('::packgae',{
sprite:fis.plugin('csssprites')
});
//(3)分配属性
fis.match('*.css',{
useSprite:true
});
对sass文件进行编译
//对sass文件进行编译
fis.match('**.{scss,sass}', {
parser: fis.plugin('sass',{
include_paths: ['modules/common/sass']
}),
rExt:'.css'
});
这样我们就可以使用基本的fis3了。
二.内置功能
fis3可以做到以下几点:
其主要功能基本都是围绕着前端开发所需要的三种编译能力:资源定位、内容嵌入、依赖声明。
1、资源定位:官网中很详细,这边就大概说下
(1)HTML中的资源定位
// 所有的 css
fis.match('**.css', {
//发布到/static/css/xxx目录下
release : '/static/css$0'
});
// 所有image目录下的.png,.gif文件
fis.match('/images/(*.{png,gif})', {
//发布到/static/pic/xxx目录下
release: '/static/pic/$1$2'
});
编译后
<img title="百度logo" src="/static/pic/logo_74e5229.gif"/>
<link rel="stylesheet" type="text/css" href="/static/css/demo_7defa41.css">
(2)js中的资源定位: __uri(path) 来定位资源,fis分析js文件或 html中的script标签内内容 时会替换该函数所指向文件的线上url路径。
var img = __uri('images/logo.gif');
var css = __uri('demo.css');
var js = __uri('demo.js');
编译后
var img = '/images/logo_74e5229.gif';
var css = '/demo_7defa41.css';
var js = '/demo_33c5143.js';
(3)css中的资源定位:识别css文件或 html的style标签内容 中 url(path) 以及 src=path 字段,并将其替换成对应资源的编译后url路径
@import url('seed.css');
编译后
@import url('/demo_7defa41.css');
2、内容嵌入
A,在html中可以嵌入其他文件内容或者base64编码值,可以在资源定位的基础上,给资源加 ?__inline 参数来标记资源嵌入需求。
<img title="百度logo" src="images/logo.gif?__inline"/>
<link rel="stylesheet" type="text/css" href="demo.css?__inline">
<script type="text/javascript" src="demo.js?__inline"></script>
<link rel="import" href="demo.html?__inline">//嵌入页面文件
编译后:
<img title="百度logo" src="data:image/gif;base64,R0lGODlhDgGBALMAAGBn6eYxLvvy9PnKyfO...gAgA7"/>
<style>img { border: 5px solid #ccc; }</style>
<script type="text/javascript">console.log('inline file');</script>
<!-- this is the content of demo.html -->
<h1>demo.html content</h1>
B,在js中嵌入资源:些处理对html中script标签里的内容同样有效。
__inline('demo.js');//在js中嵌入js文件
var img = __inline('images/logo.gif');
var css = __inline('a.css');//在js中嵌入其他文本文件
编译后:
console.log('demo.js content');
var img = 'data:image/gif;base64,R0lGODlhDgGBALMAAGBn6eYxLvvy9PnKyfO...jKc850nPeoYgAgA7';
var css = "body \n{ color: red;\n}";
C,在CSS中嵌入资源: 除了src="xxx"之外,都可以通过添加 ?__inline 编译标记都可以把文件内容嵌入进来。src="xxx"被用在ie浏览器支持的filter内,该属性不支持base64字符串,因此未做处理。
@import url('demo.css?__inline');//在css文件中嵌入其他css文件
.style {
background: url(images/logo.gif?__inline);//嵌入图片的base64
}
编译后:
img { border: 5px solid #ccc; };
.style {
background: url(data:image/gif;base64,R0lGODlhDgGBALMAAGBn6eYxLvvy9PnKyfO...nPeoYgAgA7);
}
3、依赖声明
FIS3 在执行编译的过程中,会扫描这些编译标记,从而建立一张 静态资源关系表,资源关系表详细记录了项目内的静态资源id、发布后的线上路径、资源类型以及 依赖关系 和 资源打包 等信息。使用 FIS3 作为编译工具的项目,可以将这张表提交给后端或者前端框架去运行时,根据组件使用情况来 按需加载资源或者资源所在的包,从而提升前端页面运行性能。
html中声明依赖。用户可以在html的注释中声明依赖关系,这些依赖关系最终会被记录下来,当某个文件中包含字符 RESOURCE_MAP 那么这个记录会被字符串化后替换 RESOURCE_MAP。 例如index.html中含有并且设置了useMap:
<!--
@require demo.js
@require "demo.css"
-->
//fis-conf.js
fis.match('*.html', {
useMap: true
})
// fis-conf.js
fis.match('*.html', {
useMap: true
});
fis.match('*.{js,css}', {
// 开启 hash
useHash: true
});
默认情况下,只有js和css文件会输出到,如果想将html文件加入表中,需要通过配置 useMap
让HTML文件加入 ,例如:
//fis-conf.js
fis.match('*.html', {
useMap: true
})
那么发布后会产生如下manifest.json文件:
{
"res" : {
"demo.css" : {
"uri" : "/static/css/demo_7defa41.css",
"type" : "css"
},
"demo.js" : {
"uri" : "/static/js/demo_33c5143.js",
"type" : "js",
"deps" : [ "demo.css" ]
},
"index.html" : {
"uri" : "/index.html",
"type" : "html",
"deps" : [ "demo.js", "demo.css" ]
}
},
"pkg" : {}
}
js/css文件中注释中的@require字段 标记的依赖关系,这些分析处理对 html的script标签内容同样有效。
//demo.js
/**
* @require demo.css
* @require list.js
*/
/**
* demo.css
* @require reset.css
*/
三.设计原理
fis3的设计原则是“基于依赖关系表的静态资源管理系统与模块化框架设计”,所以我们就从静态资源管理和模块化两方面来理解下fis3。
a.静态资源管理
关于性能优化是前端经久不衰的必须思考的问题,一个网站如果想要做到响应快高并发,那其中一个很有效的办法就是尽量让网站静态化。
做到动静分离。我们可以使用CDN技术,将静态资源保存在CDN上,可以用静态资源的CDN路径拉取到资源,减轻服务器的压力。fis3实现了一套“静态资源管理系统”,在开发页面的时候只需要用相对路径开发,构建后会生成带有hash静态资源版本号的文件,避免发布后页面错乱。
静态资源的大小也会影响网络传输效率,fis3也提供了很多插件来对图片进行合并、对HTML、js、css文件进行合并,fis3会对路径中带有?__sprite 的图片进行合并,减少了请求数量。
但单纯的资源合并是没有办法按需加载资源的,然而静态资源按需加载也是减少资源冗余的很重要的方式。使用fis3会生成静态资源映射表,是记录文件依赖等信息的表,虽然不会生成map.json,但当文件包含“__RESOURCE_MAP__”字符,就会用表结构数据替换这里的字符。静态资源系统可以根据表结构数据中对应对的信息进行加载。这样就解决了按需加载的问题。
b.模块化开发
前端模块化开发对开发人员来说具有很重要的意义,模块化可以方便代码复用,提升可维护性。
我们熟悉的模块化开发有commonjs、AMD、CMD,模块化框架有mod.js、require.js、sea.js等。
Fis3默认不支持模块化开发,所以需要fis3-hook-commonjs/fis3-hook-amd/fis3-hook-cmd、fis3-postpackager-loader以及fis3-deploy-wsd-cdn-upload插件的支持。
进行模块化开发首先安装npm install -g fis3-hook-module
fis.hook('module');
fis.hook('module', {
mode: 'amd' //这里支持amd和commonJs
});
fis.match('/module/*.js', {
isMod: true // 标记匹配文件为组件
});
四.配置fis-conf.js的流程:
1、使用fis3-postpackager-loader插件分析依赖
.match('::package', {
postpackager: [fis.plugin('loader', {
resourceType: 'mod',
obtainScript: false,
allInOne: true,
useInlineMap: true // 资源映射表内嵌
})]
})
2、合并资源
fis.media('dist')
.match('**.{js,tpl}', {
optimizer: fis.plugin('uglify-js'),
useHash: true
})
3、将静态资源发布到CDN
fis.match('**.{js,tpl}', {domain: 'http://xxx.com/xxx/xxx'
})
4、文件入口
<script>require('pages/xxx/main');</script>
5、js引用
var hello = require('./canvas.js');除了依赖声明内置语法中资源间相互依赖的语法,fis3还可以解析以下几种语法。
fis3可以综合处理各种资源的模块化,我们不用纠结于JavaScript模块化或是CSS模块化等单独资源的模块化,这样就可以提升开发体验,为性能优化提供良好的支持。这种一体化的模块化方案的目录划分与我们平常按照资源类型划分不同,其目录分为modules(子系统),包括common子系统(可为其他资源提供服务的通用模块)和业务子系统;page,我们实际输出的内容子系统,包含了各种资源的文件。一般来说,JS组件可以封装CSS组件的代码,template模块可以处理HTML、JavaScript和CSS等各种模块化资源。
在js中加载模块
define('pages/index/index', function(require, exports, module) {
var hello = require('pages/index/canvas');
});
在css中声明依赖关系
前端模块化需要将js、CSS和tpl同时都考虑进去,所以相对其他语言来说更加复杂。
拿commonJS举例,commonJS定义的模块有require(引入外部模块)、exports(导出当前模块的方法或变量)以及module(模块本身),只要能提供module、exports、require和global这四个变量,浏览器就能够加载CommonJS模块
构建后,文件会自动加上如下代码
define('pages/index/timeDegree-list-tmpl_tpl', function(require, exports, module) {
});
五.必须掌握命令行 fis3
fis3 release [-d path] //发布目录
fis3 install 插件名 //安装一个插件
fis3 init //初始化一个项目
fis3 server [start | stop | restart | open | info ] //内置服务器操作
fis3 inspect //比较实用的命令,用来查看文件 match 结果
六.最后
和fis3一样基于nodejs的构建工具有grunt、gulp等,那么fis3与这些热门工具对比有哪些区别呢?
就个人感受而言,grunt真的是太慢了,项目越大,构建时间就越慢,大大拖延了开发速度。grunt有三千多个插件可供选择。
gulp是轻量级的,定制性会更强,想要什么功能就装什么插件,但现有的插件并不一定能满足开发需求,所以可能也需要自己写插件,gulp插件的编写相对其他工具来说可能更方便。gulp有近七百个插件。gulp学习成本较低,只有五个API。
fis3相对来说并没有那么轻量,因此可以做的事情会比较多,所以整个项目都可以使用fis3。感觉fis3相比其他工具更着重性能优化方向。fis3现有可用插件有一千多个,基本足够我们开发使用,如果想要自己开发插件也是非常方便的。总体来说,fis3为前端开发带来了很多方便。
以下为同一个项目用这三种工具构建的结果:
grunt:
gulp:
fis3:
可见构建输出时间grunt>fis3>gulp,这只是我做的初步试验,具体选择哪种工具进行构建还需要开发人员仔细斟酌。
参考网站来自:http://www.alloyteam.com/2016/01/fis3-preliminary-learning-experiences/