FIS3前端工程构建工具
Gulp和Webpack特点对比
Gulp
Gulp侧重于前端开发的整个过程的控制管理(像是流水线),Gulp是对整个过程进行控制,所以在其配置文件(gulpfile.js)中配置的每一个task对项目中该task配置路径下所有的资源都可以管理,我们可以通过给gulp配置不通的task(通过Gulp中的gulp.task()方法配置,比如启动server、sass/less预编译、文件的合并压缩等等)来让gulp实现不同的功能,从而构建整个前端开发流程。
Webpack
Webpack有人也称之为 模块打包机 ,由此也可以看出Webpack更侧重于模块打包,当然我们可以把开发中的所有资源(图片、js文件、css文件等)都可以看成模块,最初Webpack本身就是为前端JS代码打包而设计的,后来被扩展到其他资源的打包处理。Webpack是通过loader(加载器)和plugins(插件)对资源进行处理的。
imageFIS3
集合了webpack的根据依赖关系进行模块打包的能力,同时也保留了对项目每个文件的可自定义编译能力。
FIS3 是以 File 对象为中心构建编译的,每一个 File 都要经历编译、打包、发布三个阶段。
imagelint:代码校验检查,校验代码是否存在错误。
parser:预处理阶段,比如 less、sass、es6、react 前端模板等都在此处预编译处理
preprocessor:标准化前处理插件
standard:标准化插件,处理内置语法等
postprocessor:标准化后处理插件
optimizer:启用优化处理插件,js、css代码压缩等
FIS3命令
release
编译发布一个 FIS3 项目
命令有参数:
-h, --help 参数可以看帮助信息
-d、--dest 编译产出到一个特定的目录
fis3 release -d ./output
-l, --lint 启用文件格式检测
-w、--watch 启动文件监听
-L、--live 启动 livereload 功能,livereload 功能应该跟 watch 功能一起使用(-w 在开启 liveload 的前提下,自动开启),当某文档做了修改时,会自动刷新页面。
-c, --clean 清除编译缓存
fis3 release -c
默认 fis 的每次编译都会检测编译缓存是否有效,如果有效 fis 是不会重复编译的。开启此选项后,fis 编译前会做一次缓存清理。
install
用来从组件平台中下载组件到当前项目中,并自动下载其依赖
init
fis3 脚手架工具,用来快速初始化项目
在 fis-scaffold机构中的库都可以通过 fis3 init ${模板名称}
来初始化到当前目录。当不指定模板名称时,fis3 会使用 defaul 作为模板用来初始化。
server
fis3 内置的小型 web serve
可以通过 fis3 server start 快速开启。如果一切正常,开启后它将自动弹出浏览器打开 http://127.0.0.1:8080/。
需要说明的是,fis3 自带的 server 默认是通过 java 内嵌 jetty 然后桥接 php-cgi 的方式运行的。所以,要求用户机器上必须安装有 jre 和 php-cgi 程序。
inspect
用来查看文件 match 结果。如下所示,将列出项目中所有文件,并显示该文件有哪些属性及属性值,以及该属性是源于哪个 fis.match 配置。
fis3 inspect
[INFO] Currently running fis3 (/usr/local/lib/node_modules/fis3/)
~ /README.md
-- useHash false `*` (0th)
~ /comp/1-0/1-0.js
-- useHash false `*` (0th)
-- isMod true `/comp/**/*.js` (1th)
-- release /static/comp/1-0/1-0.js `/comp/**/*.js` (1th)
~ /comp/2-0/2-0.js
-- useHash false `*` (0th)
-- isMod true `/comp/**/*.js` (1th)
-- release /static/comp/2-0/2-0.js `/comp/**/*.js` (1th)
FIS3基础应用
fis.match()
fis.match(selector, props);
FIS3 把匹配文件路径的路径作为selector,匹配到的文件会分配给它设置的 props。
捕获分组:
使用 node-glob 捕获的分组,可以用于其他属性的设定,如 release, url, id 等。使用的方式与正则替换类似,我们可以用 2, 0 代表的是 match 到的整个字符串。
fis.match('/a/(**.js)', {
release:'/b/$0'// $0 代表 /a/(**.js) 匹配的内容});
});
fis.match('/a/(**.js)', {
release: '/b/$1' // $1 代表 (**.js) 匹配的内容
});
特殊用法:
1、 ::package 用来匹配 fis 的打包过程。
2、::text 用来匹配文本文件 ['css', 'tpl', 'js', 'php' , ........]。
如果你希望命中的文件类型不在列表中,请通过 fis.set('project.fileType.text') 扩展,多个后缀用 , 分割
fis.set('project.fileType.text', 'cpp,hhp');
3、::image 用来匹配文件类型为图片的文件['svg', 'tif', 'tiff', 'wbmp', ...........]。
如果你希望命中的文件类型不在列表中,请通过 fis.set('project.fileType.image') 扩展,多个后缀用 , 分割。
fis.set('project.fileType.image', 'raw,bpg');
4、*.html:js 用来匹配命中的 html 文件中的内嵌的 js 部分。
fis3 htmlLike 的文件内嵌的 js 内容也会走单文件编译流程,默认只做标准化处理,如果想压缩,可以进行如下配置。
fis.match('*.html:js', {
optimizer: fis.plugin('uglify-js')
});
5、*.html:css 用来匹配命中的 html 文件中内嵌的 css 部分。
fis.match('*.html:css', {
optimizer: fis.plugin('clean-css')
});
重要特性:规则覆盖
假设有两条规则 A 和 B,它俩同时命中了文件 test.js,如果 A 在 B 前面,B 的属性会覆盖 A 的同名属性。不同名属性追加到 test.js 的 File 对象上。
// A
fis.match('*', {
release: '/dist/$0'
});
// B
fis.match('test.js', {
useHash: true,
release: '/dist/js/$0'
})
那么 test.js 分配到的属性
{
useHash: true, // B
release: '/dist/js/$0' // B
}
.
fis.media()
fis.media() 接口提供多种状态功能,比如有些配置是仅供开发环境下使用,有些则是仅供生产环境使用的。
fis.match('*', {
useHash: false
});
fis.media('dev').match('*.js', {
useHash:true,
optimizer: fis.plugin('uglify-js')
});
fis3 release dev
.
.
FIS3 全局属性
全局属性通过 fis.set 设置,通过 fis.get 获取;
内置的默认配置
var DEFAULT_SETTINGS = {
project: {
charset: 'utf8',
md5Length: 7,
md5Connector: '_',
files: ['**'],
ignore: ['node_modules/**', 'output/**', '.git/**', 'fis-conf.js'],
fileType: {
text: ['css', 'tpl', 'js', 'php', 'txt', ...],
image : ['svg', 'tif', 'tiff', 'wbmp', 'png', ...]
}
}
options: {}
}
.
文件属性
release
解释:设置文件的产出路径。默认是文件相对项目根目录的路径,以 / 开头。该值可以设置为 false ,表示为不产出文件。
值类型:string
默认值:无
fis.match('/widget/{*,**/*}.js', {
release: '/static/$0'
});
packTo
解释:分配到这个属性的文件将会合并到这个属性配置的文件中
值类型:string
默认值:无
fis.match('/widget/{*,**/*}.js', {
packTo: '/static/pkg_widget.js'
})
packOrder
解释:用来控制合并时的顺序,值越小越在前面。配合 packTo 一起使用。
值类型:Integer
默认值:0
fis.match('/*.js', {
packTo: 'pkg/script.js'
})
fis.match('/mod.js', {
packOrder: -100
})
id
解释:指定文件的资源id。默认是 namespace + subpath 的值
值类型:string
默认值:namespace + subpath
fis.match('/static/lib/jquery.js', {
id: 'jquery',
isMod: true
});
var $ = require('jquery');
url
- 解释:指定文件的资源定位路径,以 / 开头。默认是 release的值,url可以与发布路径 release 不一致。
- 值类型:
string
- 默认值:无
fis.match('*.{js,css}', {
release: '/static/$0',
url: '/static/new_project/$0'
})
charset
解释:指定文本文件的输出编码。默认是 utf8,可以制定为 gbk 或 gb2312等。
值类型:string
默认值:无
useHash
解释:文件是否携带 md5 戳
值类型:bool
默认值:false
fis.match('*.css', {
useHash: false
});
fis.media('prod').match('*.css', {
useHash: true
});
domain
解释:给文件 URL 设置 domain 信息
值类型:string
默认值:无
fis.media('prod').match('*.js', {
domain: 'http://cdn.baidu.com/'
});
rExt
解释:设置最终文件产出后的后缀
值类型:string
默认值:无
fis.match('*.less', {
rExt: '.css'
});
useMap
解释:文件信息是否添加到 map.json
值类型:bool
默认值:无
说明: 分配到此属性的资源出现在静态资源表中,现在对 js、css 等文件默认加入了静态资源表中;
isMod
解释:标示文件是否为组件化文件。
值类型:bool
默认值:无
说明:标记文件为组件化文件。被标记成组件化的文件会入map.json表。并且会对js文件进行组件化包装。
fis.match('/widget/{*,**/*}.js', {
isMod: true
});
useCompile
注释: FIS是否对文件进行编译
值类型:bool
默认值: true
说明:设置为 false 后文件会通过FIS发布,但是FIS不对文件做任何修改
.
插件属性
lint
启用 lint 插件进行代码检查
fis.match('*.js', {
lint: fis.plugin('js', {
})
})
parser
fis.match('*.less', {
parser: fis.plugin('less'), //启用fis-parser-less插件
rExt: '.css'
});
preprocessor
标准化前处理
fis.match('*.{js,es,es6,jsx,ts,tsx}', {
preprocessor: fis.plugin('js-require-css')
})
fis.match('*.{js,es,es6,jsx,ts,tsx}', {
preprocessor: fis.plugin('js-require-file')
})
standard
标准化处理,处理内置语法等
postprocessor
标准化处理后
fis.match('*.{js,tpl}', {
postprocessor: fis.plugin('require-async')
});
optimizer
启用优化处理插件,并配置其属性
fis.match('*.css', {
optimizer: fis.plugin('clean-css')
});
fis.match('*.png', {
optimizer: fis.plugin('png-compressor')
})
fis.match('{*.js,*.vm:js,*.html:js}', {
// js 压缩;
optimizer: fis.plugin('uglify-js', {
})
})
打包阶段插件
打包阶段插件设置时必须分配给所有文件,设置时必须 match ::package,不然不做处理。
prepackager
解释:打包预处理插件
值类型:Array | fis.plugin | function
默认值:无
用法:
fis.match('::package', {
prepackager: fis.plugin('plugin-name')
})
packager
解释:打包插件
值类型:Array | fis.plugin | function
默认值:无
用法:
fis.match('::package', {
packager: fis.plugin('map'),
});
spriter
解释:打包后处理csssprite的插件。
值类型:Array | fis.plugin | function
默认值:无
用法:
fis.match('::package', {
spriter: fis.plugin('csssprites')
})
// 对 CSS 进行图片合并
fis.match('*.css', {
// 给匹配到的文件分配属性 `useSprite`
useSprite: true
});
li.list {
background-image: url('./img/list-1.png?__sprite');
}
postpackager
解释:打包后处理插件。
值类型:Array | fis.plugin | function
默认值:无
deploy
解释:设置项目发布方式
值类型:Array | fis.plugin | function
默认值:fis.plugin('local-deliver')
用法:假设项目开发完后,想部署到其他机器上,我们选择 http 提交数据的方式部署
fis.match('**', {
deploy: fis.plugin('http-push', {
receiver: 'http://target-host/receiver.php', // 接收端
to: '/home/work/www' // 将部署到服务器的这个目录下
})
})
常用插件
- local-deliver
FIS 默认的部署插件,提供本地部署
fis.match('*.js', {
deploy: fis.plugin('local-deliver', {
to: './output'
})
})
- http-push
FIS 默认的部署插件,提供本地部署以及远程upload部署能力。
fis.match('*.js', {
deploy: fis.plugin('http-push', {
//如果配置了receiver,fis会把文件逐个post到接收端上
receiver: 'http://www.example.com:8080/receiver.php',
//这个参数会跟随post请求一起发送
to: '/home/fis/www',
// 附加参数, 后端通过 $_POST['xx'] 获取
// 如果 data 中 含有 to 这个 key, 那么上面那个to参数会覆盖掉data里面的to
data: {
token : 'abcdefghijk',
user : 'maxming',
uid : 1
}
})
})
- replace
内容替换插件 npm install [-g] fis3-deploy-replace
deploy: [
fis.plugin('replace', {
from: 'from/string',
to: 'to/string'
}),
fis.plugin('local-deliver') //must add a deliver, such as http-push, local-deliver
]
- deploy-tar
将产出文件,打包成 tar 文件。
.match('/*/(**.{js,scss,css})',{
deploy: [
fis.plugin('tar',{
filename: 'plus-h5.static.tar.gz'
}),
fis.plugin('local-deliver', {
to: './'
})
]
})
- hook-commonjs
CommonJs 模块化支持插件。
fis.hook('commonjs')
- fis3-hook-amd
- fis3-hook-cmd
FIS3嵌入资源
嵌入资源即内容嵌入,可以为工程师提供诸如图片base64嵌入到css、js里,前端模板编译到js文件中,将js、css、html拆分成几个文件最后合并到一起的能力。有了这项能力,可以有效的减少http请求数,提升工程的可维护性。 fis不建议用户使用内容嵌入能力作为组件化拆分的手段,因为声明依赖能力会更适合组件化开发。
在html中嵌入资源
在html中可以嵌入其他文件内容或者base64编码值,可以在资源定位的基础上,给资源加 ?__inline 参数来标记资源嵌入需求。
- html中嵌入图片base64
<img title="百度logo" src="images/logo.gif?__inline"/>
<img title="百度logo" src="data:image/gif;base64,R0lGODlhDgGBALMAAGBn6eYxLvvy9PnKyfO...Jzna6853wjKc850nPeoYgAgA7"/>
- html中嵌入样式文件和脚本
<link rel="stylesheet" type="text/css" href="demo.css?__inline">
<style>img { border: 5px solid #ccc; }</style>
<script type="text/javascript" src="demo.js?__inline"></script>
<script type="text/javascript">console.log('inline file');</script>
- html中嵌入页面文件
<link rel="import" href="demo.html?__inline">
.
在js中嵌入资源
js css 同上
- 在js中嵌入图片
var img = __inline('images/logo.gif');
var img = 'data:image/gif;base64lhDgGBALBn6eY9PnKyfO...Jzna6853wjKc850nPeoYgAgA7';
var img = __uri("../../common/img/okay_logo.png");
var img = "http://dev-plusappi.xk12.cn/common/img/okay_logo.png";
在css中嵌入资源
- 在css文件中嵌入其他css文件
@import url('demo.css?__inline');
.
预处理插件编写
假设给定项目中要是用 es6,线上运行时解析成标准 js 性能堪忧,想用自动化工具进行预处理转换。如原理介绍 parser 阶段就是进行归一化的过程,通过预处理阶段,整个文件都会翻译为标准的文件,即浏览器可解析的文件,这里我们选择使用babel编译es6。
准备
.es6 后缀最终变为 .js
使用 babel 进行 es6 的转换
FIS3 实现一个 parser 类型的插件,取名叫 translate-es6,插件全名 fis3-parser-translate-es6
开发插件
FIS3 支持 local mode 加载一个插件。当你调用一个插件的时候,配置如下:
{
parser: fis.plugin('translate-es6')
}
如果项目的根目录 node_modules 下有这个插件,就能挂载起来。
my-proj/node_modules/fis3-parser-translate-es6/index.js
// babel node.js api 只有 babel-core 不能完成翻译
// babel-core 需要安装依赖 babel-preset-es2015
// 参考: 阮一峰的es6入门 http://es6.ruanyifeng.com/#docs/intro
var babel = require('babel-core');
module.exports = function (content, file, options) {
var result = babel.transform(content, opts);
return result.code; // 处理后的文件内容
}
配置使用
fis.match('*.es6', {
parser: fis.plugin('translate-es6', {
presets: ['es2015']
}),
rExt: '.js' // .es6 最终修改其后缀为 .js
})