Technology selection

Our project mainly uses the following technology development, and some other auxiliary tools.

  • react
  • react-router
  • redux
  • react-redux

Development and online environment

The development environment

Since the project is front-to-back, we need a complete development environment that includes the following features:

  • The Mock data
  • Webpack implements a compile refresh
  • Convenient combination of front and rear ends

Based on these requirements, we built a complete development environment based on Express, Webpack, and Webpack-dev-Middleware.

As you can see, all browser requests are intercepted by the local Node.js service. Static resource requests are delegated to Webpack-dev-Middleware, and interface requests depend on the environment.

Local development

When ENV = ‘development’, that is, the development environment, the native mock data is read directly to render the page.

Front and rear end intermodulation

When ENV = ‘API’, which is what we consider a federated environment, node.js forwards interface requests to the actual back-end service address that needs to be federated, avoiding cross-domain issues that can be caused by direct calls.

This allows you to directly use native development code and back-end tuning, greatly improving efficiency and eliminating the need to build and deploy to the server every time.

The online environment

The front and back ends are deployed separately, and all static resources are placed on the CDN (example.cdn.com).

. That is to say our page in example CDN/index. The HTML here, but the request of interface in example.163.com/api/xxx, we certainly can’t let users to visit example.cdn.com/index.html directly, this is not reasonable, And there are cross-domain problems.

So how do we get our HTML page when we visit example.dai.163.com? See below:

Setting up an nginx between the client and the backend service, example.dai.163.com we visited had two requests:

  • HTML page resources
  • Interface request

If it is a page request, then nginx forwards it to the CDN. If it is not a page request, nginx forwards it to the backend service to respond to the interface request.

After getting the page, all other static CSS, JS and other resources are directly requested to the CDN, there is nothing to say here.

The data flow

We manage the data flow with redux.

Let’s look at this picture.

First, the Store was generated using middleware and Reducer, and then the initial state of the project was obtained, from which the initial state of the page was rendered.

Take the Home page as an example. First, the Home uses the connect method provided by react-Redux to get the initial state as the prop of the Home. The Home consists of multiple sub-components, and the data required by these components is passed by the Home to its sub-components through props.

After the initial state of Home is loaded, we need to make a back-end request to retrieve some user data. At this point, we distribute an action of the following format:

{
  types: ['home/start','home/success','home/failure'],
  payload: {
    api:
    ...
  },
  meta: {
    isApi: true
  }
}Copy the code

All actions will pass through the middleware in the order we set them.

In this case, our action will be hit by callApiMiddleware via isApi identification in meta and will do the corresponding thing.

For example, in this middleware, we make real interface requests, distribute corresponding actions when the request succeeds or fails, and do some unified business logic. For example, we have a unified convention on the code value of the interface returned by the back end. Assume that 1 is successful, 2 is failed, and 3 is not logged in. This business logic can then be handled in middleware.

When the request is successful and the page is rendered, suppose the user clicks a button that needs to invoke some functionality of Native, such as taking a photo. So we distribute a camera/start action that evokes the camera function:

{
  types: ['sdk/start','sdk/success','sdk/failure'],
  payload: {
    command:
    ...
  },
  meta: {
    isSDK: true
  }
}Copy the code

Similarly, this action is recognized and processed by EpaySDKMiddleware, and to ensure security when calling up native, we need to make a backward request to get a signature. This will distribute an interface request action in EpaySDKMiddleware, which will also need to run through all the middleware. The action requested by this interface will be handled by callApiMiddleware as in the above process.

The existence of middleware makes the whole process very clear. The middleware of interface request only makes interface request, and the middleware of calling native interface only makes call to Native. When the call to native interface needs to make back-end interface request, it distributes an action to the middleware of interface request.

Each middleware only focuses on its own business, which not only facilitates subsequent maintenance, but also provides a good way to expand.

A case in point

Suppose we are configured with one of the following routes.

{ component: App, path: '/', onEnter: initLogin(store), indexRoute: { getComponent(nextState, cb) { require.ensure([], require => { cb(null, require('.. /views/Home').default) }, 'Home') }, onEnter: initHome(store) }, childRoutes: [ createActivateRoute(store), { path: 'test', indexRoute: { getComponent(nextState, cb) { require.ensure([], require => { cb(null, require('../views/Test').default) }, 'Test') } } }, ... ] }Copy the code

Let’s look at a complete process with the React-route. When we enter example.dai.163.com/index.html/#/ browser.

First, as mentioned in the online environment section at the top, you need HTML, CSS, and JS to get to the page.

The Provide and Router components are then rendered to Provide store injection and routing control, respectively.

At this point, route matching is triggered for the root path, and then the root component APP is loaded. Then, according to the route matching rules, the IndexRouter is matched and the Home component is loaded.

The rest of the story is the same as in the previous data flow section.

conclusion

On the basis of the complete separation of front and rear ends, with the help of a set of perfect development environment, we can greatly improve the development efficiency and reduce the cost of front and rear end joint adjustment.

At the same time, with the help of Redux idea, we can realize a one-way data flow, so that we can achieve a very clear data flow. And, with the help of middleware, we can more effectively control the process of data flow. Provide unlimited imagination space for the expansion of the following projects.