current position:Home>Front end engineering practice - configurable template management

Front end engineering practice - configurable template management

2021-08-26 15:47:29 CookieBoty

️ This article is the first signing article of nuggets community , Reprint is prohibited without authorization

Preface

The actual combat of front-end engineering has now reached the third chapter , In the first two articles, we have built a simple React Scaffolding with a preliminarily available CLI Tools .

After the foundation scaffold is erected , We can start the development of Template Management , After all, in the real world , A set of scaffolding is far from meeting the demand , We will face a variety of business scenarios , For these scenarios, customized scaffolds may appear .

So how do we manage these scaffolds ?

Functional design

If every time Development of new scaffolds or updating of templates Need to be updated again CLI Words , Although the cost is not high , But the students who develop the template need to inform CLI Development students to upgrade , Students who use the template need to wait CLI It can only be used after development , The cost of intermediate communication increases .

secondly , For business development students , You may only need one or more types of templates , So if CLI Is a large and complete set of templates , For these students , Quickly selecting templates to create projects is also a burden , Because it takes time to choose what you want from many templates .

So our goal is to design a car with Custom configuration and upgradeable templates Functional CLI Tools .

 Unnamed file .png

Since it is a custom configuration , Then you need to manually add... Locally 、 Delete 、 Update your common template information , At the same time, you need to be able to dynamically pull these templates instead of downloading them all the time or local old versions .

According to the demand , But simply design us CLI Summary of template functions :

  1. You need to save the address of the template source
  2. Pull different template codes according to the user's choice
  3. Save the template locally

Practical development

Then according to the above design ideas , We can develop the required functions step by step

Save template address locally

First step , If you need to save some information of the template locally , We need a conversational interaction , Guide users to enter the information we need , So you can choose inquirer This library .

Inquirerjs  Is a collection of tools used to implement the command-line interactive interface . It helps us achieve interactive communication with users , For example, ask the user a question , Users give us an answer , We do something according to the user's answer , Typical applications are  plop And other generator tools .

Generally, if you pull the code , We need to know the template address entered by the user ( adopt URL Necessary conditions for pulling the corresponding template )、 Template alias ( Convenient for users to search )、 Template description ( Facilitate users to understand template information )

In this way, the template information to be saved has the address 、 Alias and description , It is convenient for us to manage the corresponding templates later . The sample code is as follows :

import inquirer from 'inquirer';
import { addTpl } from '@/tpl'

const promptList = [
  {
    type: 'input',
    message: ' Please enter the warehouse address :',
    name: 'tplUrl',
    default: 'https://github.com/boty-design/react-tpl'
  },
  {
    type: 'input',
    message: ' Template title ( The default is  Git  Name as the title ):',
    name: 'name',
    default({ tplUrl }: { tplUrl: string }) {
      return tplUrl.substring(tplUrl.lastIndexOf('/') + 1)
    }
  },
  {
    type: 'input',
    message: ' describe :',
    name: 'desc',
  }
];

export default () => {
  inquirer.prompt(promptList).then((answers: any) => {
    const { tplUrl, name, desc } = answers
    addTpl(tplUrl, name, desc)
  })
}
 Copy code 

adopt inquirer I've got the corresponding information , However, due to various situations such as computer restart , Therefore, it is inconvenient for data to be stored in the cache , such CLI If you use a database to store tools, you are also overqualified , So you can put the information directly in json Files are stored locally .

The sample code is as follows :

import { loggerError, loggerSuccess, getDirPath } from '@/util'
import { loadFile, writeFile } from '@/util/file'

interface ITpl {
  tplUrl: string
  name: string
  desc: string
}

const addTpl = async (tplUrl: string, name: string, desc: string) => {
  const cacheTpl = getDirPath('../cacheTpl')
  try {
    const tplConfig = loadFile<ITpl[]>(`${cacheTpl}/.tpl.json`)
    let file = [{
      tplUrl,
      name,
      desc
    }]
    if (tplConfig) {
      const isExist = tplConfig.some(tpl => tpl.name === name)
      if (isExist) {
        file = tplConfig.map(tpl => {
          if (tpl.name === name) {
            return {
              tplUrl,
              name,
              desc
            }
          }
          return tpl
        })
      } else {
        file = [
          ...tplConfig,
          ...file
        ]
      }
    }
    writeFile(cacheTpl, '.tpl.json', JSON.stringify(file, null, "\t"))
    loggerSuccess('Add Template Successful!')
  } catch (error) {
    loggerError(error)
  }
}

export {
  addTpl,
}
 Copy code 

Here we need to make a simple process judgment on whether to save or update the template :

  1. Determine whether there is currently tpl The cache file , If the cache file already exists , Then it needs to be merged with the current template information , If it doesn't exist, you need to create a file , Save the obtained information .
  2. If a cache file already exists , Need basis name The judgment is that it has been cached , If cached , According to name To update the corresponding template information .

Next , Let's demonstrate , The effect of using .

According to the previous operation , After construction CLI after , function fe-cil add tpl You can get the following results :

image.png

Then you can see that the template information has been cached in the corresponding path .

image.png

Above , We have completed a simple function of adding and modifying template information locally , Similarly, deleting is a similar operation , Develop according to your actual needs .

Download the template

After saving the template , We need to select the corresponding template to download .

Download and use download-git-repo As CLI Download plug-ins , This is a very easy-to-use plug-in , Support none clone Download the corresponding template , Very suitable for our project .

download-git-repo Is a download git repository The tool library , It provides abbreviations and direct:url There are two ways to download directly , It also provides direct download code and git clone The function of , Very easy to use .

Also when downloading the template , We need to show the user the current list of saved templates , You also need to use inquirer Tools .

  1. Use inquirer establish list Select Interactive Mode , Read the local template list , Let the user select the required template
export const selectTpl = () => {
  const tplList = getTplList()
  const promptList = [
    {
      type: 'list',
      message: ' Please select the template to download :',
      name: 'name',
      choices: tplList && tplList.map((tpl: ITpl) => tpl.name)
    },
    {
      type: 'input',
      message: ' Download path :',
      name: 'path',
      default({ name }: { name: string }) {
        return name.substring(name.lastIndexOf('/') + 1)
      }
    }
  ];

  inquirer.prompt(promptList).then((answers: any) => {
    const { name, path } = answers
    const select = tplList && tplList.filter((tpl: ITpl) => tpl.name)
    const tplUrl = select && select[0].tplUrl || ''
    loadTpl(name, tplUrl, path)
  })
}
 Copy code 
  1. Use download-git-repo Download the corresponding template
export const loadTpl = (name: string, tplUrl: string, path: string) => {
  download(`direct:${tplUrl}`, getCwdPath(`./${path}`), (err: string) => {
    if (err) {
      loggerError(err)
    } else {
      loggerSuccess(`Download ${name} Template Successful!`)
    }
  })
}
 Copy code 

But the problem is , If you choose direct The pattern of , So the download is a zip The address of , Not normal git Address , Then our above address is invalid , So before downloading the code, you need to do a layer of address conversion .

First look at the pull rule , natural git The address is https://github.com/boty-design/react-tpl, And actually github The download address in is https://codeload.github.com/boty-design/react-tpl/zip/refs/heads/main, You can see that compared with normal github Link words , The domain name and links have changed , But there must be a project name and a team name , So we can store boty-design/react-tpl Take it out , Later, it is convenient for us to assemble .

const { pathname } = new URL(tplUrl)
if (tplUrl.includes('github.com')) {
  reTpl.org = pathname.substring(1)
  reTpl.downLoadUrl = 'https://codeload.github.com'
}
 Copy code 

As the above code , analysis tplUrl To get the pathname It's the information we need , Again dowload The template , Just reassemble the download link .

image.png

image.png

As shown in the figure above , We can download the public template to the local , Convenient for students to develop normally , But there is another problem at this time , That's the branch above is main Branch , Not every template has this branch , Poor controllability , So how do we get all the branches of the project to selectively download .

Github Api

stay Github For open source 、 Not a private project , Authorization can be omitted token Steps for , Use it directly Github Api Get the corresponding information .

So for the problems mentioned above , We can use Github Api Provide the ability to solve .

The link to get the branch is https://api.github.com/repos/boty-design/react-tpl/branches, Before development, we can use PostMan To test whether it returns the results we need normally .

image.png

As you can see above , Have been able to pass Github Api Got the branch information we want .

If the following error occurs , No problem , It's just github Limit the frequency of access

image.png

To solve the above problems , What we need is to control the frequency 、 Use conditional requests or use token request Github Api To avoid , But given the template , Generally, the request frequency is not very high , It's just that I need constant requests to test when I'm developing , That's the problem , If you are interested, you can try other solutions by yourself .

Branch code optimization

 Unnamed file  (1).png

After pre research Github Api after , Next, you need to encapsulate the information you get , For example, when there is only one branch, users can directly download templates , If multiple branches are requested , You need to display the branch so that the user can freely select the corresponding branch to download the template , The overall business process diagram is shown above .

The main logic code is as follows :

export const selectTpl = async () => {
  const prompts: any = new Subject();
  let select: ITpl
  let githubName: string
  let path: string
  let loadUrl: string

  try {
    const onEachAnswer = async (result: any) => {
      const { name, answer } = result
      if (name === 'name') {
        githubName = answer
        select = tplList.filter((tpl: ITpl) => tpl.name === answer)[0]
        const { downloadUrl, org } = select
        const branches = await getGithubBranch(select) as IBranch[]
        loadUrl = `${downloadUrl}/${org}/zip/refs/heads`
        if (branches.length === 1) {
          loadUrl = `${loadUrl}/${branches[0].name}`
          prompts.next({
            type: 'input',
            message: ' Download path :',
            name: 'path',
            default: githubName
          });
        } else {
          prompts.next({
            type: 'list',
            message: ' Please select Branch :',
            name: 'branch',
            choices: branches.map((branch: IBranch) => branch.name)
          });
        }
      }
      if (name === 'branch') {
        loadUrl = `${loadUrl}/${answer}`
        prompts.next({
          type: 'input',
          message: ' Download path :',
          name: 'path',
          default: githubName
        });
      }
      if (name === 'path') {
        path = answer
        prompts.complete();
      }
    }

    const onError = (error: string) => {
      loggerError(error)
    }

    const onCompleted = () => {
      loadTpl(githubName, loadUrl, path)
    }

    inquirer.prompt(prompts).ui.process.subscribe(onEachAnswer, onError, onCompleted);

    const tplList = getTplList() as ITpl[]

    prompts.next({
      type: 'list',
      message: ' Please select a template :',
      name: 'name',
      choices: tplList.map((tpl: ITpl) => tpl.name)
    });
  } catch (error) {
    loggerError(error)
  }
}
 Copy code 

The above code , We can see the use of RXJS To dynamically render interactive problems , Because there are only one project branch of some templates . If we need users to select branches every time, it is redundant , So fixed problem interaction is no longer applicable , We need the help of RXJS Dynamic addition inquirer problem , Determine whether the select branch option appears by obtaining the number of branches , Improve user experience .

At the end

In the first chapter Enterprise class CLI Development in , We built a preliminary CLI Shelves , Provides build 、Eslint Basic functions such as verification .

In the second part Customize React The scaffold & CLI upgrade in , Let's build a simple React The scaffold , And the use of CLI To take over the template dev modular , It also provides extended build configuration and other functions , Complete a basic CLI Integration of template tools

In this article , We use the scaffold in the previous article as a template , Yes CLI Further transformation has been carried out , bring CLI Users can configure templates that meet their needs and habits independently .

After these three articles ,CLI The following functions have been provided :

CLI command function
fe-cli eslint For the current project Eslint check
fe-cli webpack Use Webapck Build the current project
fe-cli rollup Use Rollup Build the current project
fe-cli git init Local initialization git project ( The current support GitLab Some functions )
fe-cli add tpl Custom add template
fe-cli init tpl Initialize the added template to local

Whole CLI It will be designed according to the requirements of the first article , Gradually build a universal and transformable tool , Can give students a practical reference .

In the next article ,CLI It will be developed around the modules of the tool class .

All project codes have been uploaded to Project address , Interested students can pull for reference , The relevant codes of all subsequent columns will be uniformly placed in  BOTY DESIGN  in .

copyright notice
author[CookieBoty],Please bring the original link to reprint, thank you.
https://en.qdmana.com/2021/08/20210826154720620O.html

Random recommended