仲灏小栈 仲灏小栈
首页
大前端
后端&运维
其他技术
生活
关于我
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

仲灏

诚意, 正心, 格物, 致知
首页
大前端
后端&运维
其他技术
生活
关于我
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 《前端项目基础建设》
  • HTML&CSS

  • JavaScript&TypeScript

  • Node

    • nvm 使用
    • nvm 深度使用解析
    • pnpm 学习
    • pnpm 使用及问题处理
    • npm yarn pnpm命令对比
    • koa学习
    • restful api笔记
    • Egg.js 技巧
    • Sequelize 学习笔记
    • npm 使用记录
    • node 记错修复
    • npm 仓库
    • 安装npm的过程中发生了什么
    • 想用而找不到的 npm 插件
    • node全局脚本原理解析
      • dedent库
        • parse
        • npm本地包引用方法
        • 项目初始化
        • 创建package
        • 发布前的准备
        • 发布
    • 转-commander
    • 制作自己的npm包
    • lerna
    • lerna - Lerna an Nx
    • lerna - 功能点
    • lerna API参考
    • Egg.js 技巧 问题集合
    • Node+vue打造全栈资源分享网站
    • 脚手架核心流程开发
    • Untitled
  • 构建

  • Vue

  • React

  • 小程序

  • 跨端

  • Electron

  • WebGL&GIS

  • 浏览器

  • 面经

  • 其他

  • 大前端
  • Node
仲灏
2022-08-28
目录

node全局脚本原理解析

# 脚手架实现原理

# 为什么全局安装@vue/cli后会添加vue的命令?
npm install -g @vue/cli
1

查看vue实际文件路径

> which vue
/usr/local/bin/vue
1
2

bin目录下存放的是可执行文件

> cd /usr/local/bin
> ll
lrwxr-xr-x  1 song  admin    39B 12 28 21:48 vue -> ../lib/node_modules/@vue/cli/bin/vue.js
1
2
3

可以看到vue实际是一个软链接,指向:../lib/node_modules/@vue/cli/bin/vue.js

# 绑定管理在哪里指定的呢?

进入到@vue/cli安装目录

> cd /usr/local/lib/node_modules/@vue/cli
> ll
-rw-r--r--    1 song  admin   2.5K 12 28 21:48 package.json
1
2
3

在package.json中有一个bin的配置

 "bin": {
    "vue": "bin/vue.js"
  },
1
2
3

这里配置了安装完之后的软链接名称,以及指向的实际文件

# 全局安装@vue/cli时发生了什么?

npm install -g @vue/cli

  • 第一步:会把@vue/cli下载到node node_modules中
  • 第二步:下载成功后会解析package.json 中的 bin 配置,有这个配置就会创建一个软链接
# vue执行一个js文件,为什么可以执行它?
  • 执行vue命令时,系统会执行which vue在环境变量中找vue的注册并执行文件

    # 这两条命令执行是等价的
    > vue
    >/usr/local/bin/vue
    
    1
    2
    3
  • 执行的真实文件是vue对应的软链接:../lib/node_modules/@vue/cli/bin/vue.js

    直接执行一个xx.js执行不了的,vue.js又是怎么执行的呢?

    js文件需要一个解释器(node)来执行 vue.js源码第一行

    #!/usr/bin/env node
    
    1

    自己创建一个js文件,test.js中第一行加入此代码,通过 ./test.js也能直接执行。

    为什么能直接执行?

    这句话的意思是,告诉系统在环境变量中去找node命令,来执行此文件

    > /usr/bin/env node # 会将node命令执行起来,与直接执行node是一样的效果
    
    1

    所以./test.js等于 /usr/bin/env node test.js 等于 node test.js

    chmod 777 test.js 设置文件为可执行文件

    # 自定义一条命令

    思路:在环境变量中创建一个软链接,执行 test.js即可 (软链接可以嵌套) 在 /usr/local/bin下执行

    >  ln -s <路径>/test/index.js <name> #删除软链接 rm <name>
    
    1

# 脚手架的开发流程

  • 创建npm项目

  • 创建脚手架入口文件,最上方添加:

    #!/usr/bin/env node
    
    1
  • 配置package.json 添加bin属性

  • 编写脚手架代码

  • 将脚手架发布到npm

# 脚手架开发难点

  • 分包: 将复杂系统拆分成若干个模块

  • 命令注册:

    vue create
    vue add 
    vue invoke
    
    1
    2
    3
  • 参数解析

    vue command [options] <params>
    
    1

    options全称:--version、--help options简写: -V、-h

  • 帮助文档

  • 命令行交互

  • 日志打印

  • 命令行文字变色

  • 网络通信:HTTP/WebSocket

  • 文件处理 ....

理解npm link

  • npm link your-lib:将当前项目中 node_modules 下指定的库文件链接到 node全局node_modules下的库文件
  • npm link: 将当前项目链接到node全局node_modules中作为一个库文件,并解析bin配置创建可执行文件

理解npm unlink

  • npm unlink:将当前项目从node全局node_modules中移除
  • npm unlink your-li:将当前项目中的库文件依赖移除

# 创建一个脚手架

> mkdir cli-test # 创建一个文件夹
> npm init -y # 初始化
1
2

cli-test 目录: -- package.json -- bin

  • |-- inde.js

index.js 文件:

#!/usr/bin/env node
console.log('Hello cli')
1
2

package.json文件:

{
  ...
  "main": "index.js",
  "bin":  {
        "cli-test": "bin/index.js"
    }
}
1
2
3
4
5
6
7

将脚手架发布到npm

> npm login # 登录npm
> npm publish # 发布
1
2

在cli-test目录下,进行全局安装 npm install -g cli-test 就会建立一个软链接,方便进行本地调试, 通过npm link 也可。

# yargs入门

Yargs通过解析参数来帮助您构建脚手架的工具。

# 通过yargs创建一个最简单的脚手架工具

定义文件index.js

#!/usr/bin/env node

const yargs = require('yargs/yargs')
const { hideBin } = require('yargs/helpers')

const arg = hideBin(process.argv)
yargs(arg)
     .argv
1
2
3
4
5
6
7
8

执行

> ./index.js --help
选项:
  --help     显示帮助信息                                                 [布尔]
  --version  显示版本号                                                   [布尔]
1
2
3
4

# 严格模式: strict

yargs(arg)
    .strict()
    .argv
1
2
3

加入strict,如果有无法识别的参数,将会给出提示

# 用法提示: usage

yargs(arg)
    .usage('Usage: test [command] <options>')
    .strict()
    .argv
1
2
3
4

使用--help将会打印出使用信息

> ./index.js --help
test [command] <options>

选项:
  --help     显示帮助信息                                                 [布尔]
  --version  显示版本号
1
2
3
4
5
6

# 最少输入的command个数: demandCommand

yargs(arg)
    .usage('Usage: test [command] <options>')
    .demandCommand(1, '最少输入一个参数')
    .strict()
    .argv
1
2
3
4
5

# 设置command别名: alias

yargs(arg)
    .usage('Usage: test [command] <options>')
    .demandCommand(1, '最少输入一个参数')
    .strict()
    .alias('h', 'help') //-h 和  --help 效果一样
    .argv
1
2
3
4
5
6

# 设置输出内容的宽度: wrap

const cli = yargs(arg)
cli.usage('Usage: test [command] <options>')
    .demandCommand(1, '最少输入一个参数')
    .strict()
    .alias('h', 'help')
    .wrap(cli.terminalWidth()) // terminalWidth返回当前窗口的宽度
    .argv
1
2
3
4
5
6
7

# 设置结尾显示的内容: epilogue

cli.usage('Usage: test [command] <options>')
    .demandCommand(1, '最少输入一个参数')
    .strict()
    .alias('h', 'help')
    .wrap(cli.terminalWidth())
    .epilogue('结尾显示的话')
    .argv
1
2
3
4
5
6
7

# 为全局command添加选项: options

cli.usage('Usage: test [command] <options>')
    .alias('h', 'help')
    .options({
        debug: { // 添加的选项名
            type: 'boolean',
            describe: 'debug mode',
            alias: 'd'  // 别名
        }
    })
    .argv
// options('name', {}) 一个一个设置的用法
1
2
3
4
5
6
7
8
9
10
11

执行效果

> ./index.js -h
Usage: test [command] <options>

选项:
      --version  显示版本号                                               [布尔]
  -d, --debug    debug mode                                              [布尔]
  -h, --help     显示帮助信息                                             [布尔]
1
2
3
4
5
6
7

# 将选项分组: group

cli.usage('Usage: test [command] <options>')
    .alias('h', 'help')
    .options({
        debug: {
            type: 'boolean',
            describe: 'debug mode',
            alias: 'd'
        }
    })
    .group(['debug'], 'Dev Options:')
    .argv
1
2
3
4
5
6
7
8
9
10
11

执行效果

> ./index.js -h
Usage: test [command] <options>

Dev Options:
  -d, --debug  debug mode                                                [布尔]

选项:
      --version  显示版本号                                               [布尔]
  -h, --help     显示帮助信息                                             [布尔]
1
2
3
4
5
6
7
8
9

# 命令纠错提示:recommendCommands()

会根据当前输入的command去找最相似的进行提示

# 自定义错误信息: fail((err,msg) => {...})

# dedent库

去除每行顶部空格,方便多行字符串的输出

const dedent = require('dedent')
console.log(dedent`
    第一行,
    第二行
`)
// 将会订购显示输出
/**
第一行,
第二行
*/
1
2
3
4
5
6
7
8
9
10

# 自定义命令

官方示例

#!/usr/bin/env node
const yargs = require('yargs/yargs')
const { hideBin } = require('yargs/helpers')

yargs(hideBin(process.argv))
    .command(
        'serve [port]', // serve 脚手架后面输入的名,[port]定义的option
        'start the server', // 描述
        (yargs) => { //builder,在执行这个command之前做的事情
            yargs
                .positional('port', {
                    describe: 'port to bind on',
                    default: 5000
                })
        }, 
        (argv) => { // handler,执行comand 的行为
            if (argv.verbose) console.info(`start server on :${argv.port}`)
            serve(argv.port)
        }
    )
    .option('verbose', {
        alias: 'v',
        type: 'boolean',
        description: 'Run with verbose logging'
    })
    .argv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

自定义

cli.usage('Usage: test [command] <options>')
    .alias('h', 'help')
    .options({
        debug: {
            type: 'boolean',
            describe: 'debug mode',
            alias: 'd'
        }
    })
    .group(['debug'], 'Dev Options:')
    .command('init [name]', '初始化的命令', (yargs) => {
        yargs.option('name', {
            type: 'string',
            describe: 'init的option',
            alias: 'n'
        })
    }, (argv) => {
        console.log(argv)
    })
    .argv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

执行效果

> ./index.js init  
{ _: [ 'init' ], '$0': 'index.js' }

> ./index.js init -h 
ndex.js init [name]

初始化的命令

Dev Options:
  -d, --debug  debug mode                                                 [布尔]

选项:
      --version  显示版本号                                               [布尔]
  -n, --name     init的option                                           [字符串]
  -h, --help     显示帮助信息                                             [布尔]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

使用对象方式定义

    ...
    .command({
        command: 'list',
        aliases: ['ls', 'la', 'll'],
        describe: 'list 的描述',
        builder: (yargs) => {

        },
        handler: (argv) => {
            console.log(argv)
        }
    })
    .argv
1
2
3
4
5
6
7
8
9
10
11
12
13
# parse

解析命令参数,合并传入的参数,合并完作为一个新的参数注入到脚手架中

#!/usr/bin/env node

const yargs = require('yargs/yargs')
const pkg = require('../package.json')

const argv = process.argv.splice(2)
const context = {
    testVersion: pkg.version
}

yargs()
    .command({
        command: 'list',
        aliases: ['ls', 'la', 'll'],
        describe: 'list 的描述',
        builder: (yargs) => {},
        handler: (argv) => {
            console.log(argv)
        }
    })
    .parse(argv, context)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

执行效果

> ./index.js list
{ _: [ 'list' ], testVersion: '1.0.5', '$0': 'index.js' }
1
2

# Lerna初始化过程

img

# npm本地包引用方法

除了npm link 还可以通过file:

@lerna/global-options:"file:../global-options"
1

# Lerna创建发布流程

# 项目初始化

> mkdir my-cli-dev # 创建项目文件
> npm init -y # 在项目目录下初始化
> npm i -g lerna # 全局安装lerna
> lerna init # 初始化
1
2
3
4

# 创建package

> lerna create core # package name 为 @my-cli-dev/core
> lerna create utils # package name 为 @my-cli-dev/utils
1
2

package.json中name为@my-cli-dev/core这种方式,my-cli-dev则为组织名称,需要在npm上创建一个对应的组织,可以避免名字的重复。若包发布不上去检查下这个组织是否已经建立。 core/package.json 中dependencies 添加@my-cli-dev/utils的依赖。 通过lerna link链接到本地库

# 发布前的准备

1、创建git仓库

> git remote add origin https://xx/cli.git # 添加仓库的链接
# 代码提交到仓库
> git add .
> git commit -m 'init' 
> git push origin master --set-upstream
1
2
3
4
5

2、需要npm login 3、根目录下添加LICENSE.md文件 4、package.json中添加publishConfig设置为公有库

# 发布

> lerna publish
1

错误问题

lerna ERR! E403 [no_perms] Private mode enable, only admin can publish this module
1

出现原因:使用的是淘宝源cnpm,登陆到的是cnpm 解决方法:切换到npmjs的网址,代码如下 npm config set registry http://registry.npmjs.org/ 切换过去之后记得npm login

上次更新: 2022/10/26, 16:57:52
想用而找不到的 npm 插件
转-commander

← 想用而找不到的 npm 插件 转-commander→

最近更新
01
vim日常使用记录
04-02
02
滑动窗口最大值
04-02
03
有效的字母异位词
04-02
更多文章>
Theme by Vdoing | Copyright © 2021-2025 izhaong | github | 蜀ICP备2021031194号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式