憋了好久,还是决定写下这篇博客,fis3是自动化的构建工具而已,它的构建不会修改源码,而是会通过用户设置,将构建结果输出到指定的目录。下面我们来谈下怎么配置fis3的(怎么安装这里就不说了)
1.fis3工作流程
FIS3 是基于文件对象进行构建的,每个进入 FIS3 的文件都会实例化成一个 File 对象,整个构建过程都对这个对象进行操作完成构建任务。
整个 FIS3 的构建流程大体概括分为三个阶段。
1.扫描项目目录拿到文件并初始化出一个文件对象列表
2.对文件对象中每一个文件进行单文件编译
3.获取用户设置的 package 插件,进行打包处理(包括合并图片)
对于第2点,对每个单文件编译又包括以下过程:
1.初始化阶段lint:代码校验检查,比较特殊,所以需要 release 命令,命令行添加 -l 参数
2.预处理阶段parser:比如 less、sass、es6、react 前端模板等都在此处预编译处理(语言编译)
3.标准化前处理插件preprocessor:比如有些css3语法需要插件加上前缀
4.标准化插件standard:处理内置语法,比如HTML和css或者js中嵌入其他文件内容或者base64编码值inline的语法,还有一些声明依赖在HTML和css或者js中用的requie语法等
5.标准化后处理插件postprocessor:比如压缩工作等
对于第3点,也有下面几个过程:
1.prepackager 打包前处理插件扩展点
2.packager 打包插件扩展点,通过此插件收集文件依赖信息、合并信息产出静态资源映射表
3.spriter 图片合并扩展点,如 csssprites
4.postpackager 打包后处理插件扩展点
你了解这些流程你就会得心应手了!下面是工作流程图
2.配置API
fis.set(key,value)
fis.set('project.charset', 'gbk'); //指定项目编译后产出文件的编码
fis.set('project.md5Length', 8); //文件MD5戳长度。默认长度为7
fis.set('project.md5Connector ', '.');//设置md5与文件的连字符
fis.set('project.files', ['*.html']);//设置项目源码文件过滤器
fis.set('project.ignore', ['*.bak']); //排除某些文件,set 为覆盖不是叠加
fis.set('project.fileType.text', 'tpl, js, css');//加文本文件后缀列表
fis.set('project.fileType.image', 'swf, cur, ico'); //追加图片类二进制文件后缀列表
这里说下比较常用的语法 fis.set(‘project.files’, [’*.html’]),这个是我项目里面的过滤文件
fis.set('project.files', [
//报错提示、浏览器js兼容
'basepiece/**',
//主要加载程序
'bootstrap/**',
//builder公用组件、服务
'builder/**',
// Site公共组件
'commonComponents/**',
//测试数据,本地发布使用
'mockObject/**',
//产品builder
'product/customSizeGameBox/**',
// Site公共服务
'services/**',
//builder整体样式
'totalStyles/**',
//whiteLabelSite公共组件服务
'whiteLabelSite/**',
'map.json',
//builder 第三方引用配置
'package.json'
]);
key为project.files,value是你需要发布的文件,目的是设置项目源码文件过滤器,发布的时候只会发布写的这些文件,其他的不会做处理!
2.常用配置语法
fis.match(selector, props);
//selector :FIS3 把匹配文件路径的路径作为selector,下面我会说下常用的匹配规则(fis3支持glob 规则)
//props :编译规则属性,包括文件属性和插件属性
常用的匹配规则:
1.*** 匹配0或多个除了 / 以外的字符
2.? 匹配单个除了 / 以外的字符
3.** 匹配多个字符包括 /
4.{} 可以让多个规则用 , 逗号分隔,起到或者的作用
5.! 出现在规则的开头,表示取反。即匹配不命中后面规则的文件
fis 中的文件路径都是以 / 开头的,所以编写规则时,请尽量严格的以 / 开头。
fis.match('a.js',{}) //它匹配的是所有目录下面的 a.js, 包括:/a.js、/a/a.js、/a/b/a.js
fis.match('/a.js',{}) //只命中根目录下面的 /a.js
fis.match('/foo/*.js',{}) // 只会命中 /foo 目录下面的所有 js 文件,不包含子目录
fis.match('/foo/**.js',{}) //命中 foo 目录下面以及所有其子目录下面的 js 文件
捕获分组写法
我们可以用 $1, $2, $3 来代表相应的捕获分组。其中 $0 代表的是 match 到的整个字符串
fis.match('/a/(**.js)', {
release: '/b/$1'
// $1 代表 (**.js) 匹配的内容 release 匹配的文件设置文件的产出路径,默认是文件相对项目根目录的路径,以 / 开头。该值可以设置为 false ,表示为不产出文件
});
fis.match('/a/(**.js)', {
release: '/b/$0' // $0 代表 /a/(**.js) 匹配的内容
});
isMod是否组件化
fis.match('/widget/**.js', {
isMod: true //表示widget文件目录下所有的js文件启动组件化
});
useHash(文件是否携带 md5 戳)
fis.match('*.css', {
useHash: false
});
指定文件的资源id
fis.match('/static/lib/jquery.js', {
id: 'jquery',
isMod: true //模块化的意思
});
var $ = require('jquery'); //相当于 var $ = require('/static/lib/jquery.js')
packTo(合并打包操作)
fis.match('/static/folderA/**.js', {
packTo: '/static/pkg/folderA.js' //文件合并并打包到指定文件夹里,是最后的环节和release不一样
});
fis.match('/static/folderA/file1.js', {
packOrder: -100
//有时候需要控制顺序。可以通过配置 packOrder 来控制,packOrder 越小越在前面
});
fis.media(接口提供多种状态功能,比如有些配置是仅供开发环境下使用,有些则是仅供生产环境使用的)
fis.match('*', {
useHash: false
});
fis.media('prod').match('*.js', {
useHash:true,
optimizer: fis.plugin('uglify-js')
});
fis3 release dev
注意:如果发布使用了fis.media匹配的名称,那么所有代码都会执行,如果没有使用,就只会执行fis.media上面的代码,一般我们开发没有必要压缩啊,合并打包啊,要不然我们代码不好调试,所以这里提供了多次环境使用
2.插件
fis hook()
fis3.hook('relative')
.match('**', {
relative: true //启用插件,所有文件使用相对路径
});
// commonJS规范
fis.hook('commonjs'); //commonjs规范,这个需要配合mod.js一起使用
less转css插件
fis.match('**/*.less', {
rExt: '.css', //后缀名为css
parser: fis.plugin('less-2.x')
}).match('*.{css,less,scss}', {
preprocessor: fis.plugin('autoprefixer', {
"browsers": ["Android >= 2.1", "iOS >= 4", "ie >= 8", "firefox >= 15"],
"cascade": true
})
});
optimizer启用优化处理插件,并配置其属性
fis.match('*.css', {
optimizer: fis.plugin('clean-css')
//css压缩
});
fis.match('*.png', {
optimizer: fis.plugin('png-compressor')
//图片压缩
})
fis.match('{*.js,*.vm:js,*.html:js}', {
optimizer: fis.plugin('uglify-js')
// js 压缩
})
打包阶段插件(打包阶段插件设置时必须分配给所有文件,设置时必须 match ::package,不然不做处理。)
fis3-postpackager-loader
fis.match('::package', {
prepackager: fis.plugin('plugin-name')
//打包预处理插件
})
fis.match('::package', {
packager: fis.plugin('map'),
//打包插件
});
fis.match('::package', {
spriter: fis.plugin('csssprites')
//打包后处理csssprite的插件
})
fis.match('::package', {
postpackager: fis.plugin('loader', {
//打包后处理单页面合并零散资源
allInOne: true
})
})
最后附上我项目的配置
fis.set('project.files', [
//报错提示、浏览器js兼容
'basepiece/**',
//主要加载程序
'bootstrap/**',
//builder公用组件、服务
'builder/**',
// Site公共组件
'commonComponents/**',
//测试数据,本地发布使用
'mockObject/**',
//产品builder
'product/customSizeGameBox/**',
// Site公共服务
'services/**',
//builder整体样式
'totalStyles/**',
//whiteLabelSite公共组件服务
'whiteLabelSite/**',
'map.json',
//builder 第三方引用配置
'package.json'
]);
//启用插件
fis.hook('relative')
//插件作用 让所有文件,都使用相对路径。
.match('**', {
relative: true
});
//引入模块化开发插件,设置规范为 commonJs 规范。
fis.hook('commonjs');
/*************************目录规范*****************************/
fis.match("**/*", {
release: '$&',
url: '$&',
relative: '$&' //代表访问路径是相对与自己本身的。这样配置文件引用的文件路径会不发生改变
})
.match('{bootstrap,builder,commonComponents,product/customSizeGameBox,services,whiteLabelSite}/(**.js)', {
isMod: true,
id: '$1'
})
.match("product/customSizeGameBox/(*.html)", {
release: '$1',
relative: '/'
});
/****************异构语言编译*****************/
fis.match('totalStyles/**/*.less', {
parser: fis.plugin('less'),
rExt: '.css'
})
.match('totalStyles/**/*.{css,less}', {
//fis3-postprocessor-autoprefixer
preprocessor: fis.plugin('autoprefixer', {
"browsers": ["Android >= 2.1", "iOS >= 4", "ie >= 8", "firefox >= 15"],
"cascade": true
})
});
//打包与css sprite基础配置
fis.match('::packager', {
// npm install [-g] fis3-postpackager-loader
// 分析 __RESOURCE_MAP__ 结构,来解决资源加载问题
postpackager: fis.plugin('loader', {
resourceType: 'mod',
useInlineMap: true // 资源映射表内嵌
}),
packager: fis.plugin('map'),
spriter: fis.plugin('csssprites', {
layout: 'matrix',
margin: '10'
})
});
/**********************生产环境下CSS、JS压缩合并*****************/
//使用方法 fis3 release prod -d
fis.media('prod')
//注意压缩时.async.js文件是异步加载的,不能直接用annotate解析
.match('**.js', {
preprocessor: fis.plugin('annotate'),
//压缩JS
optimizer: fis.plugin('uglify-js')
})
.match('**.{css,less}', {
//压缩CSS
optimizer: fis.plugin('clean-css')
})
//node_modules 中js文件打包
.match("node_modules/**/*.js", {
packTo: "/static/vendor.js"
})
//node_modules 中CSS文件打包
.match("node_modules/**/*.css", {
packTo: "/static/vendor.css"
})
//打包builder相关所有JS文件到一个文件中
.match("{basepiece,bootstrap,builder,commonComponents,product/customSizeGameBox/,services,whiteLabelSite}/(**.js)", {
packTo: "/static/builder.js"
})
//打包所有CSS文件到一个文件中
.match("totalStyles/**/*.{less,css}", {
packTo: "/static/builder.css"
})
//打包所有图片文件到一个文件夹中
.match("totalStyles/**/*.{svg, png, bmp, gif, jpe, jpeg, jpg, webp}", {
release: "totalStyles/images/$1"
})
//不输出组件中的HTML文件
.match("{builder/builderCommonComponents,commonComponents,product/customSizeGameBox/privateComponents,whiteLabelSite/wlsCommonComponents}/(**.html)", {
release: false
})
//不输出测试数据
.match("mockObject/**", {
release: false
})
//不输出fis3配置文件
.match("map.json", {
release: false
})
.match('*.{js,css}', {
//添加md5戳
useHash: true
})
.match('*.{svg, png, bmp, gif, jpe, jpeg, jpg, webp}', {
//添加md5戳
useHash: true
很晚了,写的比较匆忙,之后再来补充!