This tutorial is largely modeled after Pro-Components and Ant-Design, so thanks to Dumi, Ant-Design and Pro-Components for enriching the front-end components, thanks to the open source community.

I wanted to use Storybook to build a component library, but later I learned from a senior in the company that it was more convenient to build a component library through Dumi, so I learned about it.

Through this article, you can roughly understand the content of

  • Dumi creates the component library
  • Lerna manages multiple packages
  • Prettier and esLint configure code styles
  • Git hooks and Commitlin configure commit specifications

Dumi creates the component library

  1. Create a k-component directory and open it with vscode
mkdir k-component
cd k-component
vscode .
Copy the code
  1. Create component library projects with dumi scaffolding
npx @umijs/create-dumi-lib --site
Copy the code
  1. Download the dependency and run it
npm install
npm run start
Copy the code

The result is shown below

To make the interface look as good as pro-Components, you can copy the.dumi/theme directory of Pro-Components into your own project.

Then run it again, and the following error message appears

Download dependencies as prompted

npm install --save @ant-design/pro-layout @ant-design/pro-skeleton antd moment react-helmet-async react-lazyload
Copy the code

Re-run NPM run start, and the following image appears

Manage component libraries with LERNA

Lerna followed the official explanation

Lerna is an administrative tool for managing JavaScript projects that contain multiple packages

Here are some steps to use it

  1. Download lerna
npm install --global lerna
Copy the code
  1. Initialize lerNA in the project root directory
lerna init
Copy the code

After initialization with Lerna, there is an additional lerna.json file and packages directory in the root directory of the project

  1. Create subpackages in the Packages directory
#Create a Button component
lerna create @keith/button packages/button --yes

#Create a tag component
lerna create @keith/tag packages/tag --yes
Copy the code

  1. After creating the package, you need to passlerna linkSymlinks together the interdependent LERNA packages in the current LERNA store; Then, intsconfig.jsonAdd a new one to the filepaths, and then add the component directory. Otherwise, the referenced component cannot be automatically identified when the component is written to the demo
{
  "compilerOptions": {
    "target": "esnext"."module": "esnext"."moduleResolution": "node"."jsx": "react"."esModuleInterop": true."types": ["jest"]."strict": true."skipLibCheck": true."declaration": true.// Add the component directory here
    "paths": {
      "@keith/button": ["./packages/button/src/index.tsx"]."@keith/tag": ["./packages/tag/src/index.tsx"]}}}Copy the code

If the lerna link does not take effect after running, restart vscode

  1. Modify the component packagepackage.json, such as under the Button componentpackage.json
{
  "name": "@keith/button"."version": "0.0.0"."keywords": []."license": "MIT"."main": "lib/index.js"."module": "es/index.js"."types": "lib/index.d.ts"."files": [
    "lib"."es"."dist"]."peerDependencies": {
    "antd": "4.x"."react": "> = 16.9.0"."react-dom": "> = 16.9.0"
  },
  "publishConfig": {
    "registry": "https://registry.npmjs.org"}}Copy the code
  1. in.fatherrc.tsFile, addbuttonandtag
import { readdirSync } from 'fs';
import { join } from 'path';

// utils must build before core
// runtime must build before renderer-react
// components dependencies order: form -> table -> list

const headPkgs: string[] = ['button'.'tag']; // Add button and tag
const tailPkgs = readdirSync(join(__dirname, 'packages')).filter(
  (pkg) = > pkg.charAt(0)! = ='. ' && !headPkgs.includes(pkg),
);

const type = process.env.BUILD_TYPE;

let config = {};

if (type= = ='lib') {
  config = {
    cjs: { type: 'babel'.lazy: true },
    esm: false.runtimeHelpers: true.pkgs: [...headPkgs, ...tailPkgs],
    extraBabelPlugins: [['babel-plugin-import', { libraryName: 'antd'.libraryDirectory: 'es'.style: true }, 'antd']],}; }if (type= = ='es') {
  config = {
    cjs: false.esm: {
      type: 'babel',},runtimeHelpers: true.pkgs: [...headPkgs, ...tailPkgs],
    extraBabelPlugins: [[require('./scripts/replaceLib')],
      ['babel-plugin-import', { libraryName: 'antd'.libraryDirectory: 'es'.style: true }, 'antd']],}; }export default config;

Copy the code

Father is a build tool that supports CJS, ESM, and UMD packaging. See Father for details

  1. inpackage.jsonaddworkspaces
   // ...
   
   / / add workspaces
  "workspaces": [
    "packages/*"]."scripts": {
    "start": "dumi dev"."docs:build": "dumi build"."docs:deploy": "gh-pages -d docs-dist"."build": "father-build"."deploy": "npm run docs:build && npm run docs:deploy"."prettier": "prettier --write \"**/*.{js,jsx,tsx,ts,less,md,json}\""."test": "umi-test"."test:coverage": "umi-test --coverage"."prepublishOnly": "npm run build"
  },
  // ...
Copy the code
  1. Remove redundant directories, such as those in the component directorylib,_test_And the root directorysrc

Then rerun NPM run start. The final result is shown below

Navigation configuration in the component library documentation, see basic usage -dumi (umijs.org)

Common lerna commands

Lerna init // Initialize lerna configuration lerna create // create lerna package lerna link // link lerna package lerna add // Install a single dependency lerna bootstrap // Install global dependencies and link to all subpackages lerna clean // clear node_modules lerna list // list subpackagesCopy the code

You can look at Lerna

The contents of the code specification and submission specification are documented below…

Prettier and esLint configure code styles

Prettier and eslint are first downloaded in vscode,

Dumi scaffolding has been used to create projectsprettierConfiguration file

// .prettierrc.js
module.exports = require('@umijs/fabric').prettier;


// The configuration of prettier under @umijs/fabric can be found by referring to the path where prettier is located
"use strict";
/** @format */
module.exports = {
    singleQuote: true./ / single quotation marks
    trailingComma: 'all', // Whether the last attribute of the {} object is added,
    printWidth: 100.// Each line is more than 100 characters long
    proseWrap: 'never', // Line breaks are not enforced
    endOfLine: 'lf', // Use lf as the newline character
    overrides: [
        {
            files: '.prettierrc',
            options: {
                parser: 'json',
            },
        },
        {
            files: 'document.ejs',
            options: {
                parser: 'html',
            },
        },
    ],
};
Copy the code

Common examples of prettier are

"semi": false.// Whether there is a semicolon
"bracketSpacing": true.{a: 1} {a: 1} {a: 1}
"arrowParens": "always" // Set whether arguments in arrow function are wrapped ()
Copy the code

Then open the file in vscode >> preferences >> Settings

When opened, a.vscode/settings.json file will appear in the project’s working directory, configured as follows

{
  "editor.formatOnSave": true.// Format code when automatically saving
  "search.exclude": { // Exclude the following files
    "**/node_modules": true."dist": true."yarn.lock": true,}}Copy the code

The code is automatically formatted when you press CTRL + S

Prettier solves the problem of uniform code, for code quality problems esLint creates.eslintrc.js and.eslintignore files in the root directory of the project where umi is already installed, just as Prettier does, Configure it directly using ESLint in UMI


// .eslintrc.js
module.exports = {
  extends: [require.resolve('@umijs/fabric/dist/eslint')],
};

// eslint under umijs
module.exports = {
    extends: ['prettier', 'plugin:react/recommended'],
    parser: '@babel/eslint-parser',
    plugins: ['react', 'jest', 'unicorn', 'react-hooks'],
    env: {
        browser: true,
        node: true,
        es6: true,
        mocha: true,
        jest: true,
        jasmine: true,
    },
    rules: {
        strict: ['error', 'never'],
        'react/display-name': 0,
        'react/jsx-props-no-spreading': 0,
        'react/state-in-constructor': 0,
        'react/static-property-placement': 0.// Too restrictive: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/destructuring-assignment.md
        'react/destructuring-assignment': 'off',
        'react/jsx-filename-extension': 'off',
        'react/no-array-index-key': 'warn',
        'react-hooks/rules-of-hooks': 'error',
        'react-hooks/exhaustive-deps': 'warn',
        'react/require-default-props': 0,
        'react/jsx-fragments': 0,
        'react/jsx-wrap-multilines': 0,
        'react/prop-types': 0,
        'react/forbid-prop-types': 0,
        'react/sort-comp': 0,
        'react/react-in-jsx-scope': 0,
        'react/jsx-one-expression-per-line': 0,
        'generator-star-spacing': 0,
        'function-paren-newline': 0,
        'sort-imports': 0,
        'class-methods-use-this': 0,
        'no-confusing-arrow': 0,
        'linebreak-style': 0.// Too restrictive, writing ugly code to defend against a very unlikely scenario: https://eslint.org/docs/rules/no-prototype-builtins
        'no-prototype-builtins': 'off',
        'unicorn/prevent-abbreviations': 'off',
        // Conflict with prettier
        'arrow-body-style': 0,
        'arrow-parens': 0,
        'object-curly-newline': 0,
        'implicit-arrow-linebreak': 0,
        'operator-linebreak': 0,
        'no-param-reassign': 2,
        'space-before-function-paren': 0,
        'react/self-closing-comp': 1,
        'react/jsx-key': 1,
    },
    settings: {
        // support import modules from TypeScript files in JavaScript files
        'import/resolver': {
            node: {
                extensions: isTsProject ? ['.js', '.jsx', '.ts', '.tsx', '.d.ts'] : ['.js', '.jsx'],
            },
        },
        'import/parsers': {
            '@typescript-eslint/parser': ['.ts', '.tsx', '.d.ts'],
        },
        'import/extensions': ['.js', '.mjs', '.jsx', '.ts', '.tsx', '.d.ts'],
        'import/external-module-folders': ['node_modules', 'node_modules/@types'],
        polyfills: ['fetch', 'Promise', 'URL', 'object-assign'],
    },
    overrides: isTsProject
        ? [
            {
                files: ['**/*.{ts,tsx}'], parser: '@typescript-eslint/parser', rules: tsEslintConfig_1.default, extends: ['prettier', 'plugin:@typescript-eslint/recommended'], }, ] : [], parserOptions: parserOptions, };Copy the code

After esLint is configured, a warning will appear if code written does not conform to the rules defined in ESLint

Git hooks and Commitlin configure commit specifications

Git hooks are similar to the vue hook functions, including pre-commit and commit-msg, which are implemented before git commit. Because the Dumi project comes with yorkie to configure git hooks, husky is not needed.

  1. Install dependencies
npm install @umijs/yorkie -D
Copy the code
  1. Package. json configuration in the root directory of the project
{
    // ...
  "gitHooks": {
    "pre-commit": "lint-staged"."commit-msg": "fabric verify-commit" / / here commitlint configuration file is in the ". / node_modules / @ umijs/fabric/dist/verifyCommit js. ""
  },
  "lint-staged": {
    "packages/**/*.{js,ts,jsx,tsx, md, json}": [
      "eslint --fix"."prettier --write"."git add ."]},// ...
}
Copy the code
  1. Submit code
  • When using git commit, esLint and prettier are triggered, and if there is something in code that doesn’t conform to ESLint’s rules, the commit fails

  • Fix errors in ESLint and resubmit. ifgit commitIf the specification is not met, the commit is unsuccessful, for example, usinggit commit -m "xxx"

Json file and found yorkie and @umijs/ Fabric dependencies, but did not trigger Git hooks when using git commit. I did some searching and finally found a @umi/ Yorkie dependency in package.json of ant-Design-Pro project on Github. I tried to download it and found that it works.

Jest unit tests, Gitlab-CI run Lint and test, lerna package to nPMjs.com, next time…

github

Refer to the link

Dumi – Documentation tool for component development scenarios Pro-Components Lerna Prettier