在npm上发布自己的包 全局包指令使用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在npm上发布自己的包 全局包指令使用相关的知识,希望对你有一定的参考价值。

  看着公司的另外一个同事写了一个静态资源服务器进行打包后的预览, 但是个人觉得他定义的指令实在是太长, 每次都得打一大串, 个人实在受不了. 于是做了个梦, 再梦里自己就写了这么一个东西, 第二天正好公司空闲没啥事干就开始琢磨着去写.

  需要准备的: node, npm账号, github仓库, 足够的耐性

  开干 : 

  1.声明npm package.json

npm init

  2.随后键入package基本信息

name:  vsv  // 模块名称
version: (1.0.0) 1.0.1 // 基础版本号
description: 描述 // 模块描述
entry point: (index.js) index.js // 默认入口
test command: none // 测试指令
git repository: https://github.com/vok123....  // 个人git仓库地址
keywords: server // 关键字
author: vok // 作者
license: (ISC) 

最后输入 y 完成package.json编辑, 随后会生成一个package.json文件

  3.在目录下新建lib文件夹和readme.md并往里面塞点说明

  4.在lib下面新建lib.js

  

module.exports = { // 暴露模块
   fun: function () {
       console.log(‘我的第一个测试包‘);
   }     
};    

  5.在跟目录新建index.js 

  

var lib = require( ‘./lib/lib.js‘ );
module.exports = lib; //暴露模块

  6.注册npm账号:

    方法1:  npm 注册账号

    方法2: npm adduser 依次输入用户名, 密码, 邮箱就注册成功了, 注册成功会自动登录

    注意: (注意当前镜像源, 如果不是原版镜像源的需要求换原镜像源 , 可以使用 nrm 进行管理镜像源) 1.安装npm install -g nrm 2. 查看镜像源 nrm ls 3. 切换 nrm use npm

      如果有npm账号

    npm login  输入用户名, 密码, 邮箱

  7. 发布

    npm publish

  8. 使用包

npm installl --save vsv

  新建test.js

var funs = require(‘vsv‘);
funs.fun(); // 调用我们定义模块的方法

  当然这仅仅是应用的模块, 貌似并不是我想要的结果 , 我想要的vsv -p 8989就启动一个静态资源服务进行浏览呢! 这时候会想到是否把这个包全局安装 npm install -g vsv 就可以使用呢? 显然不行 , 光是解决vsv不是一个指令就是一个大问题, 还有定义的端口号也是一个问题. 接下来我们一步步来解决问题.

  首先我要借助 commander 命令行来解决指令问题

npm install --save commander //这里需要使用--save 进行安装 不然下面require(‘commander‘)会找不到模块

  把根目录新建src目录新建一个没有后缀的 vsv 文件并键入代码

const program = require(‘commander‘);

program
    .version(require(‘../package‘).version) // 设置版本
    .option(‘-p, --port [port]‘, ‘Input port !‘) // 自定义形参[port]
    .parse(process.argv); // 参数数组

console.log(program.port); // 使用自定义的port参数

  然后我们可以发布npm试试了 执行指令 

npm publish

  发布完成后

npm install -g vsv

  安装完成后执行  vsv -p 8999 却发现报错了 (找不到指令)

  ‘vsv‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。

  这时候需要我们在package.json里面配置 bin 节点 (跟 "scripts"同级)

  "lib": {

    "vsv": ‘./src/vsv‘

  }

  保存后修改package.json下version节点的版本号为1.0.1, 每次发布的时候要求版本号都要比上一个大

  然后 npm publish 进行npm包发布

  发布完成后npm install -g vsv 再次安装

  执行指令 vsv -p 8999

  发现还是报了错 (指令错误)

  ‘"C:\Users\Administrator\AppData\Roaming\npm\\node_modules\vsv\src\vsv"‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。

  到这步的时候离成功已经不远了, 证明我们输入vsv 指令的时候能够找到对应的需要执行的文件了. 只差执行所编写的代码了, 代码是js 所以应该指定这个指令由node去执行.

  这时候我们需要告诉这个文件需要用node执行 , 在vsv文件的头部加上 #!/usr/bin/env node

#!/usr/bin/env node

const program = require(‘commander‘);

program
    .version(require(‘../package‘).version) // 设置版本
    .option(‘-p, --port [port]‘, ‘Input port !‘) // 自定义形参[port]
    .parse(process.argv); // 参数数组

console.log(program.port); // 使用自定义的port参数

  再次更改package.json的版本号进行发布, 安装

  在次执行vsv -p 8999

  发现这时候终于输出了 8999

  接下来就是配置打开浏览器和启动静态资源服务器了

  打开浏览器使用 open 这个npm包  npm install --save open 以及控制台颜色colors控制 npm install --save colors

  

// 使用自定义的port参数以及默认端口处理
  #!/usr/bin/env node

  const program = require(‘commander‘),
  main = require(‘../lib/main.js‘),
  open = require(‘open‘),
  colors = require(‘colors‘);

  program
    .version(require(‘../package‘).version)
    .usage(‘[entry]‘)
    .option(‘-p, --port [port]‘, ‘Input port !‘)
    .parse(process.argv);

  var ports = (program.port > 0 && program.port != true) ? program.port : 8080;
  // 监测端口是否被占用
  main.checkPort(ports).then(res => {
    main.createServer(ports);
    open(`http://localhost:${ports}`);
  }).catch((err) => {
    console.log(err);
  });

 

  新增/lib/main.js处理端口检查以及静态资源处理服务

const net = require(‘net‘),
  colors = require(‘colors‘),
  fs = require(‘fs‘),
  url = require(‘url‘),
  mime = require(‘./mime‘),
  config = require(‘./config‘),
  http = require(‘http‘),
  path = require(‘path‘);

module.exports = {
  checkPort (port) { // 监测端口
    return new Promise((resolve, reject) => {
      let server = net.createServer().listen(port);
      server.on(‘listening‘, () => { // 执行这块代码说明端口未被占用
        server.close();
        resolve(true, port);
      });
      server.on(‘error‘, (err) => {
        if (err.code === ‘EADDRINUSE‘) { // 端口已经被使用
          console.log(`${port}端口已经被占用 !`.underline.red);
          reject();
        }
      });
    });
  },
  createServer (port) { // 创建静态资源服务
    http.createServer((req, res) => {
      let pathName = url.parse(req.url).pathname;  // 获取文件名‘/xxx‘
      // 对中文进行解码,防止乱码
      pathName = decodeURI(pathName);

      // 重定向: 考虑定义标准的url,以‘/‘结尾.
      if (path.extname(pathName) === ‘‘) {  // 没有扩展名
        if (pathName.charAt(pathName.length - 1) !== ‘/‘) {
          pathName += ‘/‘;
          let redirect = encodeURI(‘http://‘ + req.headers.host + pathName); // 记得encodeURI,不然中文目录报错
          res.writeHead(301, {
            location: redirect
          });
        }
      }
      // 获取资源的绝对路径
      let realFilePath = path.resolve(process.cwd() + pathName);
      // 获取对应文件的文档类型
      let ext = path.extname(pathName); // 获取后缀名,如‘.html
      ext = ext ? ext.slice(1) : ‘notKnow‘;  // 取掉.符号
      if (ext.match(config.Expires.fileMatch)) {
        let expires = new Date();
        expires.setTime(expires.getTime() + config.Expires.maxAge * 1000);
        // 设置响应头
        res.setHeader(‘Expires‘, expires.toUTCString());
        res.setHeader(‘Cache-Control‘, ‘max-age=‘ + config.Expires.maxAge);
      }
      // 定义未知文档的类型MIME
      let contentType = mime[ext] || ‘text/plain‘; // 后缀名存在就进行映射,不存在就是‘text/plain‘
      // 判断文件是否存在
      fs.stat(realFilePath, (err, stats) => {
        // err
        if (err) {
          // 也可以定制自己的404页面
          res.writeHead(404, { ‘content-type‘: ‘text/html‘ });
          res.end(‘<h3>404 Not Found</h3>‘);
        }
        if (!stats) return;
        // 存在
        if (stats.isFile()) {
          res.writeHead(200, { ‘content-type‘: contentType });
          // 开始读取文件
          let stream = fs.createReadStream(realFilePath, {
            encoding: ‘utf8‘
          });
          // 读取时候错误处理
          stream.on(‘error‘, () => {
            res.writeHead(500, { ‘content-type‘: contentType });
          });
          // 返回文件内容
          stream.pipe(res);
        }
        // 路径是目录的情况,列出当前目录下文件
        if (stats.isDirectory()) {
          let html = ‘<head><meta charset="utf-8"></head>‘;
          // 读写该目录下的内容 files是文件数组
          fs.readdir(realFilePath, (err, files) => {
            if (err) {
              console.log(‘目录文件读取失败‘.red);
            } else {
              let tpath = ‘‘;
              for (let i = 0; i < files.length; i++) {
                tpath = realFilePath.replace(process.cwd(), ‘‘);
                // html += ‘<div><a href=‘‘+ tpath + ‘/‘ + files[i] + ‘‘>‘ + files[i] + ‘</a></div>‘;
                html += `<div><a href=‘${tpath}/${files[i]}‘>${files[i]}</a></div>`;
              }
            }
            res.writeHead(200, { ‘content-type‘: ‘text/html‘ });
            res.end(html);
          });
        }
      });
    }).listen(port, () => {
      console.log(`开启服务成功 >>>>> 端口: ${port}`.blue);
    });
  }
}

如果文章对你有帮助的话请留下你的足迹 , 拒绝做伸手党  ^_^ ~

代码 github

以上是关于在npm上发布自己的包 全局包指令使用的主要内容,如果未能解决你的问题,请参考以下文章

Ubuntu上使用npm命令全局安装的包所在的路径

npm中全局安装和本地安装的区别

npm全局安装

详细了解如何在npm上发布自己的包?

详细了解如何在npm上发布自己的包?

npm简单运用