Scaffold development - preparation phase

Basic principle of scaffold

Click to view the overview of scaffold series articles [updating]
Personal website: www.dengzhanyong.com
Pay attention to the official account. Front end Xiaoyuan ], don't miss every article

Initialize project

1. Create project file

mkdir steamed-cli
cd steamed-cli

2. Use lerna to initialize the project

lerna init

The default project structure is as follows:

C:.
|  .git
│  lerna.json
│  package.json
│
└─packages

On this basis, some changes need to be made:

  • Delete the packages directory. Packages is the directory used to place all packages. If there are many packages, it is best to create several more folders to classify them

  • Create new folders commands, core, models, and utils

  • Modify lerna packages attribute in JSON configuration, which specifies the location of the package

    {
      "packages": [
        "core/*",
        "commands/*",
        "models/*",
        "utils/*"
      ],
      "version": "1.0.0"
    }
    
  • newly build. gitignore file, add git ignore file configuration * * / node_modules

  • Create a new readme MD file to introduce and use the scaffold

Overall process

The whole scaffold development is divided into three stages: preparation stage, registration stage and execution stage

  • Preparation stage: some things that need to be done before executing the command, such as checking the node version, checking the scaffold update, checking the user directory, permissions, etc
  • Registration phase: parse the command s and options entered by the user. The parameters here are mainly for global parameters.
  • Execution phase: Install / update the corresponding package, or directly execute the local file.

Preparation stage

Create entry package

Now officially start the development of scaffold. First, an entrance is required. Create a package called @ steamed/cli

lerna create @steamed/cli ./core
# At the end, you can add a path to create the package to the specified directory

The directory structure of a package is as follows:

cli:.
│  package.json
│  README.md
│
├─lib
│      cli.js
│
└─__tests__
        cli.test.js

In order to maintain a unified specification, it is best to use cli. Cli under lib JS to index js.

@The steered / cli package is the entrance of the whole scaffold. You need to create a / bin / index JS file as the entry, and in packages Configure the bin attribute in JSON.

{
    "name": "@steamed/cli",
    "version": "1.0.0",
	"bin": {
       "st": "./bin/index.js"
    }
}

Test process

Execute npm link under core/cli and create its soft link, so that we can debug locally with the set command.

In core / cli / bin / index JS, you can write a sentence and print console Log ('Hello steered cli '), and then execute the st command on the command line. If it is entered normally, it indicates that everything is normal so far.

How do I get the input command parameters?

You need to do different things according to different commands entered by the user. Use process Argv can get all the input, and its value is an array.

st init procejectName

[
  'C:\\Program Files\\nodejs\\node.exe',
  'C:\\Users\\DZY26\\AppData\\Roaming\\npm\\node_modules\\@steamed\\cli\\bin\\index.js',
  'init',
  'myname'
]
  • The first item is the installation directory of node
  • The second item is the path of the executed file
  • The following content is the passed in parameters

bin/index.js only does one thing

We put everything we need to do after entering the command into lib / index JS, in bin / index JS only does one thing.

  • Import local: allows globally installed packages to use their own locally installed version, if available

If there is a local version, execute the local version. If not, execute lib / index JS

#! / usr/bin/env nodeconst importLocal = require('import-local'); If (importlocal (_filename)) {console.log ('execute local scaffolding ');} else {    require('../lib/index')(process.argv.slice(2))}

Function development

The following npm packages are required for development at this stage,

  • semver: user version number, specification verification, version number comparison, etc
  • colors: sets the color for the printed log
  • userHome: get user home directory
  • npmlog: user input log information
  • Root check: try to demote the permissions of the process with root permission. If it fails, block access
  • dotenv: local The environment variables in the env file are configured into the global environment variables.

Toolkit development

@steamed/log

Function: encapsulate npmlog and customize print level and style

Location: / utils/log

**npmlog print level**

In different scenarios, npmlog can be used to print different types of information, including: sly, verbose, info, timing, http, notice, warn, error, silent

The default print level is info, that is, information greater than or equal to info level will be printed.

Main role

Debug information is usually printed at verbose level, so debug information will not be displayed by default. In order to better debug and locate problems, you can pass in the -- debug parameter so that you can see the debug information. The implementation principle is to set the print level of npmlog to verbose.

Full code:

'use strict';const log = require('npmlog');log.level = process.env.STEAMED_CLI_LOG_LEVEL || 'info';   // Set the print level of log. The default is info. You can get the custom level setting log in the environment variable heading = 'Steamed';   //  User defined log header information, usually the name of the scaffold log Headingstyle = {BG: 'white', FG: 'Black'} / / custom header style module exports = log;

@steamed/get-npm-info

Function: obtain npm information, version, etc

Location: / utils / get NPM info

Full code:

'use strict';const axios = require('axios');const semver = require('semver');// Get the default NPM source function getdefaultregistry (origin = true) {return origin? ' https://registry.npmjs.org/ ' : ' https://registry.npm.taobao.org/ '} / / get all the historical version numbers of the package async function getnpmversions (npmname, registry) {const npmregistry = registry | getdefaultregistry(); return Axios. Get (` ${npmregistry} ${npmname} `) then((res) => {            if (res.status === 200) {                return Object.keys(res.data.versions);            }             return [];        })        . catch(() => {            return [];        })}//  Get the latest version async function getlatestversion (npmname, registry) {convert versions = (await getnpmversions (npmname, registry)). Sort ((a, b) = > semver. GTE (a, b)? - 1: 1); if (versions [0]) {return versions [0]} else {throw new error ('check update failed ');}} module.exports = {    getDefaultRegistry,    getNpmVersions,    getLatestVersion};

Function realization in preparation stage

In the preparation stage, each function needs to be completed in the following order.

Check current version

This refers to the current version of scaffold, and this version number is package The value of version in JSON.

const pkg = require('../package.json'); // Check the current version function checkpkgversion() {log. Info ('cli version ', PKG. Version);}

Check node version

It is necessary to check whether the node version currently used by the user meets the minimum version requirements of the scaffold to ensure that all functions of the scaffold can be used normally.

Create a new constant JS file, the user configures some constant configuration information.

const LOWEST_NODE_VERSION = '12.0.0';   // Minimum node version const STEAMED_CLI_HOME_PATH = '.steamed';  //  Scaffold home directory name const STEAMED_CLI_LOG_LEVEL = 'info';   // log print level module exports = {    LOWEST_NODE_VERSION,    STEAMED_CLI_HOME_PATH,    STEAMED_CLI_LOG_LEVEL}
const semver = require('semver');const { LOWEST_NODE_VERSION } = require('./constant');// Check node versionfunction checknodeversion() {const currentVersion = process. Version; / / get the currently used version const lowestVersion = lowest_node_version; if (! Semver.gte (currentVersion, lowestVersion)) {throw new error (` steered cli requires that the minimum version of node is ${lowestVersion}, and the current version of node.js is ${currentVersion} ') ;    }}

Check root permissions

You need to check whether the user has root permission. If not, it will be degraded. This function has been implemented in root check.

import rootCheck from 'root-check';// Check root permissions function checkRoot(){ 	 rootCheck();}

Check user home directory

Check whether the user home directory exists

const userHome = require('user-home');// Check user home directory function checkuserhome() {if (! Userhome |! FS. Existssync (userhome)) {throw new error (colors. Red ('current user home directory does not exist! ');} else {        process.env.STEAMED_CLI_USER_HOME = userHome;    }}

Check input parameters

  • If you need to execute a command, you need to enter at least one command or parameter.
  • Check whether the parameter entered by the user contains - d or -- debug. If it exists, it means that the debug mode is enabled and the print level of log needs to be set to verbose
const log = require('@steamed/log');const { STEAMED_CLI_LOG_LEVEL } = require('./constant');// Check user home directory function checkargv (argv) {if (argv. Length < 0) {throw new error ('Please enter command ')} if (argv. Includes (' - D ') | argv includes('--debug')) {        log.level = 'verbose';    }  else {        log.level = STEAMED_CLI_LOG_LEVEL;    }     process.env.LOG_LEVEL = log.level; //  Save the log level to the environment variable for use elsewhere}

Check environment variables

Put the in the home directory Environment variables in env file will be injected into process In env

const { STEAMED_CLI_HOME_PATH } = require('./constant');const userHome = require('user-home');// Check the environment variable function checkenv() {const dotnev = require ('dotenv '); const envpath = path.resolve (userhome,'. Env '); / / get the. Env file dotnev.config ({path: envpath}); / / Environment variables in Env are injected into process Process in Env env. STEAMED_ CLI_ HOME_ PATH = path. resolve(userHome, STEAMED_CLI_HOME_PATH);}

Check for version updates

Check whether the local scaffold version is the latest version. If not, prompt the user to update the scaffold in time

const { getLatestVersion } = require('@steamed/get-npm-info');// Check and update async function checkcliupdate() {const lastVersion = await getlatestversion (PKG. Name); if (lastVersion & &! Semver.gte (pkg.version, lastVersion)) {log. Warn ('steadied update ', ` new version ${lastVersion} found, current version ${pkg.version}, please update it in time! `);}}

Print error message

In the above process, there may be errors at each step, either the internal error of the third-party component or the throw new Error() written by ourselves. We can process these error messages through try catch at the outermost layer.

async function index() {    try {        checkPkgVersion();        checkNodeVersion();        checkRoot();        checkUserHome();        checkEnv();        await checkCliUpdate();    } catch (e) {        log.error(e.message);  // Print only the key information if (log.level === 'verbose') {/ / if it is in the debug mode, print the complete error information stack to locate the problem console.log(e);}}}

Full code address Github: https://github.com/DengZhanyong/steamed

Click to view the overview of scaffold series articles

Personal website: www.dengzhanyong.com

Pay attention to the official account. Front end Xiaoyuan ], don't miss every article

Keywords: node.js Front-end npm

Added by blink359 on Mon, 03 Jan 2022 14:52:26 +0200