简介 #

官方文档

YKit-Config-WMP(YKit Config for WeChat Mini Program)是为微信小程序项目量身定制的构建方案打包服务。基于开源构建工具 YKit。目标是让开发人员更方便、更快捷的进行小程序项目的开发,同时尽可能减少代码体积,以满足平台对项目 size 的限制。

YKit-Config-WMP 不仅仅是个工具,它也提供了组件机制插件机制环境配置业务隔离数据 Mock 等功能。

之后,计划支持蚂蚁应用、小米应用、即点即用应用等类小程序应用的构建转换

安装 #

  1. ykit-config-wmp 依赖于 ykit,请首先安装 ykit:

    sudo npm install ykit -g --registry=http://npmrepo.corp.qunar.com/
    
  2. 安装 ykit-config-wmp:

    npm install @qnpm/ykit-config-wmp --save --registry=http://npmrepo.corp.qunar.com/
    

快速上手 #

下面通过酒店模块 mp_module_hotel 演示整个开发环境是如何运行起来的。

  1. 首先 clone 要进行开发的模块项目,这里是 mp_module_hotel:
git clone git@gitlab.corp.qunar.com:mini_program/mp_module_hotel.git
  1. 进入项目目录:
cd mp_module_hotel
// 安装工具 ykit-config-wmp
npm install @qnpm/ykit-config-wmp --save --registry=http://npmrepo.corp.qunar.com/
  1. 安装必要的依赖的项目模块 home_qunar、common:
// 确保全局已经安装了 ykit
ykit install common
ykit install home_qunar
  1. 编译项目代码
ykit g

现在整个项目已经编译完成,用微信开发者工具对编译生成的目录 dist 进行预览即可:

打开微信开发者工具 -> 新建项目 -> 选择项目目录为编译生成的目录 dist

PS:也可以使用 ykit g -w 这样 src 目录下内容被修改会实时进行编译, 这样就可以愉快的实时开发编译了。

工程化与目录结构 #

工程化的概念 #

一个小程序项目由三个模块组成:

  • 公共模块 mp_module_common
  • 首页模块 mp_home_xxx
  • 业务模块 mp_module_xxx

home_xxx 包括小程序的首页,common 模块主要是一些公共页面(我的、订单)及公共组件。 一般这两个模块是公司小程序项目必须的。

每个模块对应一个 git 工程。每个小程序也对应一个 git 工程 mp_app_xxx,在其 package.jsonmodules 里配置了组成该小程序所引用的模块。这样同一小程序,不同业务线在独立工程下开发,互不影响。

模块工程目录结构 #

.
├── README.md       # ReadMe
├── dist            # 编译后的代码目录(微信开发者工具创建项目,请选择此目录)
├── node_modules
├── package.json    # 工程配置
├── libs            # 其他模块安装目录
├── src             # 源码路径
└── ykit.js         # Ykit 配置

关于 ykit.js 的配置:

module.exports = {
    plugins: ['wmp'],
    config: function() {

    }
};

业务隔离 #

app.json #

每个业务模块,可以在自己的工程目录下配置仅有关自己业务app.json

假设现有名为 hoteltrain 的两个业务,分别在其项目下有 app.json 配置:

// hotel app.json
{
    "pages": [
        "pages/list/list"
    ]
}
// train app.json
{
    "pages": [
        "pages/search/search"
    ]
}

那么在构建项目时,会自动合并所有模块 app.json 的路由配置到小程序项目最终的 app.json 中,并在每个路由前添加其业务名。以上构建结果:

{
    "pages": [
        "hotel/pages/list/list",
        "train/pages/search/search"
    ]
}

app.js #

每个模块可以定义自己的 app.js。定义规则是 module.exports 导出一个 object 对象,其指定小程序的生命周期函数,不包含其他函数或数据。对于一些其他函数或数据应该写在项目的 app.js 中。 例:

// mp_module_common 模块 app.js
module.exports = {
    onLaunch: () => {
        console.log('Common Launch');
    },
    onShow: () => {
        console.log('Common Launch');
    }
};

注意:mp_home_xxx 模块是小程序入口,其 app.js 即项目 app.js,会去构建小程序项目最终 app.js。定义规则是 object 作为参数传入 APP() 函数中。object 可以添加任意其他函数或数据。

global.wxss #

每个模块可以定义自己的 global.wxss 全局样式。在打包构建的时候会自动在项目的 app.wxss 中引入。

使用 Sass #

如果想使用 Sass 语法进行样式定义,可以将样式文件后缀名 .wxss 改成 .scss.sass,即可使用 Sass。其他不做任何修改,.scss 文件中可以正常引入 .wxss 和其他 .scss 文件。构建打包时,工具会将 .scss.sass 文件编译成 CSS 语法的 .wxss 文件。

基本配置 #

分包加载配置 #

使用小程序分包加载能力。小程序分包加载文档

在项目的 package.json 文件中添加 "subModules": ["packageA", "packageB"] 属性进行分包配置。

模块项目中配置这个只是测试使用。最终发布会由产品确定哪些模块放在分包中,然后公共开发在 mp_app_qunar 项目中配置。分包会在第一次进入分包内页面进行下载,下载完再进行展示。

例如,当前项目有以下路由:

{
    "pages": [
        "pages/index",
        "pages/logs",
        "packageA/pages/cat",
        "packageA/pages/dog",
        "packageB/pages/apple",
        "packageB/pages/banana"
    ]
}

添加分包配置:{ "subModules": ["packageA", "packageB"] }

打包出的分包路由结构如下:

{
  "pages":[
    "pages/index",
    "pages/logs"
  ],
  "subPackages": [
    {
      "root": "packageA",
      "pages": [
        "pages/cat",
        "pages/dog"
      ]
    }, {
      "root": "packageB",
      "pages": [
        "pages/apple",
        "pages/banana"
      ]
    }
  ]
}

环境配置 #

在项目配置的 app.json 中,可以添加 env 配置。例如,项目 app.json 中有如下 env 配置:

{
    "env": {
        "prod": {
            "server": "https://some.com"
        },
        "beta": {
            "server": "https://beta.some.com"
        }
    }
}

注意:mp_home_xxx 模块配置的 app.json 即为项目的 app.json

同样的,在业务 biz 项目中的 app.json 也可以配置 env

{
    "env": {
        "prod": {
            "server": "https://bizsome.com"
        },
        "beta": {
            "server": "https://beta.bizsome.com"
        },
        "beta1": {
            "server": "https://beta1.bizsome.com"
        }
    }
}

按照以上配置,在默认的环境 prod 下,构建完成后全局变量里会存在:

global.__envType = 'prod';
global.__env = {
    "server": "https://some.com",
    "biz": {
        "envType": "prod",
        "server": "https://bizsome.com"
    }
};

开发者,可以在 ykit generateykit pack 命令后,加 -e | --env 参数进行环境切换。例如 -e beta,此时环境如下:

global.__envType = 'beta';
global.__env = {
    "server": "https://beta.some.com",
    "biz": {
        "envType": "beta",
        "server": "https://beta.bizsome.com"
    }
};

业务和主项目可以使用不同的环境,例如参数为 -e beta,biz:beta1,非 biz 的其他业务以及主项目都为 beta 环境,biz 业务为 beta1 环境。

别名配置 #

在项目和业务项目配置的 app.json 中,可以添加 alias 配置,key 即为别名,value 引用文件路径,相对于项目根路径:

{
    "alias": {
        "user": "./user/user.js",
    }
}

项目中 require('user'),即可引用 ./user/user.js 文件

资源配置 #

资源文件需要在项目和业务项目配置的 app.json 中,添加 asserts 配置。项目中除了 .js.json.wxml.wxss 文件,其他资源文件需要配置 asserts。这样项目构建时才会加载这些资源文件。例如项目根目录下有 images 文件夹,存放图片,则需要配置:

{
    "asserts": ["images"],
}

页面忽略配置 #

在项目配置的 app.json 中,可以添加 ignorePages 配置,添加忽略构建的页面路径,小程序中将不存在该页面也访问不到该页面。例:

{
    "ignorePages": ["pages/my/my"]
}

路径跟项目 app.json 中配置的路由相同。

高级配置 #

获取配置参数 #

可以通过 Config('xxx') 获取项目 package.json 中的配置参数。例:

// package.json
{
    "version": "1.0.0"
}

// 使用 Config 获取
var v = Config('version');

// 构建后代码 =>
var v = ('1.0.0');

Mock 配置 #

开启 mock 模式之前需要配置 mock 接口以及 mock 数据。

  1. 在项目根目录下创建 mock 文件 ./mock/mock.js
  2. mock.js 里书写 mock 配置信息,例:
    module.exports = {
     // 配置接口 host
     'wxapp.xxx.com': {
         // [配置接口路径 hostname]: [mock 数据]
         '/api/user/info': { name: 'ming.xiao', age: 18 },
         '/api/admin/info': { name: 'san.zhang', age: 30 }
     }
    }
    
  3. 运行 ykit g --mock 构建项目并开启 mock 模式

现在打开小程序开发者工具,选择 dist 作为项目目录。我们发现 https://wxapp.xxx.com/api/user/info 请求变为了 https://127.0.0.1/api/user/info,请求的是本地开启的 mock server。并且返回我们配置的 mock 数据 { name: 'ming.xiao', age: 18 }。这就是 mock 最简单的使用方式。

注意:请在小程序开发者工具侧边栏『项目』配置中勾选『开发环境不校验请求域名』,否则 mock 请求不在合法域名下,无法成功发送。

mock 数据模板 #

mock 数据支持 json 对象,对象还支持数据模板规范。详见 Mock.js 语法规范,例:

// 模板
{
    'number1|1-100.1-10': 1,
    'regexp1': /[a-z][A-Z][0-9]/,
}
// =>
{
    "number1": 12.92,
    "regexp1": "pJ7",
}

mock 函数 #

mock 数据还支持函数,函数返回对象将作为数据模板。函数接受一个 req 对象作为参数。req 类似 Node http.createServer((req, res)...req,有 urlheaders 等属性。req 还有一个特殊属性 param,它是包含 querybody 中请求参数的对象。例:

// mock.js
{
    'api/info': function(req) {
        return req.param;
    }
}

// request
// url => https://wxapp.xxx.com/api/info?username=zzz
// body => password=123456

// 返回数据
{
    username: 'zzz',
    password: 123456
}

注意:忽略 host。看到上面的 mock.js 配置中,我没有配置 host,直接配置的 api/info 接口,这是允许的。这将忽略 host,只要接口路径匹配即请求 mock。

推荐配置目录结构 #

由于 mock 数据肯能比较冗长,不推荐数据直接写在接口后面,而是单独提取成文件。这样 mock.js 文件,接口配置一目了然。例:

// mock.js
module.exports = {
    'wxapp.xxx.com': {
        '/api/user/info': require('./user.js'),
        '/api/admin/info': require('./admin.js')
    },
    'api/info': require('./info.js')
}

然后在 ./mock 里有如下目录结构:

.
├── mock.js    // mock 接口
├── user.js    // mock 数据
├── admin.js   // mock 数据
└── info.js    // mock 数据

开发者 #