Alibaba Front-end Specification

repository·main·Indexed 22 days ago

https://github.com/alibaba/f2e-spec

A comprehensive set of coding standards and engineering best practices for front-end development. It includes specification documentation for JS, TS, CSS, HTML, React, and Node.js, alongside automated linting tools such as f2elint, eslint-config-ali, stylelint-config-ali, prettier-config-ali, commitlint-config-ali, and markdownlint-config-ali to enforce compliance across projects.

Tokens
64.3K
Snippets
259
Records
297
Agent score
77%

What's inside f2e-spec

  1. Overview of CSS Coding Specification

    main
    The CSS Coding Specification defines coding styles and best practices for CSS and its pre-compiled languages, specifically Sass and Less. These rules are designed to ensure consistency across front-end projects. Some of these rules can be automatically enforced using the stylelint tool.
  2. Overview of Alibaba Front-end Specification

    main

    The Alibaba Front-end Specification is a set of coding and engineering standards used extensively within Alibaba's economic ecosystem. It aims to reduce collaboration costs and improve project maintainability and stability by unifying coding styles, promoting best practices, and providing automated code defect checks.

    The project consists of two main parts:

    1. Specification Documentation: Detailed rules for various languages (JS, TS, CSS, HTML), frameworks (React, Node.js), and engineering processes (Git, Changelogs).
    2. Supporting Tools: Automated linting tools to enforce these rules.

    You can either read the documentation to understand the standards or use tools like f2elint to integrate these checks into your project automatically.

  3. Validate Keys in for-in Loops

    main

    When using a for-in loop, always verify that the key belongs to the object's own properties. This prevents the loop from iterating over properties inherited from the prototype chain.

    Recommended ESLint rule: guard-for-in

    // bad
    for (const key in foo) {
      doSomething(key);
    }
    
    // good
    for (const key in foo) {
      if (Object.prototype.hasOwnProperty.call(foo, key)) {
        doSomething(key);
      }
    }
  4. Choose a Git workflow (No Flow, GitHub Flow, or Git Flow)

    main

    Select a workflow based on your team size and release requirements:

    • No Flow: For single-maintainer projects. Commit directly to main/master.
    • GitHub Flow / One Flow: Best for agile development. Uses a single maintenance branch (main/master). Create feature or hotfix branches from main and merge back. Versions are typically strictly increasing.
    • Git Flow: Best for projects with fixed release cycles and long-term maintenance (e.g., Node.js). Uses multiple maintenance branches (e.g., LTS branches) to backport security fixes to older versions.
  5. Naming conventions for React components and instances

    main

    Follow these naming rules to ensure consistency and compatibility with ESLint rules like react/jsx-filename-extension and react/jsx-pascal-case:

    1. File Extensions: Use .jsx, .tsx, .js, or .ts for React component files.
    2. Component References: Use PascalCase (UpperCamelCase) when importing/referencing component definitions.
    3. Component Instances: Use camelCase (lowerCamelCase) when assigning a component instance to a variable.
    // bad
    import reservationCard from './reservation-card';
    
    // good
    import ReservationCard from './reservation-card';
    
    // bad
    const ReservationItem = <ReservationCard />;
    
    // good
    const reservationItem = <ReservationCard />;
  6. Node.js Coding Style: Use Built-in Globals

    main

    Avoid manually requiring Node.js built-in modules that are already available as global variables. This keeps code cleaner and follows node/prefer-global ESLint rules.

    // bad
    const { Buffer } = require('buffer');
    const b = Buffer.alloc(16);
    
    // good
    const b = Buffer.alloc(16);
    
    // bad
    const process = require('process');
    process.exit(0);
    
    // good
    process.exit(0);
  7. Order class members by priority

    main

    Class members should follow a consistent order:

    1. Static vs Instance: Static members (static) come before instance members.
    2. Type: Properties (field) come before constructor, which comes before methods (method).
    3. Accessibility: public members come before protected, which come before private.
    // good
    class Foo {
      public static foo1 = 'foo1';
      protected static foo2 = 'foo2';
      private static foo3 = 'foo3';
      public static getFoo1() {}
    
      public bar1 = 'bar1';
      protected bar2 = 'bar2';
      private bar3 = 'bar3';
      public constructor() {}
      public getBar1() {}
    }
  8. React Component Creation and Lifecycle Best Practices

    main

    Follow these rules for defining and managing React components:

    • Use ES6 Classes: Use class extends React.Component instead of createReactClass.
    • Prefer Function Components: If a component has no internal state or refs, use a function component instead of a class component.
    • Single Component per File: Each file should contain only one React component (though multiple function components are allowed).
    • Avoid this in Function Components: Do not use this inside function components; access props and context directly.
    • Avoid React.createElement: Use JSX instead of calling React.createElement directly unless you are not using JSX files.
    • Avoid Deprecated Lifecycles: Do not use componentWillMount, componentWillReceiveProps, or componentWillUpdate. Use constructor, componentDidMount, or componentDidUpdate instead. You can use the rename-unsafe-lifecycles codemod to prefix these with UNSAFE_.
    • No Mixins: Do not use mixins as they introduce implicit dependencies and naming conflicts. Use HOCs or hooks instead.
    // good - Use ES6 class
    class Listing extends React.Component {
      render() {
        return <div>{this.state.hello}</div>;
      }
    }
    
    // good - Use function component for stateless components
    function Listing({ hello }) {
      return <div>{hello}</div>;
    }
  9. Ensure return statements in array callback methods

    main

    When using specific array methods, you must include a return statement in the callback function to avoid misuse or errors. This applies to the following methods:

    map, filter, from, every, find, findIndex, reduce, reduceRight, some, and sort.

    Common Pitfalls:

    • Using map for side effects: If you only want to iterate over an array without creating a new one, use forEach instead of map.
    • Missing return in reduce: Failing to return the accumulator (memo) in a reduce callback will result in a TypeError (e.g., Cannot set property '...' of undefined).
    // bad: map used for side effects instead of forEach
    myArray.map((item, index) => {
      myObj[item] = index;
    });
    
    // good: use forEach for side effects
    myArray.forEach((item, index) => {
      myObj[item] = index;
    });
    
    // bad: missing return in reduce
    const myObj = myArray.reduce((memo, item, index) => {
      memo[item] = index;
    }, {});
    
    // good: return the memo in reduce
    const myObj = myArray.reduce((memo, item, index) => {
      memo[item] = index;
      return memo;
    }, {});