前言
参考链接:
FIS 官网
YOG2入门指引
app 的全称是 Application 应用程序的意思。
什么是 FIS ?
FIS 是百度团队自行开发的一个解决前端开发中自动化工具、性能优化、模块化框架、开发规范、代码部署、开发流程等问题调的构建工具,FIS 这个东西已经不是现在主流的工具了,我们主要的是需要理解 FIS 的思想,用这种思想用 webpack 来搭建像 FIS 这样的项目
想要从一个初级的前端慢慢提升,其实是一个必须要经历的过程,FIS 就是从 1 到 2 再到 3 的,学习这种工具不是简单的说你会某个工具这样的,而是说:你具有这种构建工程化的工具的使用能力,这个才是你需要做到的
实际上这些工具(比如:webpack、gulp、grunt)用了之后,还是要将你的代码变成 css js html 的,他们具备的都是构建工程化的能力,一个高级的前端和一个 low 的前端其实差的就是这个可以让团队持续向下发展构建大型工程能力,如果你有了这个能力的话,再进入一般的公司是没有什么太大的问题的
学了 FIS 之后可以让你体会到大公司在做一个项目的时候究竟做了些什么,会让你在公司中有一定的位置
FIS 后面的四个步骤做的还是非常的优秀的,如果是用 webpack 的话配置起来会相当的麻烦。
接下来我们去使用 yog2
简介
YOG2 是一个专注于 Node.js UI 中间层的应用框架。它基于 express 和 fis 开发,在享受 express 的灵活扩展能力和 fis 强大的前端工程化能力的同时,引入了自动路由、app 拆分以及后端服务管理模块来保证UI中间层的快速开发与稳定可靠。
创建简单的 yog2 demo
1. 首先 创建project
- 安装创建
//全局安装
npm install -g yog2
//进入桌面
cd Desktop
//创建项目 project
yog2 init project
//之后会有一个提示让你输入你的项目名称 这个是必填项
yogtest
//看到 dnoe 之后 ctrl + c 退出就可以了
-
此时找到桌面的 yogtest 文件夹并把他拖到 sublime 编辑器中
- app -> 存放App的Server端代码
- conf -> 里面是相应的配置文件
- conf -> plugins 里面是插件相应的配置文件
- conf -> ral 后端服务配置文件,就是在用 Node 去请求 java 的时候所有的配置文件都是在这的
- plugins -> 存放用户自定义或通过脚手架安装的components 组件
- static -> 对应的编译出来的静态文件
- views -> 对应编译出来的模板
- .gitignore -> 这个文件是在提交至服务器的时候哪些该提交哪些不该提交的配置文件,提交时会照着这里面的配置来
- .jshintrc -> 配置文件,她决定哪些代码该去配置
- .npmignore -> npm 配置文件
- app.js -> 项目的启动文件
- 接着就可以在命令行操作了,想要启动项目需要先在命令行中安装项目中所有的依赖
//进入项目目录中
cd yogtest
//安装项目依赖
cnpm install
//这个时候再去启动程序
node app.js
- 命令行中显示下图这个就证明启动成功了
-
此时再到 sublime 中会发现多出了一个 log 目录
里面记录都是你登录操作的写日志,这些都是自动生成的根本不需要提交
- 此时在浏览器中查看 8085 端口 http://localhost:8085/ ,显示如下,404 的原因是在代码里面没有给路由
2. 接下来 创建app
- 在命令行中敲代码
//初始化一个 app 应用目录
yog2 init app
//输入你的应用目录名称
home
- 此时在 sublime 中查看会发多出了一个 home 目录,需要知道的是这个 home 目录在上线的时候是用不到的,这个目录主要是为了 发布、编译
- home -> client 这个就是客户端目录
- home -> server 服务端目录,项目中的第一个目录 app 就是服务端,这个是 yog2 项目默认存放 server 端代码的目录,必须放在这里
- client 目录中的东西发布到对应的 static 和 views 目录中
- client -> page 里面的东西是负责组装 views 的
- client -> page -> layout.tpl 这个 layout 提供了一个完整的框架壳,这里面留了一个 block 的东西,相当于是将 layout.tpl 里面的内容通过这个 block 导入到了 index.tpl 中,所以接下来的页面只要 render 这个 index.tpl 页面就可以了,这样的写法浏览器是不识别的,是需要 Node 来进行编译的
- client -> wiget -> message 这个目录就是放置项目中用到的 css 、js文件的,这里我新建了一个 message.less 文件,然后这个 .less 文件写好之后 打包、编译之类的操作,之后就把它放到 static (项目中的一级目录)目录中
- client -> static 这里面放的是 css 、js 一些公用的文件的
- client -> static -> js -> lazyload.js 这个是很早之前为了页面的加载性能引入的一个文件,其实是没有用到的,可以删掉
- client -> static -> js -> mod.js 这个可以留着,是 FIS 自己写的,基于 AMD CMD 的一个模块加载器,这是一个类似 c.js 的东西
- client -> static -> js -> bigpipe.js 这个是在做单页的时候一个非常重要的文件
- client -> static -> js -> page.js 是做单页应用的
最后留下两个 js 文件就可以了,其他的都可以删掉
mod.js 可以使有的 widget(组件)进行同步,有的进行异步
下图是默认的渲染模式
还有一种是 quickling 模式
mod.js 默认是在 layout.tpl 中引用的
将 layout.tpl 中引用 jquery 的代码删掉
上面的都是 client 前台,下面是 server 后台
- server -> action 这个目录的内容实际上就是要发布到一级目录 app 中的,只要你在 app 这个一级目录下建一个 index 目录 他就会自动给你创建一个路由(这个实际上的例子是:当你访问一个网站的时候,比如:localhost:3000 它实际上直接访问的就是 localhost:3000/index/ 这个是可以自行去设置的)它的实现原理的是 直接去拿文件夹的 IO 找到里面有什么文件夹就会建这个路由,如果你编译了之后 会将 这个 server -> action 目录中的文件放到 app 下的 index 目录中 ,这个 action 是类似于 php 中的 controller/action 这样的文件夹 所以就可以通过 /index/book.js (编译后的位置) 访问到 /action/book.js (编译前的位置)
- server -> action -> book.js 这个文件里面是 四个协议,这样同一个接口就可以产生四个协议,一个 js 文件通过 /index/book 文件就可以创建四个请求,这四个请求可以通过 app 随意地去访问,这个是个非常需要记住的技巧
-
server -> router.js 可以使我们更加方便的去配置路由,下图的位置就可以写正则表达式,使得路由更加的灵活
home -> fis-conf.js 这个 js 设置了启用是使用的端口号,一旦你使用 yog2 run 就可以启动这个端口,而且会将该编译的目录自动送到该送的目录中去
而且这个里面还配置了 livereload 可以使编辑代码更新了之后,页面也可以跟着刷新
顶部的 namaspace 后面的目录名称需要跟你导出的目录名称一致,不然是实现不了的,所以这里把之前 app 目录建的 index 目录 重命名 为 home ,注意这个是千万不能写错的,一定要一致
3. 接下来 开始运行应用程序
- run
yog2 run
之后就会执行一堆东西,会把所有的 log 都输出到命令行中,这个是用来接收服务的,平时上线使用 pm2
- 然后需要再新开一个命令行窗口,进入到 home 打包和编译
cd Desktop\yogtest\home\
//通过下面的命令发布
yog2 release --dest debug
yog2 release –dest debug 必须要求运行框架以调试模式启动后使用,否则无法正确的部署代码。
最下面可以看到是两个程序运行窗口,左边的是yog2 run
,右边的是yog2 release --dest debug
-
这个时候在 sublime 中可以看到,app -> home 里面就是打包编译好的文件
- 在 app -> home -> action -> index.js 中 render 的页面是 一级目录中的 home/page/index.tpl
- 此时才浏览器中输入 localhost:8085/index 打开的就是这个页面
index 就是下图的这个文件
浏览器中显示的 Hello world 是下图中 views -> home -> widget -> message -> message.tpl 文件中来的
这个就是一个网站的根路由, /index 后面再加别的路径就访问不到了,这是整个网站的根
- 可以在 app -> home -> action 目录下配置多个路由
在 app -> home -> action 目录下新建一个 test.js 文件
编辑 test 文件
module.exports = function(req, res) {
//访问页面时输入一个 json 数据
res.json({
data: 123
});
};
- 这个时候需要先在 两个命令行中 重新运行一下服务,然后就可以在浏览器中访问刚配好的 test
//命令行窗口 1
yog2 run
//命令行窗口 2
yog2 release --dest debug
![image.png](http://upload-images.jianshu.io/upload_images/6264932-3ed14c01994a7f7e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
> 我们还可以在路径中加 home 目录,同样也可以访问到这个路由,因为实际上我们的这些路由请求是都需要通过 home 这个根目录的,localhost:8085/home/index 这样也是可以访问到 index 的
![image.png](http://upload-images.jianshu.io/upload_images/6264932-b3f1e70569b9fffa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
8. 这个时候我们还可以在 app 目录下再新建一个 index 目录, 里面的文件复制 home 目录下的
需要将 index -> router.js 中的代码删成下图这样的,注意这个 exports 一定要留着,不然项目就不行了
![image.png](http://upload-images.jianshu.io/upload_images/6264932-657c4119cbc85218.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
index -> action 目录下将之前的 js 文件都删掉,新建一个 pp.js 文件
编辑 pp.js 文件
module.exports = function(req, res) {
//访问页面时输入一个字符串
res.end('aaa');
};
![image.png](http://upload-images.jianshu.io/upload_images/6264932-448a3892f14b0e49.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
9. 这个时候我们再在浏览器中去访问这个 pp
直接输入 pp 是访问不到的
![image.png](http://upload-images.jianshu.io/upload_images/6264932-7ec4e812de9ceb64.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
> 实际上是需要加 /index/ 这个路径的 ,这里我第一次没有成功,然后再左侧的命令行中重新运行了一下 `yog2 run` ,再刷新浏览器页面就成功了
![image.png](http://upload-images.jianshu.io/upload_images/6264932-dd5e126a362f6b97.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
> 直接输入 pp 会失败的原因是:在 conf -> plugins -> dispatcher.js 文件中将 home 设置为了整个项目的默认路由
![image.png](http://upload-images.jianshu.io/upload_images/6264932-17f8d79f7d2cb841.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
10. 假如说你需要给网站设置一个基础的东西:index.html,这里我们修改的是 app -> home -> router.js
编辑 router.js
module.exports = function(router){
//这里我做一个假路由 这里当请求的时候直接将渲染的页面用 根目录下的 index.js 代替了
router.get('/index.html',router.action('index'));
};
![image.png](http://upload-images.jianshu.io/upload_images/6264932-4d3d549e252dea54.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
11. 如果是访问网站的 index.html 的话,肯定不会让用户去多输入一个 /home/ 路径的,所以就把 home 路径设置为了根路由,指定的文件就是下图的 conf -> plugins -> dispatcher.js 文件中设置的
![image.png](http://upload-images.jianshu.io/upload_images/6264932-cd8e8afbbb93ddcd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
12. 这个时候我们需要先在左侧的命令行中重新运行一下服务**(只要做了一些修改发现页面没有更新到就可以重新 `yog2 run` 一下)**,在浏览器中用下面的两个不同的路径就都能访问到了,其实这个 home 是多余的,我们把它设置成了 根路由(默认路径)之后,每次访问的页面默认都会经过它的,这个就叫做“伪静态”,可以方便于 百度蜘蛛找到
![image.png](http://upload-images.jianshu.io/upload_images/6264932-87e98f033fb13750.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![image.png](http://upload-images.jianshu.io/upload_images/6264932-e5b81d67300088a9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
### YOG2 进阶
#### 回顾上面的
* 上部分大致的将前后端跑通了,主要的重点还是涉及到的那些配置
* 前端火是因为有一些库在不停的应运而生,而且这些库带来了非常多的新思想和新理论
* FIS 负责的是一个编译的过程,把我们写的那些浏览器本来不认识的东西变成浏览器认识的东西,把一些工程化的东西压缩打包合并,这个就是 FIS 所做的事情,所以需要配置两步:**压缩、打包、合并** 和 **编译 less 、 js 、es6 等这些文件**
* FIS3 是已经比较完善了用的话就用这个版本,之前的版本 2 是相对来说正常一点的
#### 配置
1. [YOG2 服务管理](https://link.jianshu.com?t=http://fexteam.gz01.bdysite.com/yog2/docs/features/service.html#%E6%9C%8D%E5%8A%A1%E7%AE%A1%E7%90%86) -> [node-ral](https://link.jianshu.com?t=https://github.com/fex-team/node-ral)
> node-ral 是一个专为 Node 服务端应用打造的一款工业级后端服务管理库,它的特色是统一了各种通信协议、数据格式的请求接口,提供了集中化的服务资源配置管理能力,以及完善的异常处理和日志记录。
* 简单来理解:这个 node-ral 实际上是 在后端通过 java 去请求的时候,你直接封装他就可以了,并不用自己再去找一些库了,这里面它实现的封装已经很好了
* node-ral 使用方法:将下图中的代码直接复制到 yogtest -> conf -> ral -> demo.js 中,然后 demo.js 文件中的 **module.exprots** 里面的 **DEMO_SERVICE** 就可以使用了
![image.png](http://upload-images.jianshu.io/upload_images/6264932-4c774490cbd07343.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![image.png](http://upload-images.jianshu.io/upload_images/6264932-7aa2bf87fe2e9558.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
* **module.exprots** 对象中的配置分析
* 解包 json
* 打包 form
* 发送 POST
* 编码 gbk
* 随机的去发
* 请求 http
* 重试机制
* timeout
* server 服务端的地址
* 编辑 yogtest -> app -> home -> model -> index.js 文件
> 参照代码
![image.png](http://upload-images.jianshu.io/upload_images/6264932-3c4f58b762dc027a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
module.exports.getData = function() {
return {
title: 'FIS',
};
};
module.export.search = function(name, region) {
//DEMO_SERVICE 是 ral -> demo.js 文件中定义的对象 下面是数据 返回了一个 promise 对象
return yog.ralP('DEMO_SERVICE', {
data: {
region: region,
query: name
}
});
}
* 编辑 yogtest -> app -> home -> router.js 文件
> 参照代码
>
![image.png](http://upload-images.jianshu.io/upload_images/6264932-2afe6142f1eea48a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
var lbsModel = require("../models/index.js");
module.exports = function(router) {
//这里我做一个假路由 这里当请求的时候直接将渲染的页面用 根目录下的 index.js 代替了 这个就叫做
router.get('/index.html', router.action('index'));
router.get('/test', function(req, res, next) {
//前台带过来的 name 和 region
lbsModel.search(req.query.name, req.query.region)
//把后台输出的结果直接输出给前台
.then(res.json.bind(res))
//如果出错执行 next
.catch(next);
})
};
2. 上面的是一个基础的示例,使用了 yog2 之后,会发现不需要掌握较深的 node 知识只要安装 module 按照逻辑来写就能把业务给串起来,但是如果是后期你想要追求更高深的东西也可以,首先是需要将业务给跑起来,这是第一步,之后进行操作,先把上面修改的两处代码注释下,编辑 yogtest -> home -> fis-conf.js 文件
> 将文件中下面的代码注释掉,写上下面的代码片段
![image.png](http://upload-images.jianshu.io/upload_images/6264932-476b999709474891.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
fis.config.merge({
//项目中开发阶段的所有的文件的目录
namespace:'home',
roadmap:{
//cdn配置
domain:''
},
pack:{
//打包后的路径
'pkg/home_widgets.js':[
//打包的文件
'client/widget/.js'
],
'pkg/common_widgets.css':[
'client/widget/.less'
]
}
});
* 在 yogtest -> home -> widget -> message 目录下新建一个 message.less 文件
编辑 message.less 文件
//一般情况下为了区分权重会用下面的标签代表整个页面
.home-widget-message{
h1{
color: red;
}
}
* 编辑 yogtest -> home -> widget -> message -> message.tpl 应用上面写的样式
* 之后就可以进行编译了,还是分为两个命令行窗口
//窗口1
yog2 run
//窗口2 Dompuld
//D domain 加上前面的地址
//o 是给压缩图片
//m 是 MD5
//u
//p 是打包
//l 是监听
//d dist 是文件目录
yog2 release -Domupld debug
* 窗口2 执行命令的时候会报下面的错误
![image.png](http://upload-images.jianshu.io/upload_images/6264932-254e4e94fe8059ac.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
* 上面报错的原因是我现在使用的 node 版本过高,他并不支持,由于我的是 windows 系统所以安装了 [nvmw](https://link.jianshu.com?t=https://github.com/hakobera/nvmw.git) 来用它可以自由的使用 node 各种版本,具体安装方法可参考我的另一篇安装笔记 [Windows 下使用 nvmw 安装任意版本的 node](https://www.jianshu.com/p/26b9cd65d081),安装之后因为 yog2 需要使用 4.8.6版本(这个版本号好用,其他的没有去尝试)
//nvmw 命令使用的前提是安装并成功配置了 nvmw ,具体方法请移步上面的参考链接查看
//使用 4.8.6 版本的 node
nvmw use v4.8.6
//查看 node 版本号
node -v
- 上面的执行成功之后,再次刷新浏览器会发现 js 和 css 都已经进行了压缩、生成了 MD5 并打包到了自己配置的目录下
路径
js:http://localhost:8085/static/home/static/js/mod_75d1f98.js
css:http://localhost:8085/static/home/pkg/common_widgets_c44e883.css
上面引入的 js 其实是 下面这个 layout 中自动引用的
- 上面的
yog2 release -Domupld debug
命令中的Domupld
可以使用下面的命令查看相关的解释
yog2 release --help
![image.png](http://upload-images.jianshu.io/upload_images/6264932-3750f789eb13ef8b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
3. 因为 js 是不会自动引用的,所以需要在页面上添加引用,先在项目的 yogtest -> home -> client -> widget -> message 目录下新建一个 message.js 文件
编辑 message.js 文件
//这个是一个典型的单例模式的例子
var message = {
//init 是接收参数的
init: function() {
var me = this;
console.log('message init');
me.render();
me.bind();
},
//render 是负责 render页面
render: function() {
var me = this;
me.btn = $('#btn');
},
//bind 是负责绑相应的元素
bind: function() {
//jQuery.proxy( function, context )
//function为执行的函数,content为函数的上下文this值会被设置成这个object对象
var me = this;
me.btn.on('click',$.proxy(me._go,this));
},
_go:function(e){
console.log(e.target);
}
}
//将方法导出 这个 module.exports 方法是从 layout.tpl 中引用的 mod.js 中来的
module.exports = message;
然后在同目录下 yogtest -> home -> client -> widget -> message 的页面文件 message.tpl 中引用这个 js
编辑 message.tpl 文件
{%script%}
require('message.js').init();
{%endscript%}
* 然后再命令行窗口 2 中重新执行mingl
yog2 release -Domupld debug
* 刷新浏览,console 的内容已经生效了,下面的报错是因为没有引用 jquery 无关紧要的东西,主要是为了实现 js 的引用
![image.png](http://upload-images.jianshu.io/upload_images/6264932-a1f60ba5f251bec6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
4. 接下来试着来编译 ES6
* 将项目中的 message.js 文件的后缀名改为 .es 并将之前写的代码注释掉
![image.png](http://upload-images.jianshu.io/upload_images/6264932-a97b7e86d4730026.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
* 编辑 message.es 文件
//ES6
class Message{
constructor(x){
this.x = x;
}
init(){
console.log(this.x);
}
}
var message = new Message('message init');
export {message};
* 在修改 fis-config.js 中相应的配置文件的后缀名
![image.png](http://upload-images.jianshu.io/upload_images/6264932-2669be374e6a6c24.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
* 还要在 yogtest -> home -> client -> widget -> message -> message.tpl 修改引入的方法
{%script%}
require('message.es').message.init();
{%endscript%}
* 在命令行窗口 2 中进行编译
yog2 release --dest debug
* 从命令行中的输出可以看到,FIS 自动的将 message.es 文件编译成了 message.js 文件
![image.png](http://upload-images.jianshu.io/upload_images/6264932-bc317d13c1584cdd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
* 在刷新浏览器可以看到已经引用成功了,输出了正确的值
![image.png](http://upload-images.jianshu.io/upload_images/6264932-acdd566ead9c6421.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
#### 温馨提示
* FIS 使用的插件可以在官网的 [插件列表](https://link.jianshu.com?t=http://fis.baidu.com/fis3/plugins.html) 中搜索、查找、使用
* fis.config.js 中的目录名是必须要与项目中开发阶段放所有文件的目录保持一致的
![image.png](http://upload-images.jianshu.io/upload_images/6264932-92e93f1c4d0a30e6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
* 在每次生成的时候会有一个 FIS 里面比较核心的 map.json 文件 yogtest -> conf -> fis -> home-map.json
![image.png](http://upload-images.jianshu.io/upload_images/6264932-41611a77ba7c5d52.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
> 这个文件是整个项目的目录的依赖分析
> 就比如说 之前将 es 文件编译成了 js 文件并进行了压缩打包,就可以在这个文件中追踪的定位到这个 es 文件