Node 自定义命令执行过程及实现

2,078 阅读5分钟

一、前言

对于 Node,我并不熟悉,但搭建的项目确是在 Node 环境下(后面会去具体学习)的。

目前比较火的前端框架便是 VueReact 了,在使用这些框架时,心理是有疑惑的,为什么输入官方给的 命令后,便可以在本地搭建一个相应的项目?昨日在看 Vue3.x, 使用 Vite 工具后,觉得自己需要把这些给理一理了。

1.1 Vue3.x

# npm
npm init vite-app my-app
# yarn
yarn create vite-app my-app

1.2 React

# npx
npx create-react-app my-app
# npm
npm init react-app my-app
# yarn
yarn create react-app my-app

(后来知道,这是 脚手架。输入的命令会被执行,并根据预定的模板生成项目的骨架)

1.3 在终端输入该命令 npm init vite-app my-app

PS F:\vue3.x\vite> npm init vite-app my-app
npx: 7 安装成功,用时 2.678 秒
Scaffolding project in F:\vue3.x\vite\my-app...

Done. Now run:

  cd my-app
  npm install (or `yarn`)
  npm run dev (or `yarn dev`)

PS F:\vue3.x\vite> 

1.4 如有上面的打印结构,便是执行成功,再看目录,多了 my-app 目录,且有如下文件夹结构

my-app
├── public
│   ├── favicon.ico
├── src
│   ├── assets
│   ├── ├──logo.ong
│   ├── components
│   ├── ├──HelloWorldd.vue
│   ├── App.vue
│   ├── index.css
│   ├── main.js
├── .gitignore
├── index.html
└── package.json

1.5 那么这行命令 npm init vite-app my-app 做了什么?

从结果上来看,以当前目录为基创建 my-app 子目录,并在该目录下生成了一个如上的目录结构

首先,npm init 进行初始化,生成文件 package.json

npm init vite-app my-app 会被拆成两步

  • npm 补全模块名 vite-app -> create-vite-app
  • npx create-vite-app my-app

npmnpx 又是什么呢?(参考 zhuanlan.zhihu.com/p/45151808)

  • npm 全称是 Node Package Manager,Node 包管理器
    • 允许用户从NPM服务器下载别人编写的第三方包到本地使用
    • 允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用。
    • 允许用户将自己编写的包或命令行程序上传到NPM服务器供别人使用。
  • npx 根据脚手架应运而生
    • 脚手架也是一个 npm 包,若想使用其定义的命令,需要先全局安装
    • 如果没有 npx,使用脚手架会被分成两步
      • npm install -g create-vite-app
      • create-vite-app my-app
    • npx 将两步合一,简化了脚手架的使用
      • npx create-vite-app my-app
    • npx 不仅将两步合一,还可以临时安装脚手架包,并在执行完脚手架命令后删除该包,以避免全局污染

二、create-vite-app 命令是如何定义的?

我到 npm,搜索 create-vite-app, 并没有找到(???)

既然是开源的项目,我又到 github 上找到该项目并且下载到本地

2021-07-24_134746.png

package.json 文件中有个 bin 字段(该字段定义了命令 create-vite-app,并指明了入口 index.js)

{
    ...
    "bin": {
        "create-vite-app": "index.js",
        ...
    }
    ...
}

index.js,根据模板生成相应的目录结构

#!/usr/bin/env node
const path = require('path')
const fs = require('fs-extra')
const argv = require('minimist')(process.argv.slice(2))

async function init() {
  // 根据模板生相应的目录结构
  ......
}

init().catch((e) => {
  console.error(e)
})

三、实现自定义 Node 命令 sugar

新建一个目录并进入, 执行 npm init 生成 package.json 文件

  • package.json 文件中定义 bin 字段

    "bin": {
        "sugar": "bin/sugar.js"
    }
    
  • 创建文件 bin/sugar.js

    #!/usr/bin/env node
    
    // 具体操作
    console.log('custom command --- sugar');
    
  • 如果此刻,直接执行 sugar,会报如下错误

    PS F:\vue3.x\vite\npx> sugar
    sugar : 无法将“sugar”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。
    所在位置 行:1 字符: 1
    + sugar
    + ~~~~~
        + FullyQualifiedErrorId : CommandNotFoundException
    
    PS F:\vue3.x\vite\npx>
    

    说明该命令还没有被链接到对应的运行项目中,需要先执行 npm link

  • 执行命令 npm link,将命令链入全局

    PS F:\vue3.x\vite\npx> npm link
    npm WARN custom_command@1.0.0 No repository field.
    
    npm ERR! code ENOENT
    npm ERR! syscall chmod
    npm ERR! path C:\Users\LUSHUIXI\AppData\Roaming\npm\node_modules\custom_command\bin\sugar.js
    npm ERR! errno -4058
    npm ERR! enoent ENOENT: no such file or directory, chmod 'C:\Users\LUSHUIXI\AppData\Roaming\npm\node_modules\custom_command\bin\sugar.js'
    npm ERR! enoent This is related to npm not being able to find a file.
    npm ERR! enoent
    
    npm ERR! A complete log of this run can be found in:
    npm ERR!     C:\Users\LUSHUIXI\AppData\Roaming\npm-cache\_logs\2021-07-24T06_46_39_717Z-debug.log
    PS F:\vue3.x\vite\npx>   
    

    2021-07-24_144542.png

  • 再执行命令 sugar

    PS F:\vue3.x\vite\npx> sugar   
    custom command --- sugar
    PS F:\vue3.x\vite\npx> 
    

四、commander

也可以通过 commander 模块来制作命令会交互

commander 制作命令行交互,据说是 node.js 命令行界面的完整解决方案,受 Ruby Commander 启发。

4.1 安装

npm install commander

4.2 定义

#!/usr/bin/env node

const Commander = require('commander');

/**
 * 自定义命令 sugar start
 * 简写 sugar st
 */
Commander
    .command('start')
    .alias('st')
    .description('自定义命令 sugar start---------')
    .action(function() {
        console.log('custom command --- sugar st');
    })
    .parse();

4.3 使用

PS F:\vue3.x\vite\npx> sugar start
custom command --- sugar st
custom command --- sugar
PS F:\vue3.x\vite\npx> 

五、总结

Node环境下,自定义命令执行过程及实现,后面在搭建脚手架的时候有更多的实践。主要分为两步:

  • package.json 文件定义 bin 字段,其格式为键值对(键是命令名称,值是命令执行的入口文件),例如: "bin": {"sugar": "sugar.js"}

  • 创建并编写命令执行的入口文件,例如:sugar.js

5.1 亲测本地开发自定义命令、发包

本地开发一项目 custom-command-lsx(已发布到 npm, 地址),定义了一个命令 sugar123,代码已存储到 GitHub

亲测, 在其他同事安装该包后是否可以直接使用该命令的问题

  • 全局安装(npm i custom-command-lsx -g),可直接使用;
  • 非全局安装(npm i custom-command-lsx),需要 npm link 链入全局后方可使用(这块可以去看下Node终端命令解析路径);

如果有什么理解的不到位的,还请各位读者指摘~

好好学习,天天向上~