What does real front-end development look like? Is it to search for the silver bullet that will never be found in the vast sea of NPM? Or are you exploring a dream utopia in the ever-changing ECMAScript specification?

The front-end has developed for more than ten years, with changes of dynasties, from Vanilla. Js, to ju. js, to Angular.js, and then React/Vue. Among them are up-and-comers such as Svelte.

What is the truth behind the facade of prosperity?

Front-end technology is evolving so fast that many truths are constantly being overturned.

Behavior Structure Presentation Stratification, an old and useful code stratification specification, has been crushed in the face of JSX and vue Templates. Although there are good reasons to explain this phenomenon, it is still difficult for those who follow the norm for thousands of days and nights.

It’s not just the front end, but the world is changing every day, and we’re always trying to adapt. But hard work alone is not enough. If the speed of adaptation catches up with the speed of change, it will fall behind and be eliminated. If you want to be a good engineer all the time, you have to have something of your own that can sustain you through the dynasties.

Since cognition is often subverted, we have to observe what is real from a different perspective.

One, forced use of the MVVM framework sad

I’ve been using the MVVM framework for the last two or three years. The reason for using them is simple: something popular must have an advantage. They are good for componentization and UI responsiveness. But recently I started to wonder, “Why use the MVVM framework at all?”

A friend’s confusion

A sunny afternoon, I stretch, bubble a cup of black tea, ready to communicate with the group of water friends in the group. While chatting, I suddenly received a private chat from my friend Xiao Zhang. He asked me a question, how does Vuex maintain data after a browser refresh? This is a very simple question. Vue I use less but still know the solution to this problem. So I told him to use localstorage and vuex-PersistedState.

Xiao Zhang began to study the first solution. After realizing the function, he felt that the encapsulation of his code was not good enough. After thinking about it, he still chose to use ready-made packages. So Zhang made a mistake when installing vuex-PersistedState. After zhang repeatedly changed the NPM source, deleted node_modules, used YARN, and deleted package.lock, he finally installed the package into his project.

The problem was solved, but the next day Xiao Zhang asked me some more questions. Such as asynchronous commit, how to block stores and so on. Because I work that day quite busy, remote also is not convenient, then xiao Zhang put forward weekend invite me to have a meal, incidentally help him to see those a few problems.

At the restaurant zhang booked over the weekend, I helped him look at the code. It turned out that only one user information in his project needed to be stored globally. But his company only he a front end, their own level is limited, no one to guide him. I searched the Internet, couldn’t figure it out, went to the technical manager of the company who hadn’t written code for years to find a solution, and was told to try Vuex.

I told zhang, this demand does not need to use Vuex, save to localStorage, encryption can be.

Then I took a look at his project as a whole, and there were six or seven pages, and almost all of them were display pages, except for two forms. So I told him that we could do this project without Vue.

“No, I have to use Vue.” Xiao Zhang gave me an emphatic answer.

“Why?”

“Vue is the best framework, and a lot of people use it all the time.”

I was speechless for a while, but it also made me feel a kind of inexplicable sadness.

I was able to solve those problems, but I didn’t think he was going to be able to deal with what the framework was going to bring him.

Difficulties of the project

People die all the time in this world. I’ve never felt so close to death before. Until the emergence of the coronavirus, I was forced to wear a mask, went to the hospital for a nucleic acid test, and applied for a key card in the property management of the community. Every day, I had to check my temperature at the gate of the community and the company, and the take-away food could only be delivered at the gate of the community…

These series of changes make me feel that death is not far away from me, perhaps my life at any time may be taken away by death. I’m afraid of death, but this situation doesn’t scare me, it inspires me to love life.

Some friends complained that the company began to pay less, and even delay. Our company doesn’t do that. We pay a lot of money, but we don’t delay projects. Even three projects in a week.

A lot of work forced us to recruit during the outbreak, so two colleagues and I were in front of the computer wearing masks and chatting for a long time with the other side of the computer also wearing masks.

One of the company’s three projects had the most problems. The UI parts of the project framework are mainly vUE and Elemental-UI. I neglected to write Vue and faced this project, it can be said that step by step, a hole.

There are a lot of questions, just to name two.

The first is the issue of layout style.

There is a popover page in the project. The basic layout is as follows:

demo

The page is actually four components, with the search component at the top and the List component at the bottom. The outer layer is a Layout component that wraps the two components. The outermost layer is the el-tabs of the elemental-UI.

This is a normal page, but the person who wrote this page didn’t take into account the fact that there are too many elements in the search component. If there are too many boxes or buttons for search criteria, they will be truncated. Because he set search to overflow: hidden; .

Now you can either change search to scrollbar or wrap it. Considering the user experience, I choose the latter.

I want to change the Layout component to flex layout, but I’m afraid to change it. Because display in the search area is float. The list area is fixed using margin-top. This layout implementation sucks, but I won’t be able to change it for a while.

I overlooked the power of CSS. The SCSS code for the project is too complex, the styles are too deeply nested, and there are multiple triplet expressions and Vue style! Important. I dare not take a risk easily, so I have to find another way to solve this problem with THE method of JS.

After the element is loaded, obtain the height of the search area (sh). Take sh and subtract the height of the original row in the search area (SOh) to get the extra height (iH). Add ih to margin-top of list area.

In Vue, the ref is used to get an element. So I use ref to get the search component and the list component. Then use offsetHeight and offsetTop to obtain the corresponding height.

The pseudocode is as follows:

code

The place where this code should run is in the component’s Mounted life cycle. In the end, listRef and searchRef’s offsetHeight and offsetTop values are both 0.

It took me 30 minutes to figure out what caused the problem. The default mechanism for el-Tabs renders all the components in el-Tabs. This results in a page that displays only one TAB of content, but actually has N tabs. In other tabs, layout components are also used. In other words, there are multiple search components and list components on a page. Although these components are not displayed in the interface, they do exist, so their offsetHeight and offsetTop are both 0.

I solved this problem by adding v-if to each TAB component and adding a state change corresponding to V-if to the TAB switch callback function.

Another problem, also related to element-UI, is a more subtle Bug. If the el-select component is generated through a loop, the data in JS will change after selecting el-option, but the UI will not change.

The cause of this problem is a problem with Vue’s bidirectional data binding.

The solution is to ensure that the property corresponding to el-Select’s V-Model already exists in the data before rendering the component, or to use $set. Because Vue cannot listen to the newly added property.

The problem on the project is solved, and a new one is derived.

Why did it take me so long to solve such a small problem?

This may be due to my poor understanding of Vue or my lack of proficiency in using Elemental-UI. But these are not the root causes.

If I thought this was the root of the problem, I would probably read the Vue and Elemental-UI documents a few more times, but that wouldn’t change anything. It was clear to me that none of this was the root of the problem.

Why are you sad?

It says I feel sad for my friend Zhang. Why would I feel sad?

Xiao Zhang worked for more than two years, the earliest is to do Java development, more than a year, just this year to the front end. I haven’t had much contact with him, but I still don’t think he’s a fool.

When doing Java development, Zhang’s most familiar front-end frameworks are jQuery and Bootstarp. As an older generation of front-end technology, compared with the current mainstream technology, the learning cost is indeed very low, the development is relatively convenient, and the development process may encounter fewer problems.

Vue is not suitable for Xiao Zhang to develop the project at the current stage, he should give priority to working for the company with the technology he can handle, and MVVM is really not necessary for his project. Sticking with the mainstream and unsuitable technology makes little practical sense and creates a lot of unnecessary trouble. This is the sad first point.

The second sad thing is that Xiao Zhang didn’t realize it, and still didn’t realize it after I told him.

Once a “best practice” becomes mainstream, it is used like crazy, but few people are able to remember why it exists in the first place.

To realize what you cannot understand. If you don’t understand, you won’t wake up.

The real state of the front end

At present, the front-end technology selection is too complex, in many places there is no best solution. Each framework and library has its own narrative, and indeed each has its own merits.

React and Vue, a lot of people say they’re similar, but it’s still quite different. It’s not just about them, it’s about the whole ecological chain behind them. Vue Template and JSX, React-router-dom and Vue-Router, Redux, Mobx and vuex, redux and vuex middleware, Ant Design, Material – UI and iView, element-UI, respective hooks, etc. Style level also exists a large number of choices, CSS in JS, Sass, less, Styled -components…

It can be said that a hundred schools of thought contend, each has its own merits.

The more you work with these techniques, the more you master them, the more you’ll see the difference.

From the design ideas, to the underlying implementation, to the very different apis, there are little details of the same.

These are the costs of learning. No wonder github failed to learn last year.

The speed at which front-end technology is being updated and iterated has reached an unimaginable level.

Have you ever stopped for a moment and really thought, are these things really for us?

There are many factors that will determine the answer to this question.

Team members, historical projects, types of business, and so on. Sometimes it’s not up to one person to decide.

But there are companies hiring and programmers looking for jobs all the time. The next person who takes your place at your last company has to take over. And the new company you think is ready to hit the big time is just picking up the pieces left by someone who left.

I also thought, since front-end frameworks are all about the same goal, user experience. So why can’t technology be unified? Can not unify, the reason is that unify represents the thought imprison.

There are many ways to do the same thing. For example, Vue thinks data hijacking and Proxy push are better, while React thinks diff algorithm pull is better. The different ways of choosing cause the difference of thought.

Why is the world not unified? Why are religions not unified? This goes up to the level of philosophy.

In fact, the reason is very simple. Every country and major religion in the world has its own beliefs, ideas, traditions, values, interests, resources, cultural knowledge. This is why we have today’s diverse world.

But look at it another way, humans are unified.

On the front end, a large number of packages appear as newborns on NPM every day. Over time, some have become “best practice” and others have fallen into obscurity. Just like people, there are upper class, middle class and lower class. They have something in common. That’s the browser, HTML, CSS and JavaScript.

There are many “reformists” on the front end, who are constantly creating new things to replace the old ones.

What is popular is the trend, and what remains constant is true.

No one can go wrong between the trend of The Times and returning to nature.

“Potential” has always been there, follow the trend, the wise. But keep your eyes open and don’t be fooled by a concept you don’t understand. To understand, “potential” is the “potential”, “trend” or “trend”.

Why is it difficult to solve problems?

The key is choice.

If a developer who is good at using React is asked to solve the problems on jQuery or Vue, he may be able to solve the problems, but he will encounter many difficulties in the process of solving the problems, and the efficiency will not reach the level of React. I call this a problem above a problem.

Project technology selection should be in line with the technology pool of major developers. If there is a problem with the selection, then the problem will naturally come unbidden, what should be done? Have time to choose again, to choose again. It was too late. We had to grasp the nettle.

One more level up, why hire a Sichuanese chef to cook fujian dishes?

Is the MVVM framework bad?

There is no absolute good or bad choice of frame, just as there is no absolute right or wrong in this world.

The MVVM framework is good, but it’s also complex.

Working on projects is like buying a computer. Buy a new one instead of a used one. But it also distinguishes uses. A $20,000 MacBookPro might not work as well as a $4,000 ThinkPad for an office worker who works with documents every day. There is no need to use the MVVM framework to develop a daily activity page. You don’t need Typescript for a small project.

We need to assess whether a project needs a framework, which in turn involves distinguishing the boundaries between large and small projects.

Usually, this boundary is blurred. If you had to draw a line between using the MVVM framework, TypeScript, or other technologies, it might be a list like this:

  • More than 20 pages.
  • The number of modules exceeds 5.
  • More than 5000 lines of code.
  • There are more than 10 people on the project.
  • .

Even if you could make such a list, it would still be difficult to decide whether a project should be used or not. Because the overall difficulty of a project is not enough to rely solely on measurable metrics. For example, if a project has only a few pages, but they are all complex visualizations, with a lot of data and a lot of data linkage between each other, then the project is not a small project. Or a project has dozens of pages, but the page as a whole is very single, mostly some of the display page, or even a page is a picture with some text. Then it’s not a big project.

When you feel that the development of a project is giving you a headache, it is natural to use a more advanced and complex framework to solve the current problem. Rather than creating problems for yourself by forcing advanced and complex frameworks when everything is going well.

Software engineering thinking is the opposite of learning thinking. Learning is about stepping out of your comfort zone all the time. Software engineering is about staying in a relatively stable state.

In addition to the project factor, the team is the second factor.

Most companies in the country have little front-end team configuration. 80% of companies have a full-time front end, and 70% of companies have fewer than three front ends. A mid-to-large technical team of more than 100 people may have less than 20 people on the front end. Domestic companies with more than 100 technical teams may seem like a lot, but they are few and far between in each city.

In this situation, forcing the use of MVVM frameworks, TypeScript, Graphql, and the like is not helpful.

But if you don’t have the strength and confidence to beat the interviewer to the punch, you’ll have to follow suit, because companies will expect you to master or be proficient in certain skills when hiring.

When one’s livelihood is at stake, one no longer needs reason to think why.

MVVM is an excellent idea and a complete set of solutions worth learning, but not necessarily for every project or every person.

Two, data verification

In mid-February, the peak of attention, streets were empty and fewer people went to hospitals.

There is a hospital company under the group. In order to carry out business during the epidemic, a group of pages should be placed on wechat public account to temporarily replace offline signing and replace it with online signing.

As a C-side product, there is no UI component library, and page styles and functionality are almost all handwritten.

The project is not complicated, four or five pages. Almost all are forms, with various linkage.

This involves data verification.

Data verification is a processing method to ensure the integrity and legitimacy of data.

Data verification has a very long history.

Once upon a time. Before there were front-end engineers, or even server-side engineers, many applications were architecturally integrated.

The architecture of the application is designed to have only one layer, or no layer, where the business logic may be placed in the stored procedures of the database, and the user interface and the service application are integrated. At that time, the data verification is done on the database, as long as the data conforms to the data type and length set when creating the table, it can be stored successfully, otherwise the storage will fail. Rather than doing the check on the database, it is better to say that there is no check, all by hard. Because there was no concept of data validation.

table

As browsers became popular, web applications emerged. The concept of data validation was gradually introduced to developers, but at the time front-end development was in the wild. There’s no SPA, there’s no AJAX, there’s not even a front-end engineer. Pages are rendered from server-side templates, even with a lot of back-end logic written into the templates. Due to technical reasons, a new page was returned every time the page was submitted, so the data was flushed. There were ways to cache data, but at the time nobody cared and it wasn’t popular. To this day, some of the oldest websites are still in this phase.

Then, the emergence of AJAX, before and after the end of the division, CS architecture, BS architecture, MVC, MVVM. With the exploration of software, people pay more and more attention to user experience. As software architecture becomes more and more standardized and application quality becomes higher and higher, data verification becomes an indispensable part.

There is still a debate about whether the front end needs to do data validation.

The answer is yes, data validation is a front end thing that really needs to be done, and there are many reasons why it needs to be done. But there are some special cases.

If the back end performs data verification and accurately returns the verification failure information to the interface, the front end is allowed not to perform data verification to some extent.

In this case, the front end does the data verification, the only benefit is to reduce the interface call, can reduce the server pressure.

Small projects with short deadlines and few users. If you are affected by various factors, you can not do it. But do what you can.

No matter how the front end is, data verification must be performed on the back end interface.

Front-end data verification

At present, there are two kinds of data validation on the front end.

The first is real-time verification, each time the input will be a verification, and the verification results back to the user.

The second is submission – time validation, which is performed uniformly when a form is submitted.

Both approaches have their own benefits, but from a user experience perspective, commit time validation is more appropriate in most scenarios. Because frequent real-time verification will make users feel bored.

The realization of real-time verification is relatively simple, through listening to input, change and other events to complete.

Submit time verification is to verify data in the submit event of the form, and do different processing according to the verification result.

Component library data verification

B side projects, most of the data validation is done in the UI component library, because it is very convenient.

In the case of a component library, there is almost always a component called a Form. Almost all the Form components come with data validation, and their usage is similar.

Take Ant Design as an example.

You only need to configure the relevant validation logic in the rules attribute of form.item to implement the validation of the input.


<Form>
  <Form.Item
    {. formItemLayout}
    name="username"
    label="Name"
    rules={[
      {
        required: true.message: "Please input your name"]} >,},
    <Input placeholder="Please input your name" />
  </Form.Item>
</Form>

Copy the code

You can then use form.validateFields() in the function that submitted the form.

It’s not that complicated to use, but it actually does a lot of work behind the scenes.

Native data validation

HTML itself also has a data verification function.

The type attribute of the input performs basic validation functions, such as verifying email and URL formats.

In addition to the type attribute, there are required, min, Max, pattern, and other attributes that validate the data.

JavaScript also provides the validity interface, which allows you to customize the verification status and error message.

Use el.setCustomValidity(‘ failed validation ‘) to set the error message. Use el.setCustomValidity(“) to cancel the error message.

Here are all the validation related properties so far.

html validation type

In the form error prompt of browser, all is submit time check. However, due to different browser implementations, the specific effect is not consistent. Basically, there are two kinds.

The first is to indicate only the first result of failed verification.

Chrome 80, for example.

chrome validity

The second is to indicate all verification failures.

Such as Edge44 and IE11.

edge-validity

In addition to the display effect, the default prompt text is also different.

Validity has been around for several years, but usage is still low. The reason is no more than poor compatibility, browser inconsistency, style is difficult to customize. You can read more if you are interested.

Back-end data verification

Back-end and front-end data parity is not much different, the difference in the use of location and writing.

In terms of usage, the front end verifies data before it is submitted to the back end. If the verification fails, the submission stops and prompts the user. In the back-end, data is checked in the controller before logical processing. If the check fails, an exception is thrown and an error message is displayed on the interface.

It’s written differently in different languages and different frameworks.

Java Bean Validation

Probably the most elegant way I’ve written it is Java Bean Validation for Java.

The code looks something like this.

@Getter
@Setter
@ToString
public class User {
    @NotNull(message = "Username cannot be empty.")
    public String username;
    @NotNull
    @NotEmpty
    private List<@Email String> emails;
    @Future
    private Date endDate;
}
Copy the code

Bean Validation is a Java EE JSR specification implemented by Hibernate Validator.

In Hibernate Validator, only one annotation is needed to realize data verification. Hibernate Validator has a lot of built-in annotations.

Java Bean Validation has built-in constraints.

@Valid role
@Null The annotated element must be null
@NotNull The annotated element must not be null
@AssertTrue The annotated element must be true
@AssertFalse The annotated element must be false
@Min(value) The annotated element must be a number whose value must be greater than or equal to the specified minimum value
@Max(value) The annotated element must be a number whose value must be less than or equal to the specified maximum value
@DecimalMin(value) The annotated element must be a number whose value must be greater than or equal to the specified minimum value
@DecimalMax(value) The annotated element must be a number whose value must be less than or equal to the specified maximum value
@Size(max, min) The size of the annotated element must be within the scope specified
@Digits (integer, fraction) The annotated element must be a number, and its value must be within an acceptable range
@Past The annotated element must be a date in the past
@Future The annotated element must be a future date
@Pattern(value) The annotated element must conform to the specified regular expression

Hibernate Validator adds constraints.

annotations role
@Email The element to be commented must be an E-mail address
@Length(min=, max=) The size of the commented string must be within the specified range
@NotEmpty The string being commented must be non-empty
@Range(min=, max=) The annotated element must be in the appropriate scope
@NotBlank The string being commented must be non-empty
@URL(protocol=, host=, port=, regexp=, flags=) The commented string must be a valid URL
@CreditCardNumber The annotated string must pass the Luhn verification algorithm. Bank card and credit card numbers are generally evaluated using Luhn for validity
@ScriptAssert (lang=, script=, alias=) There should be an implementation of the Java Scripting API, JSR 223 (“Scripting for the JavaTM Platform”)
@SafeHtml (whitelistType=, additionalTags=) You should have the JSoup package in your classpath

If you want to extend your own validation rules, you can also use custom annotations.

Unfortunately, JavaScript does not currently support annotations, but you can use them in TypeScript.

node.js validator

The most popular data validation library in Node.js is the Validator. NPM downloads more than 3.3 million per week.

The Validator is not limited to Node.js, but can be used in both JavaScript modules and scripts. The built-in functions are numerous and cover most scenarios in everyday development.

The syntax is still the usual functional syntax of JavaScript.

var validator = require("validator");

validator.isEmail("[email protected]"); //=> true
Copy the code

node.js class-validator

If you’re developing Node.js programs in TypeScript, you can use the annotation feature, so you have an elegant way of writing Java Bean Validation.

Compared to the Validator, class-Validator was only downloaded 300,000 times per NPM week, indicating that Typescript’s popularity has yet to grow.

The syntax is as follows:

import {
  validate,
  validateOrReject,
  Contains,
  IsInt,
  Length,
  IsEmail,
  IsFQDN,
  IsDate,
  Min,
  Max,
} from "class-validator";

export class Post {
  @Length(10.20)
  title: string;

  @Contains("hello")
  text: string;

  @IsInt(a)@Min(0)
  @Max(10)
  rating: number;

  @IsEmail()
  email: string;

  @IsFQDN()
  site: string;

  @IsDate()
  createDate: Date;
}

let post = new Post();
post.title = "Hello"; // should not pass
post.text = "this is a great post about hell world"; // should not pass
post.rating = 11; // should not pass
post.email = "google.com"; // should not pass
post.site = "googlecom"; // should not pass

validate(post).then(errors= > {
  // errors is an array of validation errors
  if (errors.length > 0) {
    console.log("validation failed. errors: ", errors);
  } else {
    console.log("validation succeed"); }}); validateOrReject(post).catch(errors= > {
  console.log("Promise rejected (validation failed). Errors: ", errors);
});
Copy the code

Three, small but beautiful Lvp.js

After all that writing, it’s time for the main character of this article.

Lvp. js is a data validation library.

When I first wrote this library, I did not intend to open source it. Because there are so many similar libraries, and I just can’t find anything good about this one.

Fill in a hole left by an ex in an old project.

I spent the afternoon refactoring the validate class.

Coincidentally, before I left work that afternoon, a friend asked me if I had a generic JavaScript data validation library.

So the next day I posted the project to NPM.

Then I spent another weekend getting the documentation and testing done. Hence lvp.js.

The syntax is simple:

var Lvp = require("lvp.js"); // Import the LVP
var lvp = new Lvp(); // Create an Lvp instance
var phone = "15555555555"; // Test data
var isPhone = lvp.test({ value: phone, rules: "isCNPhone" }); // Start data verification
//{message: "verify success ", status: true}
Copy the code

If you need to test a bunch of data, such as form submission, then the code looks like this.

var orderInfo = {
  orderId: "tb12395x5zv4003y".idCard: "37188019840918666X".phone: "18854100312"};var tr = lvp.test([
  {
    value: orderInfo.idCard,
    rules: "isCNIDCard".message: "Id card format error"}, {value: orderInfo.phone,
    rules: "isCNPhone".message: "Wrong format of phone number",}]);// {message: "verify success ", status: true}
Copy the code

If the built-in validation logic is insufficient, you can add your own. Such as adding Fibonacci and two dog parity.

lvp.addRules([
  function isFibonacci(value) {
    function fibonacci() {
      if (value == 0) {
        return 0;
      } else if (value == 1) {
        return 1; }}return fibonacci(value - 1) + fibonacci(value - 2);
  },
  function isTwoDog(value) {
    return value === "🐶 🐶"; },]);Copy the code

More examples are not a list, like if you can go to the official website to see.

Compared with other similar libraries, Lvp.js is more like a little girl, small and minimal but just enough to meet.

Source code written in ES5, without compiling, remove comments about 200 lines, min version volume a little more than 3K. No overdesigned content, very easy to get started, syntax tolerance is very high, support CommonJS, AMD, CMD, ESM specifications. Can be used in Node.js, React, Vue, jQuery, or native HTML.

Cell coverage is 93.89%, and the remaining few lines of compatible code are not easily tested in JEST.

At present, there are few built-in verification rules, but they are the verification logic used frequently in daily development, especially by Chinese programmers.

The validation list continues to be added, but if you encounter data validation logic that is used very frequently in your work, please submit your PR.

lvp.js-api