preface

As the business platform expands and the components become more and more abundant, I want to share the components (including functional components, business components and basic components) with more partners in the company, so I have this kind of sharing. 😄 😄

Next, I will make a summary of what I have learned this time.

Watch patiently and you will learn:

  • In what way is the project managed
  • How to build a component library demo environment
  • How to build a component library development environment
  • How to build a component library compilation package to generate resources to store the location
  • Automation registers components as global components
  • How to implement on-demand import
  • The constraint specification
  • How do I publish a component library to NPM

In what way is the project managed

background

For research purposes, consider how to maintain these packages in one repository or separately in multiple repositories when developing a component library. Or a repository that wants to develop component libraries based on several different frameworks, how do you manage them?

Is it managing each component as a package(in the form of multiple projects, multiple repositories, also known as Multirepo), or managing multiple packages with a single repository (Monorepo)

If the above expression is a bit abstract, use an example to see the difference between the two:

To solve

In order to reduce the maintenance cost of multi-package projects, I use LERna as a process management tool.

  • Initialize Lerna project:
// go to project folder CD ddMC-ui - // initialize lerna initCopy the code
  • After initialization, the generated project structure is as follows:
DDMC-UI /
  packages /
  package.json
  lerna.json
Copy the code

Lerna. json is the management configuration file for LERNA, and I used the fixed mode of LerNA in the construction process. So what are fixed patterns?

Fixed-mode Lerna projects operate on a single version line, which is controlled in the Version field in the lerna.json file in the project root directory. When lerna publish, if a module has been updated since the last release, it will be updated to the new version you want to publish, which means you only need to publish the new version of the package as needed.

  • Complete the project directory, and finally generate the project warehouse as follows:
DDMC-UI / config / example / app.js index.html packages / demo1 / index.vue index.js demo2 / index.vue index.js index.js  src / utils / common / package.json lerna.jsonCopy the code

Webpack builds the project

The foundation is laid, but as a worker you have to think about how the project is structured. In the process of building the project, I used WebPack to build the project.

The component library demo environment, the component library development environment and the location of the component library compilation and packaging generated resources are all based on webpack configuration to achieve. The specific configuration directory is through the config file.

The example file in the project is the demo environment. It is an example for the user to see how the component is used.

Create dev.config.js- add dev environment configuration:

Create pro.config.js- Add production environment configuration:

These two files are respectively the configuration of the corresponding development environment and production environment. Components can be developed under the package file, and example file can be used.

Create lib.config.js- add component library to compile package to generate resource location configuration:

The generated lib file is primarily used as an entry file for component libraries published to NPM. So the entry for this is a component under Packages.

Based on the above configuration, we implement the package.json command configuration:

It’s important to separate documents and know what each document is for. Having a clear division of labor is the first step.

I also created a base.config.js configuration file that is public. This file implements some basic configuration:

  • The js module converts ES6 to ES5
  • Separate and package CSS and JS files
  • CSS conversion
  • Configure an alias
  • Image manipulation and so on

Automation registers components as global components

To avoid frequent import when using components… Import operations, which we can register as global components. The Vue.component() and vue.use () methods are used.

Let’s take a look at the directory structure of a demo component:

├ ─ ├ ─ ├ ─ ├.txt () # ├ ─ ├ ─ ├.txt () # ├ ─ ├ ─ ├.txt () # ├ ─ ├ ─ ├.txt (Copy the code

To register a component as a global component, the code is as follows:

const fs=require('fs');
const path=require('path');
var endOfLine = require('os').EOL;
const render = require('json-templater/string');

const IMPORT_TEMPLATE='import {{name}} from \'./index.vue\'; ';
const USE_TEMPLATE='Vue.component({{name}}, {{component}}); ';
const MAIN_TEMPLATE=` {{include}} {{component}}.install = function (Vue) { {{list}} }; export default {{component}}; `

const files=fs.readdirSync('./packages');

const folder =files.slice(0, -1)

console.log(folder)


const includeComponentTemplate = [];
const listComponentTemplate =[];

const writeFile=function(file,include,list){
    const p=path.resolve(__dirname,`.. /packages/${file}/index.js`);
    fs.writeFileSync(p,render(MAIN_TEMPLATE,{
        include:include,
        list: list,
        component:file
    }));
}

folder.forEach((item) = >{
    const include=render(IMPORT_TEMPLATE,{
        name:item,
        component:item,
    });
    const list=render(USE_TEMPLATE,{
        name:item,
        component:item,
    });
    writeFile(item,include,list);
});

Copy the code

The main idea is that the component provides the install method and registers as a global component using Vue.component(). The jSON-templater module in the script allows you to replace the beard style template on JS and JSON objects. NPM run build:cp, the generated demo file under the index.js code:

Once a component is registered as a global component, it needs to be imported in index.js. Also through the introduction of script automation, specific implementation can refer to the above code. By executing the command: NPM run build: PCK, the generated code:

How to implement on-demand import

After developing the component library, our class can import XXX from ‘DDMC-UI’ for other projects that require the component. This approach is called global import, where component libraries are introduced into the desired project.

So how do you implement on-demand import? Import {XXX} from ‘ddmc-ui/lib/demo’

Note: Import on demand means that you need to import the component library on demand in the project you are developing

To import components in this way, we need to package them individually, so we need to get the path of each component. With the Webpack configuration, the output lib directory is structured the same as the Packages directory. The configuration needs to be changed in lib.config.js.

The key is to get the directory of the packages file. The following code can get the entry object:

function getEntries(path) {
  let files =  fs.readdirSync(resolve(path));
  const entries = files.reduce( (ret, item) = > {
        const itemPath =`${path}/${item}`;
        const isDir =  fs.statSync(resolve(itemPath)).isDirectory();
        console.log(isDir,itemPath)
        if (isDir) {
            ret[item] = resolve(join(itemPath, 'index.js'));
        } else {
            const [name] = item.split('. ');
            ret[name] = resolve(itemPath);
        }
        return ret;
  }, {})
  return entries;
}

Copy the code

Well, this is where the on-demand import of the component library is complete. One drawback is that each import on demand requires a long string of import {XXX} from ‘ddMC-ui /lib/demo’.

This is where the babel-plugin-import plug-in comes in.

Note:babel-plugin-importThis is when you use and modify the configuration in the project you are developing

The specific configuration is as follows:

// .babelrc{..."plugins": ["import", {
            "libraryName": "ddmc-ui",}}]Copy the code

The constraint specification

Component library management and building capabilities are available, but in a multi-stakeholder project, there must be a specification to enforce the constraints, and the specification needs to be automated and enforced in addition to the written statement. Therefore, it is necessary to verify the code of each worker before the code submission to prevent random submission.

Husky submits to GIT to add hooks, perform some validation we need to do, and execute some scripts to verify that the code is compliant.

Lint-staged is a tool for running Linters on Git staging files. You can use husky for code verification before git commit.

Commitlint commits message validation. Based on the above two toolkits, we have the ability to do some things in Git hooks. The first thing to mention is the submission specification and validation of the code. Elegant submission facilitates team collaboration and quick problem location.

The common GIT submission format specification is:

:

.

Procedure for implementing constraint specifications:

  • The installation
npm install -D husky lint-staged

Copy the code
  • Initialize the
npx husky install
npx husky add .husky/pre-commit "npm run test"
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
Copy the code
  • Package. The json configuration
"lint-staged": { "src/* */* .{js,json,vue,ts,tsx}": [ "npm run lint"]}Copy the code
  • newcommitlint.js
module.exports = { extends: ['@commitlint/config-conventional']}Copy the code

How do I publish a component library to NPM

In package.json configuration:

  • Configure the component library name
{
  "name": "foxit-ui"
}
Copy the code

Note: The component library name must be unique to NPM and must not be duplicated, otherwise you will be told that you have no permission to modify the library

  • Make the component library public
{
   "private": true
}
Copy the code
  • Configure keywords, Description, and author
{
  "description": "XXX Component Library"."keywords": [
    "element"."vue"."ddmc-ui"]."author": "hhl"
}

Copy the code
  • Configure the address of the main entry file
{
  "main": "lib/index/index.js"
}
Copy the code
  • Set ignore files to reduce dependency package size

Only compiled lib folders, package.json files, and readme. md files need to be published for a component library. Create a.npmignore file in the root directory to ignore resources that do not need to be published and reduce the dependency package size.

thinking

During the build process, the main issues are compatibility issues between toolkits themselves, as well as issues related to Node versions.

Error: Cannot find module ‘webpack/lib/RuleSet’ Error: Cannot find module ‘webpack/lib/RuleSet’ The final solution is to reduce the version of vue-loader.

Although the overall repository and component library are complete, iterative optimization is needed as the repository expands. It can also be optimized from a Webpack configuration.

  • Remove unnecessary CSS styles
  • Compress the packed image
  • CDN loading file
  • Filtering third-party packets. Vue, Vuex, things like that. Use the externals option for Webpack. Externals to prevent these dependency packages from being packaged
  • Tree-shaking: Weeding out useless code, etc. I will slowly iterate on project optimization
  • Happypack is a multithreaded package that allows you to delegate different logic to different threads
  • DllReferencePlugin and DllPlugin are packaged in advance to greatly improve build speed
  • Dynamic loading imports files by adding the webpackChunkName field and configuring the Output option for webpack

Due to the relationship of time is more rushed, the follow-up will slowly iterate up.

conclusion

The above is the tool and method that I summarized and actually used from the problem of developing a component library from scratch. I hope to bring help to you.

In addition to the more common tools and methods mentioned above, there is much to explore and learn about front-end engineering/automation.

Give a thumbs-up to the article, which is my greatest support and encouragement 😘😘