Write in the front

Take 10 minutes, insert 100 lines of code, 0 extra dependencies, make your project mock support, support any WebPack project, easy to use

At present, we have reformed the company’s traditional PC project and react-Native project, and the results are good, so we want to share them with you

Write a small demo github.com/imaoda/gene… For the experience

Advantages of this scheme

Regular mocks are:

  • Utilize devSever for WebPack
  • Start services at the Node layer
  • Charles agent
  • Use the Chrome plugin to proxy mock services
  • Intercept request(This scheme)

Here are some of the reasons why we mock:

  • It requires various configurations and is too troublesome to use
  • High learning cost, incorrect configuration does not take effect
  • React-Native, small programs and other environments are not used
  • It is not possible to debug mocks on mobile real machines
  • There are learning and configuration costs for project newcomers

Advantages of this scheme:

  • No complex configuration
  • 0 rely on
  • A fool’s experience
  • Retrofitting is easy based on old projects(IT took me less than 10 minutes)
  • Mock data is managed and maintained in project centralization
  • That is, the configuration takes effect
  • Support for all types of requests (XHR Fetch WX.Request…)
  • Does not affect the packaging volume
  • The production environment is not affected

The theory

It’s still request interception in nature, and it’s not new, but it’s the detailed processing techniques that will make this mock scheme silky and easy to use

For common requests such as AXIos, FETCH, wX. request, not all requests have an interceptor method, and interceptors are not universal, usually our project will do request reencapsulation, such as:

  • BaseURL is populated according to the environment
  • Cookie/storage handling
  • The exception window is displayed
  • The loading chrysanthemum is displayed in the mobile terminal maintenance request queue
  • The fetch provides a timeout
  • Mock

For example, we encapsulate the fetch to mock the request

import mockList from '.. /.. /mock'; // Introduce the written mock data

// Encapsulate the fetch. If the URL matches the URL, the mock data is returned. Otherwise, the mock data is returned
export default async function request(url) {
  const resArr = mockList.filter(item= > item.url === url); 
  return resArr[0] | | (await fetch(url).then(i= > i.json()));
}
Copy the code

Processing techniques

How do I import mock data in bulk?

For example, we import all other files under mock/index.js and export them together, as shown in the figure below:

The trouble is that once the directory structure changes, such as adding, deleting, bulk adjusting, nesting folders, etc., we need to modify the mock/index.js file frequently, import the data, merge it, and export it

So how can we conveniently introduce the full amount?

Read the entire mock folder using fs.readdirSync.

The idea is right, but it doesn’t work; After all, this is a front-end project, not a Node project. The fs.readdirSync function is handled at runtime, and the front-end project is already running on the browser side.

We can solve this by using require.context, which is neither commonJS nor ES Module syntax, but is provided by WebPack

Webpack lexes into the API at compile time, puts the code into the Node runtime for execution, and concatenates the results into the packaged Module

userequire.contextBatch introduction

After a long theory, let’s use require.context to introduce it. This routine is relatively fixed, so there is no need to deliberately understand

let routes = [] // Collect all mock data

/ / to traverse the mock directory, open the recursive traversal, matching (js | | ts JSX | TSX) at the end of the file
const ctx = require.context('.. /.. /mock'.true./(js|ts|jsx|tsx)$/);

// Use CJS syntax to import esM exported files, add.default
ctx.keys().forEach((file) = > {
    const content = ctx(file).default;
    if (content instanceof Array) {
        routes = [...routes, ...content];
    } else console.warn(` mock file${file}Format is not array ');
});

// Export all
export default routes;
Copy the code

Tips for starting mocks

There are many ways to turn mocks on and off, but in general, the best practice is to add a command to the package.json script, such as

"script": {
  "build": "..."."dev": "..."."mock": "xxx dev --mock"
}
Copy the code

Inject a variable into the code via WebPack’s definePlugin that tells you whether to start debugging with a yarn mock command:

// In the webPack configuration, add:
new webpack.DefinePlugin({ __IS_MOCK__, process.argv.includes('--mock')})// Minimist is not used to parse parameters for simplicity
Copy the code

At this point, the constant __IS_MOCK__ has been injected into the business code

Finally, let’s make a small change to the request we wrapped earlier

export default async function request(url) {
  Return if mock is not enabled
  if(! __IS_MOCK__)return await fetch(url).then(i= > i.json())
  
  const resArr = mockList.filter(item= > item.url === url); 
  return resArr[0] | | (await fetch(url).then(i= > i.json()));
}
Copy the code

Configuration is good, start to use!

Commit to git repository, pull down any group, just 2 steps, start the mock

  1. Create files in the mock folder with contents such as
/ / xx. Js file
export default[{url: '/user/id'.data: 10086.code: 0 },
  { url: '/user/name'.data: 'wyf'.code: 0},];Copy the code
  1. yarn mock (Depending on the command you just configured

Other in-depth discussion points

At this point, the main content is complete, if you want to continue the optimization exploration in the project, you can continue to look at the following sections

Whether gitignore Mock folder

After ignore, the mock folder will not be included in git repository, which means that the mock folder will not interfere with each other when multiple people are working together.

My personal understanding:

  • Scenarios for Git inclusion: Your project relies too much on mocks, such as frequent backend hang-ups, or there is no host-provided authentication information in the browser environment (such as the app giving the WebView some login tokens) to get the data
  • Not suitable for Git inclusion: for example, if your project only adds a few interfaces for new requirements and mocks the backend when it is not ready, the rest of the interfaces will be properly requested

Note that if you ignore the mock folder, require. Context will report an error. If you add a try catch, WebPack will skip the mock folder if it cannot be found.

let routes = [] // Collect all mock data

try {
  const ctx = require.context('.. /.. /mock'.true, /(js|ts|jsx|tsx)$/);
  / * * * * /
} catch (e) {}

// Export all
export default routes;
Copy the code

Whether the package size is affected

If the project gitignore has a mock folder, it will not have that folder when it is uploaded to the Docker build, so it will not affect the package size

If you don’t ignore it, and you don’t do anything, unfortunately, you end up with the mock data in your bundle. The solution is to add an if condition before executing require.context and package it only when the mock is opened. For example:

let routes = [] // Collect all mock data

try {
  if(__IS_MOCK__) {
     const ctx = require.context('.. /.. /mock'.true, /(js|ts|jsx|tsx)$/);
     / * * * * /}}catch (e) {}

// Export all
export default routes;
Copy the code

Support for random generation of mock data equalization requirements

This solution is a very basic engineering solution, and because it does not rely on much, it is very flexible, and you can completely handle the data obtained in the interception phase, such as custom template syntax

The advantage of this solution lies in the flexibility, not only to the XHR request interception, any environment, such as applet, FETCH, etc

Attached github tweet address – JS practice