A robust front-end project needs to be managed in terms of project organization and code specification, in addition to proper build tools. This paper analyzes how to build a reasonable front-end project from two aspects of project organization and code specification.

The project management

Consider a scenario where, while developing projectA, codeX can also be used for projectB. The simplest and most direct way to do this is to copy codeX code directly to projectB. There is nothing wrong with this approach based on the “rule of three” (which means that the same code is used three times before abstraction is considered). However, if codeX is also used by projectC and projectD at this point, this approach can be cumbersome to maintain.

An experienced engineer would think to publish codeX as a module and introduce it as a dependency module into the desired project. There are two ways to organize code for codeX at this point: multirepo and Monorepo.

multirepo

Multirepo is the process of breaking up modules in a project and managing them independently in different repositories. For example, Koa, the Web framework for Node.js, relies on modules koa-convert and koa-compose to be split into two repositories for management.

The advantage of this approach is to ensure the independence of the warehouse, convenient for different teams to maintain the corresponding warehouse code, according to the situation of the team can choose tools, workflow, etc.

However, this approach also has some problems, which are as follows.

  • Development, debugging and version update are inefficient. For example, if A bug is found in warehouse B used by Warehouse A, you must go to Warehouse B to fix it, package it, release it, and then go back to Warehouse A to continue working. Not only do you have to deal with different code, tools, and even different workflows between different warehouses; Also, you have to ask the people who maintain the warehouse if they can make changes for you, and then wait for them to sort it out.
  • Team technology selection scattered. Different libraries may have different implementation styles (for example, some rely on Vue and others rely on React), and may adopt different test libraries and verification rules, which is difficult to maintain.

And the Monorepo way just can solve these problems.

monorepo

Monorepo puts all related modules in the same project repository. This approach is easier to manage, and all code in the project can use a uniform specification and build, test, and release process.

Many well-known open source projects take this approach, such as the Open source project Babel, which relies on modules in the Packages directory.

By looking at the Babel project, I found a lerna.json configuration file in the root directory, which is the configuration file of the open source tool Lerna. Lerna is a tool for managing JavaScript projects with multiple packages. Projects managed with Lerna have three directories: packages directory, Learna. json file, and package.json file. They can be created using the Lerna command line tool when the project is initialized.

Lerna supports two modes, Fixed/Locked and Independent.

Fixed/Locked is the default mode, which is used by Babel. This mode is characterized by lerna publishing, and lerna will find the specified version in lerna.json. If this release contains an update for a project, the version version number is automatically updated. This pattern is very beneficial for scenarios where projects are associated, as any major version of a project is upgraded, the major version numbers of other projects are also updated.

As the name suggests, projects are Independent of each other. Developers need to independently manage version updates for multiple packages. That is, we can specifically update the version of each package. Every release, Lerna will cooperate with Git to check the changes of relevant package files and only release the changed package.

Although monorepo has been adopted by many open source projects, it is not the most perfect way to organize code and can cause problems, such as larger warehouses and more complex directory structures due to the concentration of multiple modules in a single repository. Monorepo also requires additional tools to manage individual modules, which means there is a learning cost relative to Multirepo.

Code specification

What is good code? Different engineers may give different answers, such as:

  • Use fewer global variables
  • High cohesion, low coupling
  • Follow a single principle
  • Have comments

Switching perspective helps us get a more comprehensive answer: from a human perspective, the developer who maintains the code changes constantly; From a time perspective, the code is constantly being modified. We can sum up a simple and practical answer: consistent style. “Style alignment” is to allow engineers involved in project development to form a development contract, thus reducing maintenance costs. To achieve this goal, we can start from the two directions of code writing and code management, corresponding to write specifications and submit specifications respectively.

Write specifications

There are many documents about HTML, JavaScript, CSS writing standards (also known as writing styles) on the Internet. Generally, large Internet companies will develop their own writing standards, such as Google’s JavaScript style guide and Airbnb’s style guide, and there are many corresponding tools. Take JavaScript as an example. There are many rule verification tools such as JSLint, JSHint, JSCS, ESLint, and so on.

No matter what writing specifications we create on the team, there are three core principles that make writing specifications sound.

  • The executable. The first thing you need to ensure when you write a specification is that it is executable. If a good specification can only be implemented by engineers’ consciousness and checked by code audit, the implementation efficiency will be very low. Therefore, it is recommended that each rule in the specification should have a corresponding verification tool rule corresponding to it.
  • Can be configured. Code readability can sometimes be a subjective issue, such as space indentation. Some engineers see more code with two space indents, while others see more hierarchy with four space indents. These differences can be easily resolved using code validation tools with rich configuration items.
  • Extensible. This is also a requirement for the verification tool. If the existing configuration rules of the verification tool cannot support the project requirements, you can write plug-ins to extend the verification rules.

The most common version of ESlint is configurable and extensible. Its core functionality is implemented through a function called Verify (), which takes two mandatory arguments: the source text to verify and a configuration object (which generates configuration from a prepared configuration file plus command-line operations). This function first uses the parser to generate an abstract syntax tree (AST), and adds listening events to all the selectors in the rule, which are executed when fired. The AST is then traversed from top to bottom. After each node fires an event with the same name as the node type (i.e., “Identifier”, “WithStatement”, etc.), the listener verifies the relevant code and pushes the non-conforming problems to the lintingProblems array.

Submit specifications

While a Commit Message is written every time you Commit code with Git during development, the Commit specification is still an easy point to overlook. A good submission specification, like writing specification, can also greatly improve the maintainability of the code. On the one hand, it can ensure that the corresponding submission record can be found quickly when the code is backed back. On the other hand, it can directly generate the Change Log of the submission message.

Although Git comes with its own template function, this function allows you to define a template file to submit messages to and point to it using Git config. This will open a template file with the default editor each time you commit, edit the information and save it. The tools @commitlint/ CLI and husky are recommended. Commitlint can set commit message templates and validate, while Husky can set pre-COMMIT hooks that call CommitLint for validation when committing code to avoid generating commit messages that do not conform to the specification.

The following husky configuration file executes the command NPM test before commit and commitLint when the commit message is generated.

{
  "hooks": {
    "pre-commit": "npm test"."commit-msg": "commitlint"}}Copy the code

As you can see from the example above, husky isomorphism listens to git hooks to not only validate commit messages, but also call custom NPM scripts for code validation or test code execution. Lint-staged tests can become time-consuming to run Lint or test across a project as it grows larger, and you usually just want to check the files that have changed.

Here is the configuration for Lint-staged Vue. This means running the eslint –fix command for files with the JS suffix to verify and fix the code and then add it to the staging area with git add.

{..."lint-staged": {
    "*.js": ["eslint --fix"."git add"]},... }Copy the code

conclusion

From the perspective of front-end engineering, this paper analyzes how to build a maintainable front-end project from two aspects of project organization and code specification.

  • In project organization, modules with low correlation can be adoptedmultirepoFor independent management, high correlation modules can be usedmonorepoTo centralized management.
  • When writing code specifications, try to be executable, configurable, and extensible for writing specifications, and choose the appropriate tools for submitting specifications, such ascommitlint,huskyTo ensure the normalization and readability of the submitted message.

Public account “Grace Front end”

For every aspiring “front-end ER” to lead the way, build dream aspirations.

Just to be an excellent front end Engineer!