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

gzy-server

v1.0.1

Published

#### 初始化文件夹 ``` npm init -y ```

Downloads

2

Readme

模拟http-server 实现自己的一个服务工具

初始化文件夹

npm init -y

在package.json中添加

"bin":{
    "gzy-server":"./bin/www.js"
}

创建命令指定的目录及文件,并且制定运行环境

13.cli/bin/www.js

#! /usr/bin/env node

npm link 把当前这个包链接到npm中

// /Documents/webstorm/Project/blog/13.cli
npm link

安装commander命令行工具以及chalk粉笔工具

yarn add commander chalk --save

根据commander API 对你的工具设置个性化提示

ps:commander API

// 这个argv最后返回的就是一个对象,是根据你命令执行的后面的参数决定的
let argv = commander
    .version(version,'-v, --version') // 设置版本号
    .usage('[options] <gzy-server --port 3000>') // 用例设置
    .option('-p, --port <n>','server port')
    .option('-a, --address <n>', 'server address')
    .option('-d, --dir <n>', 'server show list')
    
    commander
    .command('log') // 这三个组成一个动作
    .option('--log','console.log')
    .action(function(){
        console.log('hello')
    })

    commander
    .on('--help', function(){
        console.log('')
        console.log('gzy-server:');
        console.log('  $ custom-help --help');
        console.log('  $ custom-help -h');
    })
    .parse(process.argv);

设置默认配置

// 如果执行命令传入了参数以参数为准
let config = Object.assign({
    dir:process.cwd(),
    address:'localhost',
    port:8080
},argv)

根据默认配置启动一个服务

// 写一个创建server的功能
let Server = require('../src/server.js')
let server = new Server(config); // 自己定义了一个启动服务的类
server.start(); // 定义了一个start方法,start()相当于http.createServer()

开始写Server类

定义实例上的属性
let tmplStr = fs.readFileSync(path.join(__dirname,'template.html'),
'utf8');
class Server {
    constructor(config) {
    this.port = config.port; // 端口号
    this.address = config.address; // eg:localhost
    this.dir = config.dir; // dir表示当前启动的目录 / 手动指定的
    this.tmpl = tmplStr; // 如果是目录的话渲染的template模版
  }
}
start (启动服务)
start() {
    let server = http.createServer(this.handleRequest());
    server.listen(this.port, this.address, () => {
      console.log(chalk.yellow(`Starting up http-server, serving ./
      Available on:`
      ));
      console.log(`  http://${this.address}:${chalk.green(this.port)}`)
    });
  }
handleRequest (处理请求)
    handleRequest() { // 处理请求的方法
        return async (req, res) => {
        // 需要判断当前请求的内容是文件还是文件
        let { pathname } = url.parse(req.url);
        pathname = decodeURI(pathname); // 文件名为汉字找不到
        if(pathname === '/favicon.ico') return this.sendError('找不到');
        let realPath = path.join(this.dir, pathname);
        try {
            let statObj = await fs.stat(realPath);
            if (statObj.isFile()) { // 文件操作
            this.sendFile(req, res, realPath, statObj);
            } else { // 目录操作
            let dirs = await fs.readdir(realPath);// ['www.js']
            // 渲染出一个渲染后的字符串
            // dirs应该包含 当前点击的链接 和显示的路径
            dirs = dirs.map((dir)=>{
                return {url:path.join(pathname,dir),dir}
            })
            let renderStr = ejs.render(this.tmpl, { dirs});
            res.setHeader('Content-Type','text/html;charset=utf8');
            res.end(renderStr);
            }
        } catch (e) {
            this.sendError(e,res);
        }
        }
    }
sendError (处理错误)
  sendError(e,res) {
    console.log(e);
    res.statusCode = 404;
    res.end(`Not found`);
  }
sendFile (处理文件)
  sendFile(req,res,path,statObj){
    // range (需要放到上面,先走分段)
    if(this.range(req,res,path,statObj)) return;

    // 先判断有没有缓存 有缓存 走缓存  boolean
    if (this.cache(req, res, path, statObj)){
      return res.statusCode = 304, res.end();
    }

    // gzip压缩 转化流
    // Accept-Encoding: gzip, deflate, br
    res.setHeader('Content-Type', mime.getType(path) + ';charset=utf-8');
    // 返回的文件需要压缩
    let zip;
    if (zip = this.gzip(req,res)){ // 调用方法后返回的是一个转化流
      return fs.createReadStream(path).pipe(zip).pipe(res);
    }
    fs.createReadStream(path).pipe(res);
  }
range (分段请求)
    range(req,res,path,statObj){
        let range = req.headers['range'];
        if(range){
            let [,start,end] = range.match(/(\d*)-(\d*)/);
            start = start ? Number(start):0;
            end = end ? Number(end):statObj.size;
            res.statusCode = 206;
            res.setHeader('Content-Range',`bytes=${start}-${end}/${statObj.size}`);
            res.setHeader('Content-Length',end-start+1);
            fs.createReadStream(path,{start,end}).pipe(res);
            return true;
        }else{
            return false
        }
    }
cache (缓存)
    cache(path,statObj,req,res){
        res.setHeader('Cache-Control','Max-Age=10');
        res.setHeader('Expries',new Date(Date.now()+10*1000).toLocaleString());
        let ctime = statObj.ctime.toLocaleString();
        let etag = ctime+'_'+statObj.size;
        res.setHeader('Last-Modified',ctime);
        res.setHeader('Etag',etag)

        let ifModifiedSince = req.headers['if-modified-since'];
        let ifNoneMatch = req.headers['if-none-match'];

        if(ifModifiedSince && ifNoneMatch ){
            if(ifModifiedSince === ctime && ifNoneMatch === etag){
                res.setHeader('Content-Encoding','gzip');
                return zlib.createGzip();
            }else{
                res.setHeader('Content-Encoding','gzip');
                return zlib.createDeflate();
            }
        }else{
            return false 
        }  

    }
gzip (压缩)
    gzip(req,res){
        let encoding = req.headers['accept-encoding'];
        if(encoding.includes('gzip')){
            res.setHeader('Content-Encoding','gzip');
            return zlib.createGzip();
        }   
        if(encoding.includes('deflate')){
            res.setHeader('Content-Encoding','deflate');
            return zlib.createDeflate();
        }
        return false;
    }

先切换到官方的源

nrm use npm

添加用户(没有的话是注册)

npm addUser

发布

npm publish