Write your own cli and publish it to npm

Write your own cli and publish it to npm

Introduction: Everyone must have used vue-cli or create-react-app. You can generate a complete project with a simple command line, which is very easy to use. Since my company accepts a lot of projects, every time I create a new project, I copy the previous project code, which is troublesome, and I have to delete a lot of useless code, which is tiring. So I thought of imitating vue-cli to write a simple cli to create a project, so it saves worry and effort. So just do it and write a cli:, vea-cliyou can also use it, just execute the following command, as follows

npm install vea-cli -g
vea-cli init project-name

github source address

Here are the implementation steps

1. Project dependencies: (install first, steps omitted)

 "dependencies": {
    
    
    "chalk": "^3.0.0",
    "commander": "^4.0.1",
    "download-git-repo": "^3.0.2",
    "inquirer": "^7.0.1",
    "ora": "^4.0.3"
  },
  "devDependencies": {
    
    
    "eslint": "^6.8.0",
    "eslint-config-standard": "^14.1.0",
    "eslint-plugin-import": "^2.19.1",
    "eslint-plugin-node": "^11.0.0",
    "eslint-plugin-promise": "^4.2.1",
    "eslint-plugin-standard": "^4.0.1"
  }

2. Project directory structure
Insert picture description here

3. Core code

/bin/vea-cli (no file extension)

// 告诉执行环境用node来执行
#!/usr/bin/env node

// 添加命令的库
const program = require('commander')

// 拿到package.json 里的版本号
const packageJson = require('../package.json')
const init = require('../lib/init')

//  执行  vea-cli -V 会输出版本号
program.version(packageJson.version)

// 添加init命令,简写是i, <name> 是参数  action回调里可以拿到
program
  .command('init <name>')
  .alias('i')
  .description('vue admin 项目初始化工具')
  .action(name => {
    
    
    init(name)
  })

// 解析命令行参数
program.parse(process.argv)


lib/clone.js

// node的 util 模块 promisify可以把回调promise化
const {
    
     promisify } = require("util");

// 进度显示工具
const ora = require("ora");

// 颜色显示工具
const chalk = require("chalk");

// 下载git 仓库代码工具
const download = promisify(require("download-git-repo"));

/**
 *
 * @param {string} repo 仓库地址
 * @param {string}  dir 文件夹
 * @param {object}  opotions 配置项
 */
const clone = async function(repo, dir, opotions = {
    
    }) {
    
    
  const process = ora(`开始下载 ${
      
      chalk.blue(repo)}`);
  process.start();
  process.color = "yellow";
  process.text = `正在下载..... ${
      
      chalk.yellow(repo)} `;

  try {
    
    
    await download(repo, dir, opotions);
    process.color = "green";
    process.text = `下载成功 ${
      
      chalk.green(repo)} `;
    process.succeed();
  } catch (error) {
    
    
    process.color = "red";
    process.text = "下载失败";
    process.fail();
  }
};

module.exports = clone;

lib/init.js

const chalk = require("chalk");

// 用户与命令行交互的工具
const Prompt = require("inquirer");

const clone = require("./clone");

// 对应github仓库地址https://github.com/l-x-f/admin-template
// #dev 是dev分支,不写默认master分支
const remote = "github:l-x-f/admin-template#dev";

const initQuestions = name => [
  {
    
    
    type: "confirm",
    name: "isInit",
    message: `确定要在${
      
      chalk.green(name)}文件夹下创建项目?`,
    prefix: "?"
  }
];

const init = async name => {
    
    
  try {
    
    
    const {
    
     isInit } = await Prompt.prompt(initQuestions(name));
    if (isInit) {
    
    
      await clone(remote, name);
    } else {
    
    
      console.log(chalk.red("程序提前结束"));
    }
  } catch (error) {
    
    
    console.log(chalk.red(error));
  }
};

module.exports = init;

package.json

The focus is on the configuration of the bin field

 {
    
    
  "name": "vea-cli",
  "version": "1.0.1",
  "description": "vue element-ui admin 项目初始化工具",
  "main": "index.js",
  "scripts": {
    
    
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "bin": {
    
    
    "vea-cli": "./bin/vea-cli"
  },
  "keywords": [
    "vue",
    "vue-cli",
    "vea-cli",
    "vue element-ui admin 项目初始化工具"
  ],
  "author": "xiaofei",
  "license": "MIT",
  "dependencies": {
    
    
    "chalk": "^3.0.0",
    "commander": "^4.0.1",
    "download-git-repo": "^3.0.2",
    "inquirer": "^7.0.1",
    "ora": "^4.0.3"
  },
  "devDependencies": {
    
    
    "eslint": "^6.8.0",
    "eslint-config-standard": "^14.1.0",
    "eslint-plugin-import": "^2.19.1",
    "eslint-plugin-node": "^11.0.0",
    "eslint-plugin-promise": "^4.2.1",
    "eslint-plugin-standard": "^4.0.1"
  }
}

4. Local test

The implementation of the project root directory npm linkwill vea-clicommand links to the global

npm unlink vea-cli Can be deleted

You can see the effect after execution

vea-cli init project-name

5. Publish to npm (register your own account)

Create a new publish.sh in the project root directory

#!/usr/bin/env bash
set -e

# 修改npm源地址
npm config get registry
npm config set registry=http://registry.npmjs.org

# 登陆输入自己的npm账号和密码,还有邮箱
echo '登录'
npm login

echo "发布中..."
npm publish

# 改回npm源地址
npm config set registry=https://registry.npm.taobao.org
echo -e "\n发布成功\n"
exit

./publish.sh Display after successful execution
Insert picture description here

6. Test after release

npm i -g vea-cli

If you don’t have this package, then take a look, is the npm source http://registry.npmjs.org? There is a time difference in taobao source synchronization

7. Realize the effect

Insert picture description here

8. Cancel or delete the npm package after publishing

Mandatory cancellation, only allowing the version released within the last 72 hours to be cancelled

npm unpublish --force

Delete the released package

npx force-unpublish package-name '原因描述'

Reference link

1.https://github.com/sindresorhus/ora

2.https://blog.csdn.net/qq_26733915/article/details/80461257

3.https://github.com/vuejs/vue-cli

4.https://github.com/chalk/chalk

5.https://github.com/ianstormtaylor/download-github-repo

6.https://github.com/tj/commander.js

7.https://www.cnblogs.com/wangming1002/p/10973759.html

Guess you like

Origin blog.csdn.net/qq_39953537/article/details/103747370