Skip to content

开发者文档

cpselvis edited this page Nov 28, 2019 · 3 revisions

本篇文档主要介绍业务接入 Feflow 的方法,可以通过以下两种方式接入 Feflow:

  • 模板 + 开发套件(官方推荐):模板用于初始化生成项目目录结构,开发套件用于提供项目的开发阶段构建(dev)、生产环境构建(build)、代码ESLint检查(lint)、Changelog 生成 (changelog) 等等命令工作流。
  • 插件:适合团队中基于插件去实现工具链体系,如:将组件平台、数据 Mock 平台、图片压缩工具等通过插件命令形式提供出来。

1. 方式一:模板 + 开发套件(官方推荐)

1.1 开发一个模板

Feflow 的模板开发完全基于 Yeoman,如果你已经会开发一个 Yeoman 脚手架了,可以跳过这个章节。但要注意以下要点:

  • 脚手架项目下 package.json 文件的 description 字段不能为空。因为在用户选择脚手架时,Feflow 需要用这个字段来提供脚手架说明。

如果你没有 Yeoman 脚手架的开发经验,那也别急,接下来会给一个入门指导,更详细的开发文档请阅读官方文档

1.1.1 准备工作

全局安装 yogenerator-generator

npm install yo generator-generator -g
# or yarn global add yo generator-generator

这里借助了 Yeoman 以及他们写的脚手架生成器,目的是为了快速让大家创建出自己的脚手架。这不是必须选项,但在本教程中最好是按这个步骤来,否则下面可能没法继续。

1.1.2 生成脚手架模版

现在,只需一行命令即可生成一个脚手架模版:

yo generator

再次强调,生成过程中询问的 Description 一定要填写,Feflow 会使用它来提供脚手架说明。

你可能会注意到,生成出来的脚手架模版的项目名是以 generator- 开头的,如果你自己手动创建一个脚手架,这也是必须的。

让我们来看一下生成的脚手架模版的主要目录结构:

├── generators/
|   └── app/
│       ├── index.js
│       └── templates/
│           └── dummyfile.txt

其中,generators/app/index.js 文件就是脚手架生成项目的逻辑,而 generators/templates/ 文件夹就是一个项目模版。后面我们主要就是在这两个地方做定制,改造出自己的脚手架。

1.1.3 创建自己的脚手架

1.1.3.1 项目模版

对于团队来说,一般都会有自己的项目目录结构规范,或者是有现成的项目模版,那要转换成 Yeoman 脚手架的项目模版就很简单了,直接找个项目或者把项目模版复制粘贴到 generators/templates/ 文件夹下即可。但是要接入 Feflow 还需要做些工作。

对于个人或者还没有项目模版的团队来说,首要任务当然是规划好自己的项目模版了。在本文示例中,我们将创建一个非常简单的、支持 React 的项目模版。

1.1.3.2 创建模版

我们的模版主要的目录结构如下:

|- src # 示例源码
    |- index.html # HTML 入口
    |- index.js # JS 入口,也是 Webpack 打包的入口
|- _babelrc # 处理 JSX 的配置
|- .feflowrc.json # 这个文件是必须的,作为项目和 Feflow 的桥梁

其中,如果项目中含有 .babelrc 这样的文件,推荐在模版中将 . 换成 _,写成 _babelrc 这样的形式。

另外,.feflowrc.json 是必须的配置文件,Feflow 会读取其中的构建器配置来对 src 中的源码进行打包构建。

这里要说明一下,Feflow 定义了一个构建器的概念,实际上它指的就是把构建的代码抽离出项目形成的 NPM 包。这样做的好处在于,团队内部的项目遇到构建工具升级的时候,无需对每个项目都进行一遍升级,只需要升级构建器并更改项目中 .feflowrc.json 中的配置即可。其他的好处例如节省本地空间、节省项目安装依赖包的时间、统一构建规范等等。

下面是我们这个项目示例的 .feflowrc.json 的配置:

{
    "devkit": {
        "commands": {
            "dev": {
                "builder": "@tencent/feflow-devkit-basic:dev",
                "options": {}
            },
            "build": {
                "builder": "@tencent/feflow-devkit-basic:build",
                "options": {}
            },
            "lint": {
                "builder": "@tencent/feflow-devkit-basic:lint",
                "options": {}
            },
            "changelog": {
                "builder": "@tencent/feflow-devkit-basic:changelog",
                "options": {}
            }
        }
    }
}
1.1.3.3 动态模版内容

如果你想在你的项目模版中加入动态的内容,例如根据询问用户得到的答案来填充项目名称,你就可以在项目模版下的 package.json 中这样写:

{
  "name": "<%= name %>"
}

Yeoman 模版支持 <%= variable > 这样的语法来填充动态内容,其中的 variable 是如何传进来将会在后面看到。

1.1.4 项目生成逻辑

有了项目模版之后,我们还缺少根据项目模版创建一个项目的逻辑。最简单逻辑就是复制一份模版到当前目录下,当然,高级点的脚手架一般都会有如下过程:

  1. 询问并接收用户的输入;
  2. 执行一些自定义的脚本;
  3. 根据用户输入和脚本执行的结果渲染项目模版,并生成于当前目录下。

上述的这些逻辑统统都写在 generators/app/index.js 文件中。通常来说,这个文件都满足如下格式:

const Generator = require('yeoman-generator');

module.exports = class extends Generator {
    // 初始化阶段
    initializing () { /* code */ },
    // 接收用户输入阶段
    prompting () { /* code */ },
    // 保存配置信息和文件
    configuring () { /* code */ },
    // 执行自定义函数阶段
    default () { /* code */ },
    // 生成项目目录阶段
    writing () { /* code */ },
    // 统一处理冲突,如要生成的文件已经存在是否覆盖等处理
    conflicts () { /* code */ },
    // 安装依赖阶段
    install () { /* code */ },
    // 结束阶段
    end () { /* code */ }
}

Yeoman 提供了一个基础的生成器类 Generator,我们基于它扩展自己的生成逻辑。Generator 类定义了八个生命周期,它们会按上述代码的顺序依次执行。

示例脚手架的生成逻辑可阅读这里

1.1.5 调试

现在,你的脚手架就定制好了,让我们来试一试吧。先安装在 Feflow 主目录下:

cd <your-path>/generator-startkit-demo
npm link
cd ~/.feflow
npm link generator-startkit-demo

然后再编辑 ~/.feflow/package.json 文件(可用 vi ~/.feflow/package.json 编辑),在 dependencies 字段中添加一行 "generator-startkit-demo": "1.0.0"(版本号随意)。目的是为了让 Feflow 找到你的脚手架。

现在,可以在你想创建项目的位置运行 feflow init 了。你会看到你的脚手架被展示出来了,选择它,就能开始项目的创建了。

generator-feflow-example 的源码地址是 https://github.com/feflow/generator-feflow-example

1.2 实现开发套件

Feflow v0.16.0 版本重新设计了它的生态体系,去掉了构建器、部署器等概念,整合为一个套件。它将项目的构建、部署、代码检查等功能都整合在一起,并且套件会跟随项目一起走,存储在项目的 node_modules 里。

这里我们重点对如何开发一个 Feflow 套件进行讲解,以 feflow-devkit-miniprogram 为例。

1.2.1 配置 devkit.json 文件

首先,我们需要创建一个空文件夹,命名为 feflow-devkit-miniprogram,并且在文件夹下新建一个 devkit.json 或者 devkit.js 文件,以 devkit.json 为例,配置如下:

{
  // 必须,builder 包含各种构建命令的集合
  "builders": {
    // 开发者自己定义,dev 意味着套件包含 dev 命令,一般本地开发命令约定俗成就是 dev
    "dev": {
      // dev 命令对应的真正实现脚本
      "implementation": "./lib/command/dev.js",
      // dev 的描述,会在 fef -h 的时候显示出来
      "description": "Mini program development mode."
    },
    // 套件 build 命令的配置,一般构建部署时的构建就是用 build 命令
    "build": {
      "implementation": "./lib/command/build.js",
      "description": "Build a mini program bundle."
    }
    // ...... 其他命令
  }
}

1.2.2 创建命令对应的实现文件

配置好了 devkit.json 文件,接下来就是一一实现里面定义的各个命令对应的脚本。以 dev 命令为例,通过上述脚本地址可以知道我们需要在 feflow-devkit-miniprogram 下创建一个 lib 文件夹,然后在 lib 文件夹下创建 command 文件夹,最后在 command 文件加下创建 dev.js 文件。当然,文件路径可以自定义,这样的创建文件就按照自己定义的路径去创建。

dev.js 文件需要向外部暴露一个函数,当执行 fef dev 的时候其实就是执行暴露出来的函数,如下所示:

const buildDev = () => {
    // 真正的构建脚本
    const devServer = require('../build/dev-server');

    return devServer.then((response) => {
        console.log('response', response);
    })
        .catch(error => {
            console.log('error', error);
        });
};
module.exports = buildDev;

具体构建的脚本代码是什么样子,根据不同的构建需求决定,我们这里就不继续展示了。

1.2.3 调试和发布

开发好了套件,就要开始调试了,这里和以前构建器的调试有点区别,你需要将套件 npm link 在项目的 node_modules 里面,而不是 ~/.feflow 的 node_modules 里面,项目里通过 .feflowrc.json 文件来声明项目的命令所对应的套件命令,格式如下(以 .js 格式的文件为例):

module.exports = {
    // 必须
    devkit: {
        // 必须,代表着 feflow 的命令
        commands: {
            // 推荐,代表着 fef dev 的命令
            dev: {
                // 必须,代表着 fef dev 命令对应执行的套件命令,这里表示使用套件 @tencent/feflow-devkit-miniprogram 的 dev 命令,配置格式为 `<套件>:<命令>`
                builder: "@tencent/feflow-devkit-miniprogram:dev",
                // 可选,如果上述套件命令支持一些配置,可以写在这里
                options: {}
            },
            // 推荐,代表着 fef build 的命令
            build: {
                // 必须,代表着 fef build 命令对应执行的套件命令,这里表示使用套件 @tencent/feflow-devkit-miniprogram 的 build 命令
                "builder": "@tencent/feflow-devkit-miniprogram:build",
                // 可选,如果上述套件命令支持一些配置,可以写在这里
                "options": {}
            }
        }
    }
}

调试 OK 后就可以发布了。

2. 方式二:插件开发

Feflow v0.16.0 版本作为一个全新出发的版本,对插件的支持方式也发生了变化,主要表现为:不再用全局的 feflow 对象来注册命令,而是暴露一个函数,注册命令的方法在函数首个参数的上下文内。这么说还是有点抽象,直接看下面两个图对比一下就明白了:

老的方式

新的方式

下面的图展现的就是新的命令注册方式,可以看到,新的注册方式更加灵活。

你可以用新的插件开发方式重温一遍官方文档上加法运算插件的开发,官方仓库是 feflow-plugin-example。入口代码如下:

const calculate = require('./calculate');

module.exports = (context) => {
    const calculator = calculate(context);
    const { args } = context;

    // 注册一个 add 命令
    context.commander.register('add', '加法运算器', () => {
        // args 是 add 后面的参数,已被 minimist 库解析
        // 例如 `fef add 1 2 3`,args 就是 { _: [1, 2, 3] },
        // 再比如 `fef add -x 1 -y 2 --z-value 3 4 5 6`,args 就是 { _: [ 4, 5, 6 ], x: 1, y: 2, 'z-value': 3 }
        // 调用主要的逻辑
        return calculator.add(args._);
    });

    // 注册乘、除、减三个命令
    context.commander.register('multiply', '乘法运算器', () => calculator.multiply(args._));
    context.commander.register('minus', '减法运算器', () => calculator.minus(args._));
    context.commander.register('divide', '除法运算器', () => calculator.divide(args._));
};

另外,开发过程中还需要注意的是上下文提供的 API 有所精简和变化,目前 context 对象有以下几个属性:

{
  root: '/Users/<username>/.fef', // .fef 主目录的位置
  rootPkg: '/Users/<username>/.fef/package.json',  
  args: { _: [ 1, 2 ] }, // 参数
  version: '0.16.0-alpha.7',
  config: { packageManager: 'tnpm' }, // feflow 配置
  commander: Commander, // 命令管理器
  logger: Logger // 日志模块
}

像上面那个加法器的例子老版本就用到了 .log 方法,在新版本中是没有的,得用 .logger 代替。