本文来自 网易云社区 。

Foxman ⇗ 是一个使用 Node.js 开发的命令行工具,定位是一个可扩展的 Mock Server,帮助前端开发者轻松、独立、高效地进行前端开发和完成后续的联调工作。

他不是一款静态文件响应工具, 假如你只需要一款轻量的 Node.js 开发服务器,推荐你使用 puer ⇗ 或 webpack-dev-server ⇗

github 地址: https://github.com/kaola-fed/foxman

背景

作为前端开发的我们,在实际的开发场景中会遇到以下问题:

  1. 环境:进行本地开发,需要起后端环境(Tomcat),对于新人来说,需要大量时间熟悉;熟练的人遇到某些确实存在的问题,也要花时间去解决,耗费大量前端开发的时间;
  2. 流程:前端开发先开发 html,再将 html 改写成指定的模板语法,影响开发效率;
  3. 接口:
    • 接口定义使用聊天工具发送,前端开发时不好理解接口字段,影响开发效率;
    • 接口变更需要重新编写文档,并重新发送,影响开发效率;
    • 文档散落,影响接口维护;
  4. 联调:
    • 联调过程很复杂,尤其是没有做热部署的Java工程,改视图还需要重启Tomcat,影响前端联调效率;
  5. 效益:
    • 前后端对接的方式,期望纯粹的 JSON 交换。不过现实情况,是依赖后端的模板引擎,导致前端理解接口存在一定的障碍;

以上问题的存在,才产生了 Foxman 这个项目。

影响

从 考拉前端 使用情况来看,在接入 Foxman 后开发效率得到一定提升,主要体现在以下方面:

  1. 前端开发者不再需要在本地起 Tomcat 服务,新人也无需熟悉本地启动环境;而启动一个 Foxman 所需要的时间,在 5s 以内;
  2. 前端开发者更加有意识地去与后端定义接口,因为接口定义会落实到具体的 mock 数据上;
  3. Mock 功能,使得前端开发者在开发阶段几乎可以是自治、无打扰的情况(产品不改需求的前提下);
  4. Foxman 提供 Living Reload 的功能 - 页面开发过程中,修改 html 和 js 会通知浏览器 reload 页面;修改 css 会通知浏览器只 reload 样式,提升了开发体验,节省了人肉刷新耗费的时间。
  5. Foxman 提供 Processors 的功能 - 即时编译的设定,更好地兼容无 webpack 构建的场景;
  6. 联调阶段,由于 Foxman 提供 了 Proxy 功能,使前端开发可以再本地调试模板和 javascript,避免了修改提交,再重新部署服务器的时间耗费,大大提升联调效率与体验;

核心概念

容器 - Foxman 核心提供了一个挂载插件的容器,并且提供方法供插件提供或调用的服务。实现上,使用了IoC(依赖查找)、插件化等架构设计的思想。

插件 - Foxman 所有具体的功能都使用插件实现。插件的作用是实现本身需求,并提供服务供其他插件使用。

服务 - 服务是架设于 容器 与 插件 之上的概念,容器 提供方法供 插件 注册或调用服务。

在这样的体系下,你可以轻松地编写 Foxman 的插件,并调用已有插件的服务。所以,完全不需要担心,Foxman 会不适合你的项目,因为你完全可以根据自己的需求来定制你所需要的Foxman。

安装

NPM

$ npm i -g foxman@lastest # 无梯子用户,推荐使用 cnpm

  

⚠️ Foxman 采用 es6 语法的大部分特性编写,要求使用 Node.js 版本不低于 v6.4.0

编写配置文件

module.exports = {
port: 9000,
secure: false,
statics: [
'./src/'
],
routes: [
{
method: 'GET',
url: '/ajax/index.html',
sync: false,
filePath: 'foo.bar'
}
],
engineConfig: {},
viewRoot: './views/',
extension: 'ftl',
syncData: './syncData/',
asyncData: './ajax/',
plugins: [],
processors: [
{ match: '/src/css/*.css', pipeline: [], locate( reqUrl ) {} }
],
proxy: [
{ name: 'pre', host: 'm.kaola.com', ip: '1.1.1.1', protocol: 'http' }
]
}

  

这是一份基础的 Foxman 的配置文件,可以发现大部分字段都给 Server 用的,比如:

  • port - Server 监听的端口
  • secure - 是否启用 https
  • statics - 静态资源配置
  • routes - 路由列表
  • engineConfig - 模板引擎配置项
  • viewRoot - 模板根目录
  • extension - 模板扩展名
  • syncData - 同步数据根目录
  • asyncData - 异步数据根目录

以及一些特殊的字段,后面我们会重点介绍:

  • proxy - 联调阶段,同步数据与异步数据的转发至后端主机或测试服务器
  • processors - Runtime Compiler 的配置
  • plugins - 插件配置

更详细的 Foxman 配置,点击此处 ⇗

启动

在编写完 foxman.config 的目录下,执行命令即可启动 Foxman :

$ foxman

设计理念

插件体系

Foxman 的外置插件可以在配置文件中灵活载入:

...
plugins: [
new RouteDisplay(),
new MockControl({}),
new Automount({}),
new WebpackDevServer({}),
]
...

而所有的内置功能,其实也是依托于插件展开。每个 Foxman 插件,需要实现一些方法,用于装载入 Foxman 容器时,做一些登记工作:

class Plugin {
constructor() {
// 初始化自身需要的属性
} name() { // 定义插件的名字,如果没有该字段,会使用 constructor.name
return 'name';
} service() { // 提供给其他插件的服务
return {
foo() {
return 'bar';
}
}
} init({getter, service}) {
const use = service('service.use');
}
}

LivereloadPlugin ⇗

容器与依赖查找

容器的设定,离不开 IoC(控制反转)的概念。

实现 IoC,惯用的一种方案是依赖注入 (Dependency Injection) ,用于运行时被动地接收依赖的对象,早期的 Foxman 是根据 DI 的方式实现插件化的;

另一种方案是依赖查找 (Dependency Lookup) - 与 DI 相比更加主动,主动得调用框架提供的方法来获取依赖,获取时提供相关的配置文件路径 或 keypath 等信息。

Foxman 核心提供了 use 和 start 两个方法:

  • use - 注册 Plugin 及 service
  • start - 执行 Plugin 的 init 方法,传入 service/getter 方法,供其依赖查找
// core.js
class Core {
use() {
// 1. 注册 Plugin 进入容器;
// 2. 在容器中登记 Plugin 提供的 service
} start() {
// 1. 循环 Plugin 执行 init 方法, 注入 getters, service 等方法,用于获取其他插件的配置或是服务
// 2. 如果插件执行了 this.pending 方法,则等待异步操作完成。
}
}
// app.js
const core = new Core(); core.use(new Plugin({}));
// 1. 执行 Plugin constructor
// 2. 注册 Plugin 进入容器
// 3. 在容器中登记 Plugin 提供的 service core.start();
// 执行 Plugin 的 init 方法,会在参数中注入的 getters 和 service 方法,用于插件依赖查找,

具体的实现细节,感兴趣的同学可以 查看源码 ⇗

功能模块

Server模块

基于 Node.js Server 框架 koa@1.x 构建,Server 的职责便是渲染模板、响应异步数据,以及在页面插入一些特定的脚本。

整个 Server 的启动分为三个阶段:

  1. 初始化 - 设置配置,设置路由,以及初始化 Koa 对象;
  2. 装载中间件 - 初始化中间件队列;
  3. 启动服务 - 启动 Server,并建立 websocket 服务器,用于与浏览器的通信。

在 Server 启动后,请求进入 Server 时,会经历中间件的处理,这个过程又能分为 3 个阶段:

  1. 请求分析,及确定响应方式,在请求的 context 上,生成 dispatcher 对象,用于在步骤 3 中确定以何种方式进行响应(同步 or 异步,模板路径 or mock 数据路径);
  2. 由插件装载的中间件对请求进行处理(取决于具体使用的插件),这个阶段可以对 dispatcher 对象进行修改,以完成插件所期望的渲染方式;
  3. 请求响应,根据请求的类型,分为以下几种方式
    • 同步请求 - 交给 Foxman-Engine 进行渲染,(注入一些 script 脚本,并且在页面上追加同步数据,使得浏览器 console 中输入 window.FOXMAN_SYNC_DATA 即可获得 )
    • 异步请求 - 默认 json 方式展示,如需要 jsonp 响应,或是要自由控制响应方式,请使用插件 @foxman/plugin-mockcontrol ⇗
    • 文件夹请求 - 展示文件夹内的文件列表
    • 静态资源 - 响应静态资源

Server模块 提供其他插件一些关于 Server 相关的服务,可以供其他插件调用,比如:

  • injectScript - 允许其他插件在同步接口中插入 javascript 脚本
  • eval - 允许其他插件执行 js 代码
  • livereload - 允许其他插件通知浏览器 reload
  • use - 允许其他插件给 server 加入中间件
  • registerRouterNamespace - 允许其他插件新增路由,使用命名空间可以保证不同的插件的路由不会相互干扰

Foxman 的内置的 Mock Data 编写方式使用最原始的 JSON 字符串。
没有使用 MockJS 等库的原因是,原始的 JSON字符串,使用者可以对模拟数据的完全掌控。
有特殊需求可以使用插件 @foxman/plugin-mockcontrol ⇗对响应进行额外控制。

整合 NEI

NEI ⇗是我们网易开发的一个接口定义平台。

foxman 接入 nei 非常简单, 在 foxman.config.js 中配置 nei key 即可:

...
nei: {
key: 'xxx' // nei key
}
...

首次运行会自动同步 NEI 接口。

当需要更新本地 nei 接口时,使用以下命令:

$ foxman -U

Template 渲染引擎

模板解析模块,具有特定接口,完成模板渲染需求。

var engine = require('@foxman/engine-arttemplate');

...
engine: engine,
engineConfig: { // 取决于具体的模板引擎
bail: true,
compileDebug: true,
imports: renderImports,
debug: false,
cache: false,
}
...

目前支持的模板引擎有:

假如没有你需要的,你也可以自行开发一款 Foxman 的模板引擎解析器,只需要实现一个特定的接口,基本结构如下。

const template = require('xxx-template');
class TemplateEngin {
constructor(viewRoot, engineConfig) {
// 初始化配置
} parse(path, mockData) {
// 返回一个 Promise,Promise 的返回是处理后的接口
return Promise.resolve(template(path, mockData));
}
}

具体实现,参考 @foxman/engine-arttemplate ⇗

Proxy

使用本地的模板,结合远程端的数据来拼装页面。

代理的原理:

  1. Foxman 接收到用户的代理需求时,将请求转发给后台服务器,并带上特殊的请求头(X-Special-Proxy-Header: foxman);
  2. 后端接收到 Foxman 的代理请求后,要求以 JSON 的方式将页面的同步数据返回;
  3. Foxman 接收到服务端的响应数据后,结合本地的模板来实现模板渲染的需求,并响应给用户。

代理的设定,使得我们可以在本地的环境下调试测试环境的场景,发现存在前端的 bug 也能轻松修复,不再需要重复的部署测试服务器。

来接触下 Foxman Proxy 的实际配置:

...
proxy: [{
name: 'pre',
host: 'm.kaola.com', // 用于 nginx 转发到制定应用
ip: '1.1.1.1', // 目标的 IP 地址
protocol: 'http' // 协议
}]
...

完成上述配置后,使用者输入以下命令启动 Foxman,即可代理至远程服务器

$ foxman -P pre # pre 为 配置的 proxy name

Processors

Processors 是 Runtime Compiler 的设定,在接收到静态资源请求时,才去即时地编译前端资源(sass/less/mcss/autoprefixer),主要目的是兼容无 webpack 构建的开发场景。如已使用 webpack,则推荐使用插件 @foxman/plugin-webapck-dev-server

举例介绍 mcss 的即时编译配置

const Mcss = require('@foxman/processor-mcss');
const AutoPrefixer = require('@foxman/processor-autoprefixer'); ...
processors: [
{
match: '/src/css/**.css', // 拦截该请求
pipeline: [ // pipe 式的处理
new Mcss({
paths: []
}),
new AutoPrefixer({
cascade: false,
browsers: '> 5%'
})
],
locate(reqPath) { // 根据请求路径,定位到在系统中具体路径
return path.join(__dirname + reqPath.replace(/css/g, 'mcss'));
}
}
],
...

假如没有你需要的,你也可以自行开发一款 Foxman 的 Processor ,只需要实现一个特定的接口,基本结构如下:

const mcss = require('mcss');

class Processor {
constructor(options) {
// 初始化解析器的参数
} locate(reqPath) { // 根据请求路径找到文件在系统中的位置
return reqPath.replace(/\.css$/g, '\.mcss');
} *handler({ raw, filename }) {
return yield new Promise((resolve, reject) => {
// 在这里 进行 parse 操作,如 sass | less 的解析操作
return {
dependencies, content
// 该文件依赖,及内容
}
})
}
}

具体实现,参考 @foxman/processor-mcss ⇗

结束

最后,如果你对 Foxman 的开发感兴趣,欢迎一起参与到开发当中。

感谢阅读!

本文已由作者许骏宇授权网易云社区发布。

Foxman, 基于微核架构的 Mock 解决方案的更多相关文章

  1. atitit.跨架构 bs cs解决方案. 自定义web服务器的实现方案 java .net jetty  HttpListener

    atitit.跨架构 bs cs解决方案. 自定义web服务器的实现方案 java .net jetty  HttpListener 1. 自定义web服务器的实现方案,基于原始socket vs   ...

  2. 基于AgileEAS.NET企业应用平台实现基于SOA架构的应用整合方案-开篇

    开篇 系统架构的文章,准备在这段时间好好的梳理和整理一下,然后发布基于AgileEAS.NET平台之上的企业级应用架构实践,结合具体的案例来说明AgileEAS.NET平 台之上如何进行系统的逻辑架构 ...

  3. COS 数据湖最佳实践:基于 Serverless 架构的入湖方案

    01 前言 数据湖(Data Lake)概念自2011年被推出后,其概念定位.架构设计和相关技术都得到了飞速发展和众多实践,数据湖也从单一数据存储池概念演进为包括 ETL 分析.数据转换及数据处理的下 ...

  4. 如何基于LSM-tree架构实现一写多读

    一  前言 PolarDB是阿里巴巴自研的新一代云原生关系型数据库,在存储计算分离架构下,利用了软硬件结合的优势,为用户提供具备极致弹性.海量存储.高性能.低成本的数据库服务.X-Engine是阿里巴 ...

  5. 构建一个基本的前端自动化开发环境 —— 基于 Gulp 的前端集成解决方案(四)

    通过前面几节的准备工作,对于 npm / node / gulp 应该已经有了基本的认识,本节主要介绍如何构建一个基本的前端自动化开发环境. 下面将逐步构建一个可以自动编译 sass 文件.压缩 ja ...

  6. 常用 Gulp 插件汇总 —— 基于 Gulp 的前端集成解决方案(三)

    前两篇文章讨论了 Gulp 的安装部署及基本概念,借助于 Gulp 强大的 插件生态 可以完成很多常见的和不常见的任务.本文主要汇总常用的 Gulp 插件及其基本使用,需要读者对 Gulp 有一个基本 ...

  7. 在windows下安装gulp —— 基于 Gulp 的前端集成解决方案(一)

    相关连接导航 在windows下安装gulp —— 基于 Gulp 的前端集成解决方案(一) 执行 $Gulp 时发生了什么 —— 基于 Gulp 的前端集成解决方案(二) 常用 Gulp 插件汇总 ...

  8. 执行 $Gulp 时发生了什么 —— 基于 Gulp 的前端集成解决方案(二)

    前言 文章 在windows下安装gulp —— 基于 Gulp 的前端集成解决方案(一) 中,已经完成对 gulp 的安装,由于是window环境,文中特意提到了可以通过安装 gitbash 来代替 ...

  9. Yii2 基于RESTful架构的 advanced版API接口开发 配置、实现、测试 (转)

    环境配置: 开启服务器伪静态 本处以apache为例,查看apache的conf目录下httpd.conf,找到下面的代码 LoadModule rewrite_module modules/mod_ ...

随机推荐

  1. 黑暗之光 Day1

    1. 设置鼠标指针图标 Build Setting -> Player Setting 2. 添加雾的效果 Window->Lighting->Settings. 3. 任意键按下事 ...

  2. Elasticsearch-PHP 概述

    最近在学习使用Elasticsearch,并且是和PHP一起使用的,看到了Elasticsearch-PHP,其实是Elasticsearch为PHP提供的客户端,那么我们来学习一下API文档,如何在 ...

  3. MySQL数据库篇之索引原理与慢查询优化之二

    接上篇 7️⃣  正确使用索引 一.索引未命中 并不是说我们创建了索引就一定会加快查询速度,若想利用索引达到预想的提高查询速度的效果, 我们在添加索引时,必须遵循以下问题: #1 范围问题,或者说条件 ...

  4. linux系统中的进程

    一.fork 在类unix系统中,我们所执行的任何程序,都是由父进程(parent process)所产生出来的一个子进程(child process),子进程在结束后,将返回到父进程去.此一现象被称 ...

  5. 28-组合数(dfs)

    http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=32 组合数 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 ...

  6. eclipse基础环境配置和svn、maven的配置以及maven的安装

    安装eclipse和基础配置 第一步:解压eclipse安装包,直接解压就可以,绿色版安装 第二步:启动eclipse,注意这里的eclipse需要依赖jdk,并且版本需要匹配,否则启动会出 现问题. ...

  7. ROS Learning-032 (提高篇-010 Launch)Launch 深入研究 --- (启动文件编程)ROS 的 XML语法简介

    ROS 提高篇 之 Launch 深入研究 - 01 - 启动文件的编程 - ROS 的 XML语法简介 我使用的虚拟机软件:VMware Workstation 11 使用的Ubuntu系统:Ubu ...

  8. java基础知识汇总(持续更新中....)

    1.java四大特性:抽象.继承.封装,多态 构造函数: http://blog.csdn.net/qq_33642117/article/details/51909346 2.java数据基本类型: ...

  9. Java研发书单

    Java研发书单 计算机基础:<深入理解计算机系统><计算机网络> 网络方面:<TCP/IP协议卷一><unix网络编程卷一>(部分章节,JAVA主要是 ...

  10. tp5写日志