preface

Earlier this year, I started a new project with Preact and developed all the components myself, so I came up with the idea of building a component library. In my spare time, I slowly grinded out a component library. Consider recording and summarizing two or three things about development.

If you’re interested, check out the component library documentation, source code at the project address.


Hands type

He that would do a good job must sharpen his tools. Personally, I suggest you don’t worry about writing components first. I was too anxious at the beginning and have been making major changes since then. Speaking from experience, we can design what we need first. The design can be started from the following points:

  1. Debug and preview components:

    We need to create demos to preview the components, usually using scaffolding or building an actual development environment ourselves to introduce the components. At this point, we can consider various aspects of the consumer’s actual use, such as: how to do the load on demand, how to integrate CommonJs and ES Module component introduction, etc

  2. Documentation:

    When we finish writing the component, we need to document the usage. We can consider whether code is documentation, how to write a good component document efficiently, and multilanguage support.

  3. Script design:

    When we need to create and remove components, there is always a chance that manual work is missing and not elegant enough, so it is better for scripts to help us integrate a series of actions. We can use scripts to support our development, including subsequent builds, automatic document generation, and push updates.

With these presets in mind, we can begin to design the component library from the big picture.

The directory structure

  1. First, we can create a demo. In most cases, CLI scaffolding is relatively mature and is the default choice for many developers to write projects. We can build our own demo directly using CLI, and then customize or integrate some development tools.

    At the same time, most of the final documents presented to developers include demos, so we can combine demo and Doc into one and debug the demo while developing the document. In the case of my project, I created it with preact-CLI and then just defined the route and some loader configurations.

    With the demo created, we are ready to introduce our component libraries for development.

  2. Import {Comp} from ‘./ Comp ‘; export {default as Comp} from ‘. To export individual components. The directory is as follows:

     |-- src/ / / the source code
         |-- comp/ // Component directory
             index.tsx // Component entry file
         index.ts // The entry of the entire component library
    Copy the code
  3. With entry files, most components require style files. For the location of the style file, some people will choose to be independent of the component library directory and then load the style with the import ‘component library name /style/comp.scss’ when using it.

    But if you want to be compatible with babel-plugin-import, you can see from the following figure that the plugin actually imports the style directory in the component directory. Assuming that you set style to true, it will look for comp/style/index.js. For CSS, it is comp/style/css.js. These js are used to import.. /index.scss to import style files from the component directory. Therefore, when we write a component, we do not need to introduce a style file into the component in advance, and once we do, we will not be able to introduce it on demand.

    In addition, we need one more style entry file in the overall component library directory to introduce base class styles and individual component styles so that we can introduce all styles at once.

    Now our directory will look like this:

    |-- comp/ // Component directory
        |-- style/ // Component styles
            index.ts
            css.ts
        index.scss // Component styles
    Copy the code
  4. When we write a component, we usually need to test it. As with style files, you can consider keeping it out of the component directory, but when you look for it, you need to look for the corresponding file in both directories, so I would recommend putting the test file in the component directory for easy management.

  5. The component is complete, and it’s time to document. If you need more documentation for your component, add a file to the component directory and import it in the document according to the actual situation. If you need to support multiple languages, you can also create a document directory in the component directory and put documents in different languages, such as zh-cn.md and en-us. md.

    At this point, our component directory is much clearer and we have everything we need

     |-- comp/ // Component directory
         |-- style/ // Component styles
             index.ts
             css.ts
         |-- test/ // Test the file
             index.test.js
         |-- doc // File directory
            index.tsx // Component entry file
            index.scss / / component style | - comp / / / component
        index.scss // Component styles
    Copy the code
  6. With the architecture of the component complete, you can now consider designing scripts to manage the component.

    • Every time we want to create or delete a component, we need to create the corresponding file and import it in the entry file. If you do it manually every time, you might miss something, you might not conform to the expected specification, it might be cumbersome, and it might not be elegant. Once we have designed the architecture, we can write scripts based on the architecture. Each time we call the script, passing in the component name, we can generate the desired component directory and file, and add dependencies to the entry file. When deleting, simply delete the component directory and remove the dependencies.

    • When developers want to introduce our component libraries, they usually introduce code that we’ve built. If we write in typescript or if the developer wants to introduce it in CommonJs, we need to compile it. This part can be compiled using Webpack or Gulp, depending on the situation. My project is not too complex, so I just create scripts to compile.

The final directory is as follows

|-- assets/ // The resource folder
|-- test/ // Test the initialization directory
|-- src/ / / the source code
    |-- comp/ // Component directory
        |-- style/ // Component styles are loaded on demand
            index.ts
            css.ts
        |-- test/ // Test the file
            index.test.js
        |-- doc // File directory
        index.tsx // Component entry file
        index.scss // Component styles
    index.ts // The entry of the entire component library is js
    index.scss // Style entry for the entire component library
|-- scripts/ / / script
|-- doc/ / / documentation
Copy the code

The development of

  • component

    When writing components, in order to better improve the reusability and generality, you can pay attention to the following aspects when designing components:

    • Prefix namespace

      Generic components don’t always fit everyone’s needs, and developers often have custom requirements. Expose a prefix namespace for your components, giving users greater freedom to customize components by simply changing the prefix of the component to conform to the convention.

    • Checking attribute Types

      When writing React components, defining propTypes or interfaces and checking the types of input properties improves the robustness of the code and gives developers a better idea of what data they need to input. In addition, with well-defined attributes and comments, tools such as React-Docgen can be used to extract component attributes to generate documents, such as the author’s component library.

    • Controlled and uncontrolled

      In Vue, we can often complete bidirectional binding through v-model and other syntax-sugar. However, there is no native support for this in react syntax. When designing components, we must make it clear whether the components need to be controlled or not, so as to avoid confusion in the final state caused by mixed use.

  • Icon processing

    Icon components exist in most component libraries, and in general, ICONS can be introduced via SVG or iconFont. Both of them have their advantages and disadvantages. After consulting, they summarize their advantages and disadvantages for reference only:

    • iconfont

      Advantages: vector, good compatibility, can control the color, transparency and even gradient effect

      Disadvantages: 1. Some browsers will anti-aliasing, resulting in decreased icon clarity; 2. 2. Unable to control the color of each part of the icon, that is, unable to achieve color ICONS, usually solid color ICONS; 3. It will be affected by the row height, spacing and font related CSS attributes;

    • svg

      Advantages: 1. Not by anti-aliasing image, the same is a vector; 2. Can control the color of each part of the icon; 3. Can be directly inserted into the page, convenient control, semantic better;

      Disadvantages: 1. Poor compatibility with some browsers on PC, but good compatibility with mobile terminals; 2. 2. May increase the page size;

  • Custom theme

    When we write styles, we usually write them with a Sass or Less preprocessor, which makes it easy to customize the theme by overwriting variables. In order for the style file to support variable overrides, we can isolate some key variables that we want to customize.

    For example, if we had a Calendar component and wanted to customize its rounded corners, we could set the border-radius to $Calendar-border-radius, and then set the variable to $Calendar-border-radius: 16px! default; Is written in the style/_var.scss file, followed by! Default means that it is the default variable and can be overridden. Then introduce… in the component style. / style / _var SCSS can.

  • build

    1. Components to build

      When a component is developed, it is usually compiled into ES Module and CommonJs forms. When using babel7.x, the compiled configuration items are usually stored in babel.config.js, which exports a function that passes the configuration function Api. That means we can change the configuration at execution time.

      In my project, for example, I decide how to compile by copying the source code into the lib and ES directories and setting process.env. For the specific code, refer to the build-Components. Js file.

      // scripts/build-component.js
      const fs = require('fs-extra');
      // ...
      fs.copySync(srcDir, esDir);
      compile(esDir);
      
      process.env.BABEL_MODULE = 'commonjs';
      fs.copySync(srcDir, libDir);
      compile(libDir);
      Copy the code
      // babel.config.js
      // ...
      const { BABEL_MODULE } = process.env;
      constuseESModules = BABEL_MODULE ! = ='commonjs';
      return {
          presets: [['@babel/preset-env',
              {
                loose: true.modules: useESModules ? false : 'commonjs'}].'@babel/preset-typescript'].// ...
      Copy the code
    2. Style building

      In fact, the previous code said to the press should be the introduction of the code in the style of directory is not complete, because we often in the introduction of other components in the component library, on-demand loaded at this time is not going to help us find depend on the style of the component, we need to be in style in the directory entry file introducing depend on the style of the component. If it is cumbersome to add a dependency manually, we can use the dependency tree to look for the dependent component and check if it has a style file. If so, add it to the entry file in the style directory.

      With the dependent component styles introduced, we can compile the preprocessor styles into CSS. After compiling, CSS. Js is generated in the style directory to support loading on demand lookup when the style option is set to ‘CSS’.

      If icon is introduced into component A, the file in component A’s style directory should look like this:

      // index.js
      import '.. /.. /icon/index.scss';
      import '.. /index.scss';
      
      // css.js
      import '.. /.. /icon/index.css';
      import '.. /index.css';
      Copy the code

      The specific build code can be found in build-style.js.

release

  • Submit specifications

    A good commit record is always a good practice and is important for subsequent collaborative review and management. Due to the length of this section, the actual operation can refer to the elegant commit of your Git Commit Message.

  • NPM release

    In general, component library developers do not need source code or documentation code to use our components. We can add “files” to package.json: [“dist”, “lib”, “es”], which limits the number of files that can be included in the download and also reduces the NPM size.

    /lib/index.js”, “module”: “./es/index.js”, to allow developers to import our code the way they want it, define it as follows:

    Main: Defines the entry file for the NPM package, which can be used by both the Browser and node environments

    Module: The entry file that defines the ESM specification for the NPM package and can be used by both browser and node environments

    Browser: defines the entry file of the NPM package in the browser environment

The document

After the components are developed, it is troublesome to add and write component documents one by one in the documentation directory. If the components need to be deleted, we have to delete the corresponding documents. At this point, the script can be used to extract the document by component.

During the iteration of the component library, occasionally the property name or type needs to be changed, and the documentation needs to be updated manually. It would be nice to keep the documentation in sync with the code. The React component can be used with React-DocGen. Once the propTypes or interfaces are written and the annotations are completed, the properties can be extracted and then the target documents can be generated based on the actual requirements, such as loading the instructions in different languages.

For example, in my component library, there will be a Markdown directory in the DOC directory, and the documents will be divided by type. For example, the component document will be in the Components directory, and the information will be extracted through DocGen to generate markDown and write to the directory. Put the documentation in the DOC directory and write and maintain it manually. The benefit of this is that it is easy to find and only the necessary documents are updated each time the generate document command is executed. The custom Markdown-loader is then configured in WebPack, highlighting the code through Prismjs.

For example, the interface of the icon component in the component library is defined as follows

You can also use tools like StyleGuidist and Storybook to generate your favorite documents.

github page

When the document is written, we need to publish it for others to see, and the most common way is to host our document directly on Github Page. Github. IO repository is created by creating a gh-pages branch in our current project repository (or docs folder in the master branch). You can access static projects in this branch by < username >.github. IO/project name /

As programmers, it is very difficult to cut branches every time we commit, so we can use gh-pages to specify the repository and branch name, execute the command to automatically commit the document, and then our document is published.

Some thoughts

  1. If you’re working with multiple people, it’s best to do it after you’ve pulled the codebootstrap, that is, to removenode_modulesInstall the dependencies again to avoid development problems if someone changes the dependencies;
  2. If you want multiple users to use it, test and review it carefully before release, standardize it, and automate it.

So far, the prototype of a component library has already appeared, we can refer to the mature component library, standing on the shoulders of giants, develop their own set of excellent component library.

Put the address again, I hope you give me advice, let me learn to improve, thank you.

Component library document

Project address.