npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

create-my-react-project

v1.2.7

Published

首先,需要确保你已经安装了 node,然后我们来初始化一个项目

Downloads

10

Readme

1. 准备

首先,需要确保你已经安装了 node,然后我们来初始化一个项目

mkdir mycli-demo & cd mycli-demo
npm init -y

2. 添加一个简单的命令

在 package.json 中添加 bin 配置,mycli是我们 cli 工具提供的命令名称,对应的值是文件入口,我们这里指向bin/cli.js文件

{
  "name": "mycli-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
+ "bin":{
+   "mycli": "./bin/cli.js"
+ },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

在项目中创建bin/cli.js,并打印一段文字

#!/usr/bin/env node

console.log("i'm a cli");

第一行很重要,用来指明运行环境

此时我们可以再控制台运行mycli

你可能会有错误:控制台找不到我们的cli工具,这是因为我们在使用一个工具的时候必须安装它,例如你没有安装npm的时候去使用也会遇到同样的错误。

由于我们的mycli并没有发布,因此可以借助npm link或者yarn link选择本地安装,执行:

npm link

yarn link

如果你觉得 npm link 和 yarn link 比较繁琐,你也可以使用yalc 进行本地调试

然后再执行mycli,就可以看到控制台输出了bin/cli.js中打印的内容

至此,我们已经了解cli工具是如何作用的,下面我们在此基础上做一些改进,让他可以处理参数,彩色打印,显示加载中等等功能

3. 处理参数

很多时候我们需要在运行cli工具时携带参数,那么如何获取到这个参数呢?

node程序中,通过process.argv可获取到命令的参数,以数组返回

可以看到其实我们已经拿到各个参数,但是这样的获取方式不太直观,所以我们引入一个第三方 npm 包帮我们处理这部分功能:commander,参考文档:commander 文档

npm i commander -S

我们在bin/cli.js添加如下代码

#!/usr/bin/env node
+ const program = require('commander')

console.log("i'm a cli")

// 打印参数
console.log(process.argv)

+ program
+  .command('create <projectName>')
+  .description('create a new project')
+  .alias('c')
+  .option('-u, --umi', 'umi react template')
+  .option('-v, --vite', 'vite react template')
+  .option('-w, --webpack', 'webpack react template')
+  .action((projectName, options) => {
+    console.log(projectName, options)
+ })
+ program.version('1.0.0').parse(process.argv)

到目前为止,我们可以直观的获取到命令的参数,你可以在控制台尝试一下

4. 交互式命令

有的时候我们可能需要在命令行工具中融入一些交互,根据用户的输入或者选择生成一些东西或者做相应的操作。我们可以引入一个npm包来帮我们实现:inquirer

npm i inquirer -S

我们在bin/cli.js添加如下代码

#!/usr/bin/env node
const program = require('commander')
+ const inquirer = require('inquirer')

console.log("i'm a cli")

// 打印参数
console.log(process.argv)

program
  .command('create <projectName>')
  .description('create a new project')
  .alias('c')
  .option('-u, --umi', 'umi react template')
  .option('-v, --vite', 'vite react template')
  .option('-w, --webpack', 'webpack react template')
  .action((projectName, options) => {
    console.log(projectName, options)
+   inquirer
+     .prompt([
+       {
+         type: 'list',
+         name: 'frameTemplate',
+         message: '请选择框架类型',
+         choices: ['vite react', 'umi react', 'webpack react']
+       }
+     ])
+     .then((answer) => {
+       console.log(answer)
+     })
  })
program.version('1.0.0').parse(process.argv)

我们在控制台运行

mycli create test -r

至此,我们完成了交互式命令,下面我将完成一个模板的下载,一起动手吧!

5. 完成一个模板下载

在前面的步骤中,我们发现我们的日志打印不是很友好,我们可以通过log-symblos chalk ora 帮我们做一些提示信息的优化

| npm 包名称 | 作用 | 官网 | 备注 | | :---------- | ------------------------ | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | | chalk | 修改控制台中字符串的样式 | chalk | 字体样式、颜色、背景颜色 | | log-symbols | 各种日志级别的彩色符号 | log-symbols | 从 5 版本开始使用 ESMRelease v5.0.0 | | ora | 终端加载效果 | ora | |

由于 log-symbols 从 5 版本开始使用 ESM,所以我们这里使用 4 版本

npm i chalk log-symbols@4 ora -S

要下载一个 github 仓库的代码,我们需要引入download-git-repo, download-git-repo - npm

npm i download-git-repo -S

我们来实现一个简单的下载功能

#!/usr/bin/env node
const program = require('commander')
const inquirer = require('inquirer')
+ const ora = require('ora')
+ const download = require('download-git-repo')
+ const { errLog, successLog } = require('../src/utils/log.js')

console.log("i'm a cli")

// 打印参数
console.log(process.argv)

program
  .command('create <projectName>')
  .description('create a new project')
  .alias('c')
  .option('-r, --react', 'react template')
  .option('-v, --vue', 'vue template')
  .option('-v2, --vue2', 'vue2 template')
  .option('-v3, --vue3', 'vue3 template')
  .action((projectName, options) => {
    console.log(projectName, options)
    inquirer
      .prompt([
        {
          type: 'list',
          name: 'frameTemplate',
          message: '请选择框架类型',
          choices: ['Vue3', 'Vue2', 'React']
        }
      ])
      .then((answer) => {
        console.log(answer)
+       const spinner = ora()
+       spinner.text = '正在下载模板...'
+       spinner.start()
+       download(
+         '',
+         projectName,
+         { clone: true },
+         function (err) {
+           if (err) {
+             spinner.fail('模板下载失败')
+             errLog(err)
+           } else {
+             spinner.succeed('模板下载成功')
+             successLog('项目初始化完成')
+           }
+         }
+       )
      })
  })
program.version('1.0.0').parse(process.argv)

在控制台输入

 mycli create test -r

可以看到模板下载成功

如果下载不成功,请详细查看download-git-repo的文档:download-git-repo - npm

至此,我们已经实现了一个简单的模板仓库下载功能。更多的功能大家可以自行尝试。

6. 项目优化

如果我们有多个命令,那么我们就需要写多个

program
  .command("")
  .description("")
  .alias("")
  .option("")
  .action(() => {
    // 命令处理
  });
  1. 因为这部分代码被重复使用,我们自然而然想到了遍历,首先声明一个 list 变量用来维护我们的命令配置,在 src 新建 command-config.js 文件,该文件导出配置
const COMMAND_LIST = [
  {
    command: "create <projectName>",
    description: "create a new project",
    alias: "c",
    options:  ['-u, --umi', 'umi react template'],
      ['-v, --vite', 'vite react template'],
      ['-w, --webpack', 'webpack react template'],,
    action: require("./commandHandler/create"),
    examples: ['-u', '--umi', '-v', '--vite', '-w, --webpack'].map((v) => `create projectName ${v}`),
  },
];

module.exports = COMMAND_LIST;

修改bin/cli.js

/**
 * 注册option
 * @param {Object} commander commander实例
 * @param {Object} option 每个命令配置对象
 * @returns commander
 */
const registerOption = (commander, option) => {
  return option && option.length ? commander.option(...option) : commander;
};
/**
 * 注册action
 * @param {Object} commander commander实例
 * @param {Object} commandEle 每个命令配置对象
 * @returns commander
 */
const registerAction = (commander, commandEle) => {
  const { command, description, alias, options, action } = commandEle;
  const c = commander
    .command(command) // 命令的名称
    .description(description) // 命令的描述
    .alias(alias);
  // 循环options
  options && options.reduce(registerOption, c);
  c.action(action);
  return commander;
};

// 循环创建命令
COMMAND_LIST.reduce(registerAction, program);
  1. 由于命令处理部分代码量较大,所以我们考虑把命令处理的函数提取在一个文件夹下,我们在 src 下新建 commandHandler 目录,并新建一个 create.js,把 create 命令的处理代码放进 create.js

  2. 为了更方便使用,我们改写 mycli --help 命令

// help命令 把example显示出去
const help = () => {
  console.log("\n");
  console.log(chalk.green("如何使用:"));
  COMMAND_LIST.forEach((command, index) => {
    console.log(
      "  ",
      chalk.keyword("orange")(index + 1),
      `${command.command}命令`
    );
    command.examples.forEach((example) => {
      console.log(`     - mycli ${example}`);
    });
  });
};

program.on("-h", help);
program.on("--help", help);
  1. 为了更方便使用,我们加入对 npx 的支持
{
  "name": "mycli-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "bin":{
     "mycli": "./bin/cli.js"
  },
  "scripts": {
+   "start": "./bin/cli.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

至此我们完成了一个简易版 cli 工具的开发,后续优化版本将会直接发布至 npm