Skip to main content

特性矩阵配置

特性矩阵是reSKRipt独有的概念,它用于声明一个项目可能发布的多个版本(或多个环境)中不同的功能标记,并在skr build时自动构建出多个入口HTML文件。只需要将所有的构建结果发布,并将不同的用户导向不同的HTML,即可灵活地进行灰度、小流量实验等工作。

使用特性矩阵

定义矩阵

项目配置文件中增加featureMatrix导出,它是一个对象,且至少包含一个叫做dev的属性:

export default configure(
'webpack',
{
featureMatrix: {
stable: {},
insiders: {},
dev: {},
},
}
);

这个对象的每一个属性代表一个构建后的入口(dev除外),我们称之为“特性名称”,对应的值则称为“特性名”。最终生成的HTML会以{entryName}-{featureName}.html命名。例如由src/entries/index.tsx构建的insiders版本,就会是index-insiders.html

每一个特性集是一个对象,对象内可以是任意的键-值对。

需要注意的是,一个特性集中的值必须是可以被JSON.stringify序列化的,如基本类型(数字、字符串等)、简单的数组、对象都可以,但你不可以使用functionMapSet这些类型。

引用特性

在项目的源码中,可以使用skr.features.someKey来引用某一个特性。引用特性的代码类似于process.env.NODE_ENV,必须是一个完整的串,不可以有任何的动态性,例如下面的写法都是不可用的:

const myKey = 'someKey';
skr.features[myKey];

for (const key of skr.features) {
// ...
}

Object.keys(skr.features).filter(k => k.startsWith('app'));

推荐特性名

在常见场景下,我们推荐使用如下特性名称区分不同流量:

  • 全流量:stable
  • 小流量:insiders
  • 内部试用流量:pioneer

其它场景下,如版本具有明确的业务含义,可以随意取名。

一些注意点

特性集结构

featureMatrix中的每个特性集的结构必须完全一致,如果不同的特性集有不同的属性名称,则会在构建过程中报错:

Build target foo & bar have incompatible feature schema

本地开发用特性

在本地开发即skr dev时,会默认使用dev这特性集。这也是为什么前文有提到featureMatrix中至少要有dev这个键。

同样的,dev的结构必须与其它特性集保持一致。并且dev这一特性集默认不会在构建时使用,即并不会有类似index-dev.html这样的最终产物。

如果你需要针对另一个特性集进行调试,可以使用skr dev --build-target={featureName}来指定。

从构建中排除其它特性集

如上文所述,默认情况下dev这一特性集是被排除在构建之外的,如果你需要同样排除其它的构建集,也可以使用build.excludeFeatures配置来解决。在使用这个配置时,原有的排除dev的行为会被禁掉,你需要手动把它加回来。

例如你想要同时排除devlocal这两个特性集,那么这样配置:

export default configure(
'webpack',
{
build: {
excludeFeatures: ['dev', 'local'],
},
}
);

正确使用

推荐场景

在以下情况中,我们推荐通过特性矩阵来管理:

  • 功能开关,如在小流量中启用某个功能,但在全流量中暂不可见。
  • 一个文案在不同的版本上显示不同的内容。

总的来说,特性矩阵适合用来区分不同的用户,让不同的人看到不同的内容。

不推荐场景

首先,我们不推荐用特性矩阵来区分不同的环境,例如这样的诉求:

在测试环境中不要采集用户行为数据,但在线上环境中打开采集能力。

类似这样的诉求,它是对环境的区分。如果我们同时在特性矩阵中区分环境和用户,就会形成“环境X用户”的条件组合,比如你既有stableinsiders两个用户版本,又有testonline两个环境版本,那最终一定会出现testStableonlineInsiders这种组件的版本,随着用户和环境版本增多,组件版本是不可控的。

因此,对于环境我们依然推荐用process.env来做区分,例如:

if (process.env.TRACK !== 'off') {
enableUserTrack();
}

其次,特性矩阵不可用来声明运行时的特性,特性矩阵是在编译期被常量替换的,会在运行时完全丢失。