This article has participated in the good article call order activity, click to see: back end, big front end double track submission, 20,000 yuan prize pool for you to challenge!

Hello, everyone. I’m an unwomanly cat.

In this article you can learn:

  • Be familiar withcliThe whole process of development can be developed similar@babel/core,@babel/preset-envNPM package
  • Be familiar withnpmRelease process
  • Be familiar withlernaThe development ofcliTools, quick startlerna
  • How does an architect complete the design and development of a scaffold
  • How can scaffolding be used to efficiently solve CI/CD processes in daily development

Note: this article Lao na under the MAC test, use the classmate directory of win own change below ha

1. Prepare

Why develop scaffolding (think like an architect)

That’s where it comes inCI/CD:

Assembly lines in factories produce consumer goods from raw materials in a fast, automated and repeatable manner. Similarly, the software delivery pipeline generates releases from source code in a fast, automated, and repeatable manner. The overall design of how this is done is called “Continuous delivery” (CD). The process of starting an assembly line is called “continuous integration” (CI). The process of ensuring quality is called “continuous testing,” and the process of delivering the final product to the user is called “continuous deployment.” Some experts make it all simple, smooth, and efficient, and they’re called DevOps practitioners. [1]

Problem solved:

Traditionally (in fact, larger companies consider CI/CD automation) manual operations are inefficient, error prone, dependent on certain people, etc. These issues get worse as the project gets bigger, not to mention “grayscale publishing,” and any one of these points is reason enough to continue with this article. Being a front-end architect is all about solving “efficiency” problems.

Solution scenario:

  • Unified CI/CD specification
  • Improve CI/CD efficiency
  • Reduce CI/CD error rate
  • Don’t rely on anyone. Follow the process

Front knowledge

  • Be familiar withjsTo understandnodejs
  • Knowledge of one or more command-line tools, such as:vue-cli,vite,create-react-app,gitEtc.
  • To understandnpmjsRegistration, login, publishing, etc. (Minimum knowledge tutorial below)

demand

  • Subcontracting, if a scaffolding is more complex, it must involve subcontracting, subcontracting can effectively reduce the complexity of the project, improve development/maintenance efficiency, and each subcontracting is relatively independent, can be used separately,babelThere are nearly 150 bags,Click to viewHow can you manage all these packages? How do I install dependencies each time I update the version? What about the escalation of subcontracting dependence?
  • Command + subcommand, daily usegit.vue-cliBoth have subcommands, and scaffolds can involve subcommands if they are complex enough
  • The log
  • Command line interaction
  • Network request
  • Local file processing

Note: When we do the demand research and technology selection of a project, we will not only consider what is needed at the moment, but “consider one more step” under the demand and consider its expansibility, such as subcontracting, command + subcommand as above. Of course, if it is really a small scaffolding, it is possible to reduce the complexity of the design by not considering subcontracting (of course, familiar with LERNA is not the complexity), for example only one or two functional modules. But if, like Vue-CLI or Babel, there are dozens or hundreds of modules/plug-ins involved, you must consider them. As a reservation, we use a Multirepo extension scheme here.

Monorepo vs Multirepo

The selection

  • The subcontract,lerna, famous in the industryMultirepoSolution Solution
  • Command + subcommand,commander,yargs
  • The log,npmlog,colors
  • Command line interaction
  • Network request
  • Local file processing,fs-extra

other

  • Version comparison:semver
  • Parse parameter options:minimist

2. Start

2.1. The initialization

  • createmkdir ~/huamiao-cli_allFolder with back-end services behind it
  • createmkdir ~/huamiao-cli_all/huamiao-cli
  • Switch directory:cd ~/huamiao-cli_all/huamiao-cli
  • To initialize an NPM project:npm init -y
  • Install lerna:npm i -D lernaFor ease of use (without using NPX), install lerna globally:npm i -g lerna
  • Lerna initialization:lerna initIf you do not want to install LERna globally, usenpx lerna initGenerated),lerna.jsonChange the version to1.0.0
{
  "packages": [
    "packages/*"]."version": "1.0.0"
}

Copy the code
  • lerna initWill be executed by defaultgit initTo create.gitignore, ignore the following files:
**/node_modules
.vscode
.DS_Store
lerna-debug.log
Copy the code
  • Git is temporary:git add . && git status
Git add. && git status: ("git rm --cached < file >...") To unsave) New file:.gitignore New file: lerna.json New file: package-lock-json New file: package.jsonCopy the code
  • Submit to local repository:git commit -m 'init'

Note: If the NPM official source is too slow, you can switch to Taobao source or use CNPM /yarn

npm config set registry https://registry.npm.taobao.org/
Copy the code

2.2. Create packages & test releases

  • createcoreCore package, enterlerna create coreAll the way to enter

Special note: Package name: (core) @huamiao-cli/core, this needs to include the organization name @Huamiao-cli

lerna create core package name: (core) @huamiao-cli/core { "name": "@huamiao-cli/core", "version": "1.0.0", "description" : "> TODO: the description" and "homepage" : ""," license ":" ISC ", "main" : "lib/core. Js", "directories" : { "lib": "lib", "test": "__tests__" }, "files": [ "lib" ], "publishConfig": { "registry": "https://registry.npm.taobao.org" }, "scripts": { "test": "echo \"Error: run tests from root\" && exit 1" } } Is this OK? (yes) lerna success create New package @huamiao-cli/core created at ./packages/coreCopy the code
  • createutilsTool kit, ditto
  • npmjsCreate a group:@huamiao-cli

Click on theCreate Click on theSkip Now you canNPMJS -> Profiles -> PackagesSee the

  • Release,lerna publish, publish the organization’s packages need to be configuredpublishConfig

If you use Taobao source, the following situation may occur:

{
  "name": "@huamiao-cli/core"."version": "1.0.6"."description": "> TODO: description"."homepage": ""."license": "ISC"."main": "lib/core.js"."directories": {
    "lib": "lib"."test": "__tests__"
  },
  "files": [
    "lib"]."publishConfig": {
    "registry": "https://registry.npm.taobao.org"
  },
  "scripts": {
    "test": "echo 'run utils test'"}}Copy the code

Look at this

  "publishConfig": {
    "registry": "https://registry.npm.taobao.org"
  },
Copy the code

Change package.json to:

  "publishConfig": {
    "access": "public"
  }
Copy the code

Git commit before release, and bind to remote repository, otherwise:

Lerna publish info CLI using local version of Lerna Lerna notice CLI v4.0.0 lerna info current version 1.0.0 Lerna ERR! ENOREMOTEBRANCH Branch 'master' doesn't exist in remote 'origin'. lerna ERR! ENOREMOTEBRANCH If this is a new branch, please make sure you push it to the remote first.Copy the code

We are creating a public library in Gitee, so I won’t go into detail here.

Configure the remote repository and push:

git remote add origin https://gitee.com/xxx/huamiao-cli.git
git push -u origin master
Copy the code

Switch to NPM official source:

npm config set registry https://registry.npmjs.org
Copy the code

Note: If you do not switch to the official source by mistake, submit another Git and release it, and the version can be released by accumulating

Publish: lerna publish select first:

❯ Patch (1.0.1) Minor (1.1.0) Major (2.0.0) Prepatch (1.0.1-alpha.0) Preminor (1.1.0-alpha.0) Premajor (2.0.0-alpha.0) ❯ Patch (1.0.1) Minor (1.1.0-alpha.0) Premajor (2.0.0-alpha.0) Custom Prerelease Custom VersionCopy the code

Enter y

Lerna publish Info CLI using local version of Lerna Lerna notice CLI v4.0.0 Lerna info current version 1.0.0 Lerna info Assuming all packages changed ? Select new version (@huamiao) Patch (1.0.1) Changes: -@huamiao -cli/core: 1.0.0 => 1.0.1 -@huamiao -cli/utils: 1.0.0 = > 1.0.1? Are you sure you want to publish these packages? (ynH) y>> Yes
Copy the code

Full log:

Info CLI using local version of lerna Lerna notice CLI v4.0.0 Lerna info current version 1.0.4 Lerna info Looking for Changed Packages since V1.0.4? Select a new version (currently 1.0.4) Patch (currently 1.0.5) Changes: -@huamiao -cli-dev/core: = > 1.0.4 1.0.5 - @ huamiao - cli - dev/utils: = > 1.0.4 1.0.5? Are you sure you want to publish these packages? Yes lerna info execute Skipping releases lerna info git Pushing tags... lerna info publish Publishing packages to npm... lerna notice Skipping all user and access validation due to third-party registry lerna notice Make sure you're Authenticated ¯\_(ツ)_/¯ lerna WARN ENOLICENSE Packages @huamiao-cli-dev/core and @Huamiao-cli-dev /utils are missing a license. lerna WARN ENOLICENSE One way to fix this is to add a LICENSE.md file to the root of this repository.  lerna WARN ENOLICENSE See https://choosealicense.com for additional guidance. lerna http fetch PUT 200 https://registry.npmjs.org/@huamiao-cli-dev%2futils 4431 ms lerna success published @ huamiao - cli - dev/utils 1.0.5 lerna Notice lerna notice 📦 @huamiao-cli-dev/[email protected] lerna notice === Tarball Contents === lerna notice 73B lib/utils.js lerna notice 487B package.json lerna notice 108B README.md lerna notice === Tarball Details === lerna notice name: @huamiao-cli-dev/utils lerna notice version: 1.0.5 lerna notice filename: Huamiao-cli-dev-utils-1.0.5.tgz Lerna notice Package size: 565 B Lerna notice unpacked size: 668 B Lerna notice shasum: 9af0a5740f88b0a6829ea4a90c7107435d0f5489 lerna notice integrity: sha512-8kKZVoH1sF0WB[...] 1aTA3UQiBl70g== lerna notice total files: 3 lerna notice lerna http fetch PUT 200 https://registry.npmjs.org/@huamiao-cli-dev%2fcore 7474ms lerna success Published @huamiao-cli-dev/core 1.0.5 lerna notice lerna notice 📦 @huamiao-cli-dev/[email protected] lerna notice === Tarball Contents === lerna notice 71B lib/core.js lerna notice 485B package.json lerna notice 105B README.md lerna notice === Tarball Details === lerna notice name: @huamiao-cli-dev/core lerna notice version: 1.0.5 lerna notice filename: Huamiao-cli-dev-core-1.0.5.tgz Lerna notice Package size: 566 B Lerna notice unpacked size: 661 B Lerna notice shasum: a26f686a3951de2df1ef2196a1b82c9d87e299ec lerna notice integrity: sha512-rP/WQo7oROLD3[...] 7LZKGyzZ9vHYQ== lerna notice total files: 3 lerna notice Successfully published: - @huamiao-cli-dev/[email protected] - @huamiao-cli-dev/[email protected] lerna success Published 2 PackagesCopy the code

After the release is successful, check whether the release is successful in the HUamiao – CLI organization in NPMJS Packages.

This is published in the huamiao-CLI-dev organization

NPMJS is occasionally unstable, and the access to the domestic network is often slow due to the connectivity problems. If it fails, it is not our problem and can be rereleased. In other words, each release of Learn requires a version, which is a little unreasonable

Note: the novice here will encounter various problems, if there are problems, you can leave a message to solve.

It is strongly recommended that the novice test release is successful before development.

3. Have the minimum necessary knowledge

3.1. Learn

3.1.1. Initialization

  • lerna init, initialize the project, createlerna.jsonstorageversionAnd check thepackage.jsonIn thedevDependencyWith or withoutlerna, if no, add

3.1.2. Create a package

  • Lerna create, create package
<> is required and [] is optionalUsage:lerna create <name> [loc] name: unique, containing scope domain name (@huamiao-cli, eg: @huamiao-cli/core) loc: packages and packages can be nested, select the relative address of the package, default to the first configured package locationCopy the code
  • lerna add, install dependencies, eg:lerna add module-1 --scope=module-2.scopeSpecify packages. Do not specify that dependencies will be installed in each package. Only one dependency can be installed at a time
Usage: lerna add <package>[@version] [--dev] [--exact] [--peer]Copy the code
  • Lerna link, link dependency, local debugging package interdependence, multiple packages developed together

3.1.3. Development and testing

  • lerna execFor each package in packages, run the command eg:lerna exec -- rm -rf ./node_modules
  • lerna run, for each package in Packagesnpm scriptEg:lerna run test
  • lerna clean, remove node_module from all packages, approximately equal tolerna exec -- rm -rf ./node_modules
  • Lerna bootstrap: re-install dependencies for each package in packages

3.2. npmSimple Release process

3.2.1. npmjsRegistered account

3.2.2. Switching to the official source

Open the terminal and switch to the official source (if the source has not been switched before, it is official by default, and you do not need to switch).

npm config set registry https://registry.npmjs.org
Copy the code

3.2.3. The NPM to log in

npm login

Username: <username>
Password: 
Email: (this IS public) <username>@qq.com
Logged in as <username> on https://registry.npmjs.org/.
Copy the code

3.2.4. NPM release

npm publish

Successfully published:
 - @huamiao-cli/[email protected]
 - @huamiao-cli/[email protected]
lerna success published 2 packages
Copy the code

4. Cli preparations

4.1. Configuration Commands

Packages /core will serve as the CLI entry

Switch to the Packages /core directory

Add file bin/index.js:

#! /usr/bin/env node

require('.. /lib/index') ();Copy the code

Package. Json to add:

"bin": {
  "miao": "bin/index.js"
},
Copy the code

Lib/index. Js:

console.log('hello world! ');
Copy the code

If NPM Link is installed globally, the miao command can be invoked globally

Open the terminal to test: Miao, the test succeeds, print out normally:

hello world!
Copy the code

4.2. Version number and greeting

Then develop and get the version number

const packageJson = require('.. /package');
Copy the code

The greeting above, more general, let’s have a strong:

const packageJson = require('.. /package');

console.log('Welcome to use');
console.log(There comes ` _ _ __ __ _ _ _ | | | | _ _ __ _ | \ \ / (_) __ _ ___ ___ | (_) | | _ | | | | | / _ \ ` | | \ \ / | | | / _ \ ` | / _ \ \ ___ | | _ - _ - | | | | | | | | (_ | | | | | | (_ | | (_) | | ___ | | | ___ | | | | _ | | _ | \ \ __, _ | \ \ __, _ _ - | | | _ _ - | | \ \ __, _ | \ \ ___ there comes / \ \ | _ _ - | | Version${packageJson.version}
`);
Copy the code

4.3. Log, subcontract development

Console. log(‘ welcome ‘) above; Change the color to improve the force:

const { log } = require('@huamiao-cli/utils');
Copy the code

We haven’t developed the log yet

The core/package. Add json

"dependencies": {
    "@huamiao-cli/utils": "^ 1.0.0"
},
Copy the code

lerna link

Now you can use the packages/utils method

To switch to npmlog, you need to install a dependency on NPM I npmlog

Packages/utils/package. Json modification:

  "main": "lib/index.js".Copy the code

Lib/index. Js file:

'use strict';

const log = require('./log');

// Export unified, there are many tools behind
module.exports = {
  log
};
Copy the code

Lib/log. Js file:

const log = require('npmlog')

log.level = 'info'

log.heading = 'huamiao-cli' // Customize the header
log.addLevel('success'.2000, { fg: 'green'.bold: true }) // Customize the Success log
log.addLevel('notice'.2000, { fg: 'blue'.bg: 'black' }) // Customize the notice log

module.exports = log
Copy the code

Back in the packages/core/lib/index. Js:

"use strict";

module.exports = core;

const packageJson = require(".. /package");
const { log } = require("@huamiao-cli/utils");

function core() {
  console.log(There comes ` _ _ __ __ _ _ _ | | | | _ _ __ _ | \ \ / (_) __ _ ___ ___ | (_) | | _ | | | | | / _ \ ` | | \ \ / | | | / _ \ ` | / _ \ \ ___ | | _ - _ - | | | | | | | | (_ | | | | | | (_ | | (_) | | ___ | | | ___ | | | | _ | | _ | \ \ __, _ | \ \ __, _ _ - | | | _ _ - | | \ \ __, _ | \ \ ___ there comes / \ \ | _ _ - | | Version${packageJson.version}
`);
  log.info("Welcome to use");
}
Copy the code

This version number, welcome has been OK

4.4. Determine the lowest nodeJS version

Some of the libraries used by the CLI need nodeJS version 12+, so we need to check the current nodeJS version, and we need to install the semver package: NPM I Semver

Packages/core/lib/index, js is increased:

  const semver = require("semver");
  const MINIMUM_NODEJS_VERSION = "14.0.0";

  if (semver.lte(process.version, MINIMUM_NODEJS_VERSION)) {
    console.log('huamiao- CLI Minimum node.js version V${MINIMUM_NODEJS_VERSION}`);
    process.exit();
  }
Copy the code

This hint we want to make red, we can use log:

  const semver = require("semver");
  const MINIMUM_NODEJS_VERSION = "14.0.0";

  if (semver.lte(process.version, MINIMUM_NODEJS_VERSION)) {
    log.error('huamiao- CLI Minimum node.js version V${MINIMUM_NODEJS_VERSION}`);
    process.exit();
  }
Copy the code

The lowest nodejs version number is removed from the constant to make it easier to change later

Packages/core/lib/index. Js now we complete code is as follows:

"use strict";

module.exports = core;

const packageJson = require(".. /package");
const { log } = require("@huamiao-cli/utils");

function core() {
  console.log();
  console.log(There comes ` _ _ __ __ _ _ _ | | | | _ _ __ _ | \ \ / (_) __ _ ___ ___ | (_) | | _ | | | | | / _ \ ` | | \ \ / | | | / _ \ ` | / _ \ \ ___ | | _ - _ - | | | | | | | | (_ | | | | | | (_ | | (_) | | ___ | | | ___ | | | | _ | | _ | \ \ __, _ | \ \ __, _ _ - | | | _ _ - | | \ \ __, _ | \ \ ___ there comes / \ \ | _ _ - | | Version${packageJson.version}
`);
  log.info("Welcome to use");
  console.log();

  const semver = require("semver");
  const MINIMUM_NODEJS_VERSION = "14.0.0";

  if (semver.lte(process.version, MINIMUM_NODEJS_VERSION)) {
    log.error('huamiao- CLI Minimum node.js version V${MINIMUM_NODEJS_VERSION}`); process.exit(); }}Copy the code

To perform themiao:

4.5. Analyze whether the parameter is valid and whether to debug

Let’s look at the parameters

Easy to debug packages/utils/lib/the js can modify the log level for verbose, this is for the use of debug level:

log.level = 'verbose'
Copy the code

The minimist package, installed under the dependency: NPM I Minimist

  const minimist = require("minimist");

  log.info("Verify input parameters:");
  let args = minimist(process.argv.slice(2));
  log.info("args: ", args);
  
  if (args["_"].length === 0) {
    log.warn('Please enter parameters')}Copy the code

Test Miao cmdChild cmdchildparams-a aparams-b bParams

Huamiao -cli verb args: {_: ['cmdChild', 'cmdChildParams'], a: 'aParams', b: 'bParams' }Copy the code

We often need debugging, so we add a debug parameter, miao –debug, minimist support by default

  const minimist = require("minimist");

  log.info("Verify input parameters:");
  let args = minimist(process.argv.slice(2));
  log.info("args: ", args);

  if (args["_"].length === 0 && !args.debug) {
    log.warn("Please enter parameters");
  } else {
    // You can configure debug Settings here, such as changing the log level to verbose to print debug logs
    log.level = "verbose";
    log.verbose("debug");
  }
Copy the code

Add the environment variable process.env.log_level and set the log level

  const minimist = require("minimist");

  log.verbose("Verify input parameters:");
  let args = minimist(process.argv.slice(2));
  log.verbose("args: ", args);

  if (args["_"].length === 0 && !args.debug) {
    log.warn("Please enter parameters");
  } else {
    // You can configure debug Settings here, such as changing the log level to verbose to print debug logs
    if (args.debug) process.env.DEBUGGING = "verbose";
    else process.env.DEBUGGING = "info";
    log.level = process.env.DEBUGGING;
  }
Copy the code

The preparations are over

4.6. Registration commands

Using the Commander package, install the dependency: NPM I Commander

const program = require("commander");

// Set the version number and custom usage description
program.version(packageJson.version).usage(" [options] Other Instructions");

// Add commands can be added here
/ /...

// Register command
program.parse(process.argv);
Copy the code

So let’s test that out,miao -h Add a simple command:

const program = require("commander");

  // Set the version number and custom usage description
  program.version(packageJson.version).usage(" [options] Other Instructions");

  // Add commands can be added here
  program
    .command("test")
    .description("Description")
    .option("-a, --all"."Empty it all.")
    .action((cmd, options) = > {
      / / CMD. All automatically by the above configuration. Option (" -a - all ", "clear all") to create
      console.log("cmd: ", cmd.all);
      log.success("Test"."A flowered cat.");
    });

  // Other subcommands
  program.command("*").action(function (cmd, options) {
    console.log("cmd: ", cmd);
    console.log("options: ", options.args);
    console.log("Command not matched: miao", args['_']);
  });

  // Register command
  program.option("--debug"."Turn on debug mode").parse(process.argv);
Copy the code

Try miao Test-a aAAA, All BBBB, and DIY!

Content is a bit much, the first section so!

FAQ

  • Dependency error or unknown error, clean up all dependencieslerna clean, reload dependencelerna bootstrap

Loadmap

  • Init [blockbuster] : Select a template, customize a template, etc
  • Release [blockbuster] : Release, Git operation, build, etc
  • More implementation details

reference

  • [1] What is CI/CD: linux.cn/article-992…
  • Lerna doc:github.com/lerna/lerna
  • What is CI/CD: www.redhat.com/zh/topics/d…

The more you like it, the more you follow it