Please do not reprint without permission, thank you.

I have been in touch with small program development for more than 3 years. If you ask me how to develop a small program from scratch, you can look at this article.

The beginning of everything

To develop a small program, the first thing is of course to register a small program.

Applets registration

Registered address of wechat applets

Click the arrow to register, follow the interface prompts to complete the registration.

Once registered, we’ll get our first important item, APPID

The development environment

Like H5 development, developing applets requires a little setup. For wechat small program development, the most important environment is the wechat developer tools provided by wechat official.

Wechat developer tools download address

Click the biggest + sign in the middle of the interface can enter the new interface of the small program.

Fill in the applet APPID at the arrow in the image above and a applet with the official template will be automatically generated.

So far, we have taken the first step in developing small programs. But this time must not be in a hurry to masturbate the code, in fact, there are many things more important than just getting started with the code.

Common cognitive

Generally speaking, there is no avoiding collaboration in development, and the most important thing in collaboration is the tacit understanding with partners, which comes from the common cognition of everyone.

Only when everyone’s understanding of the project is on the same level can the overall development collaboration be positive.

Directory structure specification

Do not underestimate the naming and distribution of each file and folder. With the expansion of the project, the project with directory structure specification and the project without specification, give a person a completely different feeling.

Before we talk about directory structures, let’s take a quick look at the concept of a small program package.

  • Applets currently have three types of packages – main package, sub-package and independent sub-package

  • There are also restrictions on package size – the size of a single subpackage/main package cannot exceed 2M, and the size of all subpackages for the entire applets cannot exceed 20M

Because wechat has a limit on the size of the main package, we definitely shouldn’t put all the logic in the main package.

Primary package and the subcontractor has a very significant difference between the two, all contents of the subcontract can refer to the main package, but there is no mutual reference between the subcontract, it is doomed, our common logic must be in the Lord in the package, as well as another conclusion – the business logic can be on different subcontract, also have the picture below. (What is a tabBar page?)

What is the subcontract common component library? Shouldn’t common components be in the main package?

In fact, in the actual development, due to the difference of each business, not every component we think can be common, it is sure to be used by everyone. Therefore, the author thinks that if it is a common component of the business, it should be put into the subcontract first. If it does have the needs of other businesses, we can carry out component promotion, move it to the main package, and uniformly change the references in the original subcontract.

Independent subcontracting is seldom used in development, so it is not described too much here.

Now we should have a certain understanding of the small program package body, in the actual development of how we should carry out directory structure planning? Here the author only throw out a brick to introduce jade, give a very shallow example, probably express the author’s train of thought.

Let’s take a look at the first layer, our root directory. Why is there an APP folder that wraps up the contents of a real applet? This is mainly to pave the way for us to introduce engineering in the future. If the root directory is the root directory of the small program, there will be mixed use of package.json later, and then it will be more troublesome to separate.

Js /app.json/pages and other files/folders are placed in this directory. The only difference is that the main folder is added. The Settings in this folder are consistent with the previous ones. Pages folder is placed the content of each business subcontracting, from the file directory on the main, subcontracting isolation.

The pages folder inside the main folder contains the contents of the main package. The pages folder inside the main folder contains tabBar pages, and the external folder contains various public resources.

Finally, there is the Pages folder at the same level as main, where the subcontracting of each business is stored. Each specific business can be stored in an independent package here.

Coding style specification

The previous paragraph was about the outer structure specification, and the next part should be the more detailed one about the coding style specification.

There’s not much to say about this, and every team’s coding style is definitely different, so here’s a quick mention.

One is the naming of variables and functions. Naming is actually a very complicated thing. We need to clarify the responsibilities of this variable or function.

Then there are classic specifications like Lint and comments, which I won’t go into here.

Development mode * Optional

There are basically three ways we can develop applets now

  • Multi-terminal development framework
  • Secondary encapsulation based on native applets development
  • Native applets development

Multi-development frameworks refer to frameworks such as Taro and KBone, while the definition of the latter two development modes is fuzzy, because under the accumulation and precipitation of the team, the pure original development will also add a variety of secondary packaging to improve efficiency. So the secondary encapsulation mode is at a higher level, for example, the vue3 Composition API can be used for the development of small application pages.

You may ask, is there a difference between this secondary encapsulation and multi-terminal VUE writing development? The biggest difference between them is that the former template is still.wxml and the latter is.vue.

The author is not sure which of these three ways is better. Each mode has its advantages and disadvantages. The only thing that can be determined is that the selection of mode cannot be separated from the project form. Is it necessary to output multiple terminals, what is the main technology stack or technology accumulation of the team, and is it necessary to always be ready to access the latest features of applets…..

Infrastructure construction

In fact, doing project development is a bit like building a house. We treat the whole project as a house, and the first task of building a house is to lay the foundation. Going back to our code project, this is what I call infrastructure setup. We need to make sure we have a solid, high availability base before we can talk about how gorgeous our interiors are, otherwise it’s a castle in the air.

Login state

The first part we need to focus on is the login state, which is the user’s ID card in our small program. We must ensure that every user can operate our program with the correct login state, otherwise there will be unexpected consequences, including burying point reporting disorder, or affecting the stability of data in the database.

So how to ensure that our login state can be stable access and maintenance, the author thinks that the most basic point is to maintain a unified login method, after the bundle path can maintain stability. Next, I will talk about the login state in two parts. Due to different business requirements, there may be two login states in a small program — the login state of the small program and its own account system login state.

Applets login state

The applets login state here refers to the process of obtaining the code by calling wx.login and using the code to exchange for the user in the applets OpenID

Ideally, we should be able to provide a general-purpose method, miniappLogin, that doesn’t care if it has a valid login state, just validates the login state with the Wx.checksessionAPI every time it is called and re-logs in if it has expired. (The back-end implementation, along with the source address for the entire process, is provided at the end of the article.)

Login status of own account system

Why is there another login state here? They are two different login systems, in fact, the login state provided by small programs can also meet our requirements for login state, it has both a unique identification ID and maintain a set of effective logic, for small businesses can be directly used.

But when the business scale is large, especially if there are more than one small program under the same main body, in this case we need to formulate a new unique identification field as the identity of the user, and the identity of the user is consistent no matter in which small program.

This so-called new field is actually our H5 development can often see userid,uid, etc., about the generation of identity varies from person to person, each team on its userid requirements are different, some may be ordinary random string, some may be encrypted string. In addition to the user ID, the login status generally contains a token or accessToken field with an expiry date, just like the session_key of wechat, which is used to judge the validity of the login status.

There is basically no general scheme for how to generate userID and token, which needs to be designed based on business needs. However, the premise is relatively clear — only after the user’s OpenID and UnionID are successfully obtained can the user register and login state be generated.

Request to packaging

Since the separation of the front and back ends became common sense, requests have become something the front end must touch.

Normal project, the request of almost every page has a plural, if we don’t make unified and standardized packaging on request as soon as possible, the project will soon be in a circle, with the passage of time, we will find the request of the project agreement is becoming more and more heavy, in the end no one dare to sort through agreement, lest affect the global request for adjustment.

Because projects vary so much, we certainly can’t come up with a universal request logic, just a little sample code.

As the pseudocode mentioned above, it first declared a general Request class Request, and on this basis, developed the Request method that the business really needs.

In the example, I simply preset three types of requests: defaultRequest, configRequest, and cfRequest. In actual development, there are probably many more types of requests than this, but these three types of requests are what I consider indispensable.

// Common business request
const defaultRequest = (. args) = > {
    const r = new Request({ baseURL: BASE_URL })
    returnr.request(... args); }Copy the code

The first is defaultRequest, as the name implies is the defaultRequest mode, the front end in addition to interact with the user, do the most things is to interact with the back end, this request is used for this situation, it may be a form submission may also be a state query……

// Page configuration request
const configRequest = (someKey, data = {}) = > {
    const r = new Request({ baseURL: `${BASE_URL}/config-api` });
    return r.request('getConfigBySomeKey', { someKey, ... data }); }Copy the code

Then there is configRequest, which is a special request paradigm that I have conceived. Configuration is now the mainstream thinking, everyone wants to use front-end configuration to achieve fast validation, agile implementation purposes, so we should take this into account when thinking about the framework. We should consciously separate configuration requests from business requests; in the original development, we always coupled them together. But if you think about it, there are obvious differences. One is the pull of interface configuration and the other is the trigger of back-end operations, which can be decoupled at the time the project is conceived.

// Cloud function request
const cfRequest = (cfKey, data = {}) = > {
    const r = new Request({ baseURL: BASE_CF_URL });
    returnr.request(cfKey, { ... data }); }Copy the code

See here, may be some combat experience rich children shoes will ask, in some cases, we need to front-end is not a static configuration, but need and back-end data for a series of processing configuration. This is a very valuable question, and it is bound to happen, but it can also be solved once and for all, with the help of our final request, cfRequest.

Cloud function is not particularly novel, but the author feels that the popularity rate is not too high. Here, I consider cfRequest to be a high-order configRequest. We can complete defaultRequest and configRequest requests in cloud functions, and then configure and process the returned data to output out-of-the-box data to the front end.

In addition, cloud function can not only be used to pull page configuration, it can also be added, deleted, changed and checked according to the atomic interface provided by the back end. It will not be extended here, but it involves the responsibility boundary of the cloud function of the team. If you have the opportunity, you can write a new article about it.

Finally, one of the important advantages of encapsulating a request, besides convenience and specification, is that it provides great convenience for subsequent buried reporting.

The full code for Request can be found here (Github)

Routing encapsulation

The jump API of small program is special, and H5 route jump is not quite the same, but we encapsulate the idea is actually the same.

The main purpose of routing encapsulation is to solve the following problems:

  • Maximum page level
  • Routing data transmission
  • Buried some report

Wechat applet only supports the routing level up to level 10. If you want to jump to a new page on the tenth page, an error will be reported and the normal jump cannot be achieved. Therefore, we need to handle navigateTo type jump with the judgment of the current page level. If the page level has reached 10, we can change the navigateTo jump into redirectTo to ensure the normal operation of this jump.

options.action = 'navigateTo';
const { _pathName, _query } = _navigateFormator(path, query);
if (getCurrentPages().length >= 10) {
    options.action = 'redirectTo';
}
Copy the code

Then there is the problem of data transfer. When we do various jumps, we always want to pass some data from the original page to the target page. Although the applet now provides a way to communicate between pages through EventChannel, it is still cumbersome to use. If we can harness full project hopping, then we can maintain page-passing data in a unified encapsulation routing approach.

constructor(options = {}) {
    this.routes = {};
}

router(path, query, options) {
    // ...
    const preloadData = typeof options.preloadData === 'function' ? options.preloadData() : options.preloadData;
    const routeID = _randomString(6);
    query.__routeID = routeID;
    this.routes[routeID] = {
        routeID,
        preloadData,
        // ...
    };
}
Copy the code

Finally, the buried point reporting problem, and the above mentioned request, the unified operation, the buried point reporting is good without harm. We can implement a default jump complete callback that implements the logic associated with reporting. The following is a simple encapsulation of the Router code, but there are many more details that can be optimized for business needs, which are not covered here.

The complete Router code can be found here (Github)

Page, component initialization functions

The essence is to re-wrap the Page and Component functions exposed by the applet.

As development progresses, we want to be able to retrieve some of the globally shared parameters or methods as soon as the page loads, which requires page development and component initialization functions. The authors conclude that it is time to start developing a unified initialization function when we encounter the following situations.

  • Certain operations, such as loading reports, must be performed uniformly during page or component initialization
  • You need to get some global parameters or utility classes on multiple pages or components

As in the above code block, the onLoad function is declared in the defaultPage object, which performs some page initialization operations, and the convention is to store the data generated in this stage to the this.data.$$define.

In the example, I complete these initial actions:

  • Get global data
  • Save page link parameters in the development of small application pages should encounter this troublesome problem, in the non-onLoad cycle to obtain link parameters is always very troublesome.
  • Under strong constraints, we can preprocess some agreed data, such as decoding the URL in the parameter……

The above is just the tip of the iceberg, and you can add more logic to make your development easier according to your business needs.

The full code for the initialization function can be found here (Github)

Common component library

Public libraries and small application we H5 inside to see at ordinary times is different, because small programs, there are two limit inclusion size, subcontractor shall not refer to each other, so we can’t place the component library alone with a subcontract, only in the main bag, and then extend out another problem, inclusion size problem.

Is mentioned in directory structure specification part, the author is not advocated all pulled out of the component as a global public components placed in the main package, and adopt the way of a component upgrade, when the component is really need is referenced to other business, it can be up to the main package, to ensure the smooth development of the main package volume already so, also can to secondary review components.

Infrastructure documentation

!!!!! The construction and accumulation of team technical documentation must not be neglected

Quote do not know where to come out of the classic statement – iron auxiliary, water output

Use this scenario for a simple misunderstanding:

The turnover of staff within the team is highly likely to be frequent, and no matter it is post adjustment or manpower increase or decrease, it is inevitable. In this case, we need to have a stable support to ensure the continuity of our project, that is, our technical documentation.

So what exactly does a technical document do? It can be hard to notice them, and even harder to write about them.

Based on these years of experience in the team, the author summarizes the following points:

  • The technical document is a guide. The original intention of the technical document is to provide guidance services for the new entry or new students. The degree of detail of the document directly affects the speed of everyone into the project.

  • Writing technical documentation is a kind of backlog. Take a component document as an example. Records of the component’s usage, such as receiving parameters or passing events, are inevitably presented to the component author at this point. This is a good opportunity to take a second look at component details, such as whether a parameter is really necessary, and whether an event should be notified to the parent component……

  • The author believes that a technical team should not only guarantee the maintenance iteration of project requirements, but also have its own technical precipitation, and technical documentation is one of the methods of technical precipitation. In the short term, technical document editing may seem like a thankless task, but in the long run, it’s like planting a tree that, over time, we’ll look back at under its shade.

The business development

Every company has its own business development process, which is impossible to be unified. We should fully observe the internal work process of the company and dynamically adjust the development mode most suitable for the team based on the company’s business form.

Test and Release

This section focuses on the black box testing process, and introduces the release in passing.

Before we get to the topic, we need to think about whether we need to apply two mini-programs based on the size of our business.

For large businesses, it is recommended to have two small programs, one for testing and one for release.

If it is clear that the business is small, or that it is an MVP project, we can only prepare a small application.

Below, the author will start from these two projects, respectively, to introduce the test mode of the two projects.

MVP project

There are three versions of small programs: development version, experience version and official version. Both development version and experience version have certain access restrictions, while the official version is accessible to all users. According to the features of each version, we can make the following version planning:

  • Development version – generally used by developers, this version contains native small program code and is only used for self-testing during development.
  • Experience version — the version with relatively stable features, generally used for testing intervention, later can be used for product walk-through.
  • Official version – features have been very stable and through testing, check, this stage small program will be officially released.

This is the ideal version planning, but in the actual project advancement, there will certainly be multiple requirements interspersion development to the situation, this time the experience version will be repeatedly covered, is not conducive to testing and walking. So why can’t we test with the development version?

It is not totally impossible, because there are very few users who can have development permission. If the team is small, it can be tested in the development version, and then use the experience version to conduct walkthroughs. However, larger teams cannot do this and can only migrate testers into play privileges.

If, along the way, the project is much larger than expected and the team is larger, we should consider converting the project into a test plan for a larger project.

A large project

As shown in the figure, a large project will have two mini-programs, one of which is specially used for testing. The function of each version is similar to that of MVP project, but the only difference is that the timing of walkthrough has changed. In large projects, we will choose a more stable version for product and design walkthrough, which is the official version of the mini-program.

The other small program is a small program that will be released to the outside. The code is absolutely stable when it comes to this side, so there is only an experience version left here. In this experience version, pre-release experience can be basically understood as a formal small program in the gray stage.

In the above test section, there are various versions, so how are these versions released and deployed to wechat?

  • Use wechat developer tools

  • Use CI tools provided by wechat official

The above two ways can the development of the local version of the small program into experience version of small programs, if want to let the external users also have access to our small program will need to login WeChat public platform, into the operation of the corresponding small application background, version and remand the case, there is nothing to say about this, follow the guidance in the interface to fill in the data can be small program the questioning.

summary

Thank you for seeing this to the end 🙂

If the above content is successfully built, our small program will have a prototype, with the in-depth business development, we can summarize and abstract more in line with the team business development “wheel”, let our small program more robust.

Now I will give you some additional implementation of partial business, the following implementation and the code implementation mentioned above will be recorded in this warehouse.

  • Wechat login back-end implementation
  • Applets login state sharing
  • Small program push system construction (there are many contents, a separate record will be opened)

In addition, there is also a miniapp-startKit directory in the warehouse, which is a continuous iterative project, which is the final implementation of the content of this article. If you need it, you can pay attention to it