1

foreword

What is grayscale publishing? Wikipedia's explanation is as follows.

Grayscale publishing refers to a publishing method that can smoothly transition between black and white. AB test is a grayscale release method, allowing some users to continue to use A, and some users to start using B. If users have no objection to B, then gradually expand the scope and migrate all users to B. Grayscale release can ensure the stability of the overall system, and problems can be found and adjusted at the initial grayscale to ensure their influence.

As can be seen from the above, the main functions of grayscale publishing are as follows:

  1. Reduce the impact of direct full-scale release, let a small number of users use the new version first, if any problems are found, they will be repaired in time, and new functions will be released in full after verification that there are no major problems
  2. Determine whether the new version needs to be released in full by comparing the data of the new and old versions

Overview

There are many ways of grayscale publishing. You can distinguish the server, client, and web front-end according to the end. There is no best, only the business scenario that is more suitable for you.

As you can see above, several common grayscale publishing methods have their own advantages and disadvantages. Since our company has a complete big data AB test solution, the front end only needs to pay attention to the field identifier returned by the interface to do specific page loading. Logic, today focuses on how to do grayscale publishing in the front-end using the Vue framework. In Vue, it can be mainly divided into the following two situations:

Component level:

  1. Component-level dynamic control only needs to return the corresponding scheme ID from the backend.

Page level:

  1. The access address of the front-end page remains unchanged, and the AB test tag field is agreed with the back-end staff. The front-end returns different content according to the field to load the corresponding page.
  2. The old and new functions distinguish two page addresses, and the jump page address is controlled by the backend. The front end of this solution does not need too many changes, so this article will not explain much.

Let's first look at the daily processing method. There may be multiple places on a page to judge the AB test logic, or more AB tests are performed at the same time. The logic complexity of such page code is relatively high, and it is not clean and easy to understand. When a new AB test is added or an AB test needs to be decided, the cost of modifying the code is high, which reduces the efficiency of code maintenance.

 <template>
    ...
    <test-a v-if="testA" />
    <test-b v-else-if="testB" />
    ...
    <div v-if="testA">
        ...
    </div>
    <div v-else-if="testB">
        ...
    </div>
    ...
</template>
<script>
    ...
    if (testA) {
        ...    } else if (testB) {
        ...
    }
</script>

Next, let's start the main topic of our article today, and see what ways can solve the above problems.

component level

If it is just a simple grayscale of two widget functions, it can be processed directly with v-if

 <testA v-if="testA" />
<testB v-else />

If multiple functions are tested at the same time, it can be implemented by adding a special isattribute to the <component> element of Vue. The currentTabComponent can be obtained based on interface acquisition or other front-end calculations.

 <component :is="currentTabComponent"></component>

page level

Scheme 1: New entry page distribution

Add an entry page, upgrade the old and new versions of the page into a component, and add an interface query to the entry page, which can be loaded through v-if or through Vue's <component> element with a special is attribute Page components. The following is an example of querying code through the interface. Pre-querying through the interface will bring a certain delay loading of the interface. Depending on the response speed of the interface, we can also obtain it by adding parameters to the URL. At this time, the URL is spliced with parameters from the backend and then return, so that an interface query can be avoided.

 <template>
   <component :is="testId"></component>
</template>
<script>
  import IndexA from './index-a'
  import IndexB from './index-b'
  import {
    getTestID
  } from '@/api/getTestID'

  export default {
    name: 'index',
    components: {
      'index-a': IndexA,
      'index-b': IndexB
    },
    data() {
      return {
        testId: ''
      }
    },
    created() {
      this.getTestID()
    },
    methods: {
      async getTestID() {
        const { testId } = await getTestID({
          xxx: xxx
        })
        this.testId = testId
      }
    }
  }
</script>

Loading page-level components directly in this way will increase the size of the file. You can change the loading method of page components to asynchronous components to improve page loading speed.

 components: {
    'index-a': () => import(/* webpackChunkName: "index-a" */ './index-a'),
    'index-b': () => import(/* webpackChunkName: "index-b" */ './index-b')
}

Scheme 2 High-level component scheme

In the routing configuration, the grayscale identification data is obtained from the interface for routing distribution. If you do not want to increase the overhead of the interface query, you can also return the identification data from the URL parameters. In this method, the parameters need to be spliced in advance.

The advantage of high-level components is that all the loading logic that requires grayscale is in the routing configuration file, which is maintained uniformly, and components can be reused. There is no need to add an entry file for each page that requires grayscale.

component code

 <template>
  <component :is="com" />
</template>
<script>
export default {
  name: 'DynamicLoadComponent',
  props: {
    renderComponent: {
      type: Promise
    }
  },
  data() {
    return {
      com: () => this.renderComponent
    }
  }
};
</script>

router.js configuration

 {
  path: 'originPath',
  component: () => import('@/views/components/DynamicLoadComponent'),
  name: 'originPath',
  props: (route) => ({
    renderComponent: new Promise((resolve, reject) => {
      // 根据 route 拼接参数获取加载页面
      if (route.query.testA) {
          resolve(import('@/views/testA'));
      } else {
          resolve(import('@/views/testB'));
      }
      // OR 根据接口返回标识动态加载页面
      getAPIData()
        .then((response) => {
          if (response.testA) {
            resolve(import('@/views/testA'));
          } else {
            resolve(import('@/views/testB'));
          }
        })
        .catch(reject);
    }),
  })
}

Scheme 3 Dynamic Router.js introduction

If there is a large area of page replacement, this method can be used. For example, the change of the back-end development language leads to changes in the interface address and the content of the returned fields, so there will be a transitional use for a period of time. The page still retains the original scheme.

Modify router.js, extract the original routing configuration into default.js, and then create a new java.js to write the routing configuration of the new scheme, and dynamically load the routing configuration file based on front-end calculation or interface return identification.

 import Vue from 'vue'
import Router from 'vue-router'
import { isHitJavaAPI } from '@/config'

Vue.use(Router)

const router = new Router({
  mode: 'history'
})

const computedRouterDirectory = (routeFile) => {
   let routerConfig;
   const requireRouter = require.context('.', false, /\.js$/);
   routerConfig = requireRouter.keys().filter(file => file === `./${routeFile}.js`)[0];
   if (routerConfig) {
     routerConfig = requireRouter(routerConfig)
     routerConfig.default && router.addRoutes(routerConfig.default);
  }
}

if (isHitJavaAPI()) {
   computedRouterDirectory('java')
 } else {
   computedRouterDirectory('default')
}

The isHitJavaAPI method is the logic of hitting grayscale. If the front-end is doing grayscale, it can be calculated based on deviceID or UA. If this is the call interface acquisition scheme, it needs to be changed to synchronous call.

Summarize

This article mainly introduces several grayscale schemes at the page level. The trial scenarios of each scheme have their own advantages and disadvantages. For example, the new entry file is mainly for the page that changes greatly and the current project only has one in progress. Grayscale test; high-level components are suitable for multiple grayscale tests in progress in the current project, and components can be reused; dynamic loading of routing configuration files is mainly for grayscale tests with large-scale page UI or logic replacement in the current project; The above solutions can greatly improve the maintainability of the code and decouple the grayscale logic and business code logic. When there is no problem with the grayscale test and it needs to be fully launched, we only need to modify the entry logic, without the need for business code. Modify the grayscale logic one by one in the code.

In addition to the several methods introduced in this article, there are also other loading methods, such as routing hook functions to perform dynamic jumps after interception, or requests to the backend, and the backend to perform redirection processing. Each method has its own advantages and disadvantages, depending on whether it is the most suitable solution for your current situation. If you have other plans, please leave a message to communicate with us~

refer to

Vue Router loads different components based on background data
components-dynamic-async


南城FE
2.2k 声望574 粉丝