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 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-front2

v1.0.1

Published

$ back

Readme

egg-node

$ back

Mock library for testing Egg applications, plugins and custom Egg frameworks with ease. egg-mock inherits all APIs from node_modules/mm, offering more flexibility.

Install

Usage

$ npm i react-front --save-dev

Create testcase Launch a mock server with mm.app

$ src/App

import logo from './logo.svg';
import './App.css';
import RootRouter from './router/index'
function App() {
  return (
    <div className="App">
      <RootRouter />
    </div>
  );
}

export default App;

Retrieve Agent instance through app.agent after mm.app started.

Using mm.cluster launch cluster server, you can use the same API as mm.app;

Test Application baseDir is optional that is process.cwd() by default.


$ src/index

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

ReactDOM.render(
  <>
    <App />
  </>,
  document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();


Test Framework

framework is optional, it's node_modules/egg by default.

$ src/router/routerconfig

### views
	*index
		1.home
			>home.js
		2.my
			>my.js
		3.people
			>people.js
		4.index
	*login
		1.login.js
	*registry
		1.registry.js

Test Plugin

If eggPlugin.name is defined in package.json, it's a plugin that will be loaded to plugin list automatically.

You can also test the plugin in different framework, e.g. test aliyun-egg and framework-b in one plugin.

If it's detected as an plugin, but you don't want it to be, you can use plugin = false.

options

*--framework egg web framework root path. *--baseDir application's root path, default to process.cwd(). *--port server port, default to 7001. *--workers worker process number, default to 1 worker at local mode. *--sticky start a sticky cluster server, default to false. *--typescript / --ts enable typescript support, default to false. Also support read from package.json's egg.typescript. *--declarations / --dts enable egg-ts-helper support, default to false. Also support read from package.json's egg.declarations. *--require will add to execArgv, support multiple. Also support read from package.json's egg.require debug Debug egg app with V8 Inspector Integration.

automatically detect the protocol, use the new inspector when the targeted runtime >=7.0.0 .

if running without VSCode or WebStorm, we will use inspector-proxy to proxy worker debug, so you don't need to worry about reload.

$  views//registry


import React, { Component } from 'react'
import {registry} from '../../api/api'
import {
    Form, Input,Tooltip,Icon, Radio, Cascader,Select, Row,Col,Checkbox,Button,AutoComplete,
} from 'antd';

const { Option } = Select;



class RegistrationForm extends React.Component {
    state = {
        confirmDirty: false,
    };

    handleSubmit = e => {
        e.preventDefault();
        this.props.form.validateFieldsAndScroll(async (err, values) => {
            if (!err) {
                console.log('Received values of form: ', values);
                let res = await registry(values);
                if(res.data.code == 0){
                    this.props.history.push('/login');
                }
            }
        });
    };
    validateToNextPassword = (rule, value, callback) => {
        const { form } = this.props;
        if (value && this.state.confirmDirty) {
            form.validateFields(['confirm'], { force: true });
        }
        callback();
    };
    render() {
        const { getFieldDecorator } = this.props.form;

        const formItemLayout = {
            labelCol: {
                xs: { span: 24 },
                sm: { span: 8 },
            },
            wrapperCol: {
                xs: { span: 24 },
                sm: { span: 16 },
            },
        };
        const tailFormItemLayout = {
            wrapperCol: {
                xs: {
                    span: 24,
                    offset: 0,
                },
                sm: {
                    span: 16,
                    offset: 8,
                },
            },
        };
        return (
            <Form {...formItemLayout} onSubmit={this.handleSubmit}>
                <Form.Item label="邮箱">
                    {getFieldDecorator('email', {
                        rules: [
                            {
                                type: 'email',
                                message: 'The input is not valid E-mail!',
                            },
                            {
                                required: true,
                                message: 'Please input your E-mail!',
                            },
                        ],
                    })(<Input />)}
                </Form.Item>
                <Form.Item label="密码" hasFeedback>
                    {getFieldDecorator('pwd', {
                        rules: [
                            {
                                required: true,
                                message: 'Please input your password!',
                            },
                            {
                                validator: this.validateToNextPassword,
                            },
                        ],
                    })(<Input.Password />)}
                </Form.Item>
                <Form.Item
                    label={
                        <span>
                            昵称&nbsp;
                <Tooltip title="What do you want others to call you?">
                                <Icon type="question-circle-o" />
                            </Tooltip>
                        </span>
                    }
                >
                    {getFieldDecorator('name', {
                        rules: [{ required: true, message: 'Please input your nickname!', whitespace: true }],
                    })(<Input />)}
                </Form.Item>

                <Form.Item label="电话">
                    {getFieldDecorator('phone', {
                        rules: [{ required: true, message: 'Please input your phone number!' }],
                    })(<Input style={{ width: '100%' }} />)}
                </Form.Item>

                <Form.Item label="性别">
                    {getFieldDecorator('sex')(
                        <Radio.Group>
                            <Radio value="1">男</Radio>
                            <Radio value="2">女</Radio>
                        </Radio.Group>,
                    )}
                </Form.Item>

                <Form.Item {...tailFormItemLayout}>
                    <Button type="primary" htmlType="submit">
                        注册
            </Button>
                </Form.Item>
            </Form>
        );
    }
}

const WrappedRegistrationForm = Form.create({ name: 'register' })(RegistrationForm);


export default WrappedRegistrationForm;

API

mm.app(options) Create a mock application.

mm.cluster(options) Create a mock cluster server, but you can't use API in application, you should test using supertest.

$ views//login

import React, { Component } from 'react'
import { Form, Icon, Input, Button, Checkbox } from 'antd';
import { login } from '../../api/api'
import { getCode, getUser } from '../../utils/oauth'
class NormalLoginForm extends React.Component {
    state = {
        captcha: '/getcaptcha'
    }
    handleSubmit = e => { //点击登录 账号登录
        e.preventDefault();
        this.props.form.validateFields(async (err, values) => {
            if (!err) {
                console.log('Received values of form: ', values);
                let res = await login(values);
                console.log(res)
                if (res.data.code == 0) {
                    //登录成功  1.存(token name avatar) 2.跳转
                    // localStorage.token = res.data.token;
                    localStorage.userInfo = JSON.stringify({
                        token: res.data.token,
                        name: res.data.name,
                        avatar: res.data.avatar
                    })
                    this.props.history.push('/index');
                }
            }
        });
    };
    handleClickImg = () => {
        this.setState({
            captcha: '/getcaptcha?_t=' + new Date().getTime()
        })
    }
    handleClickGitee = () => {
        getCode();
    }
    componentDidMount() {
        getUser((data, token) => { //第三方登录成功
            console.log(data, token);
            // localStorage.token = token;
            localStorage.userInfo = JSON.stringify({
                token,
                name: data.name,
                avatar: data.avatar_url
            })
            this.props.history.push('/index'); //登录成功,跳转到首页
        });
    }
    render() {
        const { getFieldDecorator } = this.props.form;
        const { captcha } = this.state;
        const formItemLayout = {
            labelCol: {
                xs: { span: 24 },
                sm: { span: 8 },
            },
            wrapperCol: {
                xs: { span: 24 },
                sm: { span: 16 },
            },
        };
        return (
            <Form {...formItemLayout} onSubmit={this.handleSubmit} className="login-form">
                <Form.Item label="用户名">
                    {getFieldDecorator('name', {
                        rules: [{ required: true, message: 'Please input your username!' }],
                    })(
                        <Input
                            prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
                            placeholder="Username"
                        />,
                    )}
                </Form.Item>
                <Form.Item label="密码">
                    {getFieldDecorator('pwd', {
                        rules: [{ required: true, message: 'Please input your Password!' }],
                    })(
                        <Input
                            prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />}
                            type="password"
                            placeholder="Password"
                        />,
                    )}
                </Form.Item>
                <Form.Item label="验证码">
                    {getFieldDecorator('captcha', {
                        rules: [{ required: true, message: 'Please input your Password!' }],
                    })(
                        <Input
                            prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />}
                            type="text"
                            placeholder="请输入验证码"
                        />,
                    )}
                </Form.Item>
                <Form.Item>
                    <img src={captcha} alt="" onClick={this.handleClickImg} />
                </Form.Item>
                <span onClick={this.handleClickGitee}>码云</span>
                <Form.Item>

                    <Button type="primary" htmlType="submit" className="login-form-button">
                        登录
                    </Button>
                    Or <a href="/registry">注册</a>
                </Form.Item>
            </Form>
        );
    }
}

const WrappedNormalLoginForm = Form.create({ name: 'normal_login' })(NormalLoginForm);



export default WrappedNormalLoginForm;

You can disable coverage, because it's slow.


$ views/index//index

  import React, { Component } from 'react'
import RouterView from '../../router/routerview'
import { Layout, Menu, Breadcrumb, Icon, Avatar, Popover } from 'antd';
import { NavLink } from 'react-router-dom'
const { SubMenu } = Menu;
const { Header, Content, Sider } = Layout;
export default class Index extends Component {
    state = {
        name: localStorage.userInfo ? JSON.parse(localStorage.userInfo).name : '',
        avatar: localStorage.userInfo ? JSON.parse(localStorage.userInfo).avatar : ''
    }
    handleClickExit = () => {
        //1.清空本地数据  2.跳转登录
        localStorage.clear();
        this.props.history.push('/login');
    }
    render() {
        const { child } = this.props;
        const { name, avatar } = this.state;
        return (
            <div>
                <Layout>
                    <Header className="header">
                        <h3>1903A</h3>
                        <div>
                            <span>姓名:{name}</span>
                            <Popover content={<div>
                                <p onClick={() => this.props.history.push('/index/people')}>个人中心</p>
                                <p onClick={this.handleClickExit}>退出</p>
                            </div>}>
                                <Avatar src={avatar} />

                            </Popover>
                        </div>
                    </Header>
                    <Layout>
                        <Sider width={200} style={{ background: '#fff' }}>
                            <Menu
                                mode="inline"
                                defaultSelectedKeys={['1']}
                                defaultOpenKeys={['sub1']}
                                style={{ height: '100%', borderRight: 0 }}
                            >
                                <Menu.Item key="1">
                                    <NavLink to="/index/home">首页</NavLink>
                                </Menu.Item>
                                <Menu.Item key="2">
                                    <NavLink to="/index/my">知识小册</NavLink>
                                </Menu.Item>
                                <Menu.Item key="3">
                                    <NavLink to="/index/people">个人中心</NavLink>
                                </Menu.Item>
                            </Menu>
                        </Sider>
                        <Layout style={{ padding: '0 24px 24px' }}>
                            <Breadcrumb style={{ margin: '16px 0' }}>
                                <Breadcrumb.Item>Home</Breadcrumb.Item>
                                <Breadcrumb.Item>List</Breadcrumb.Item>
                                <Breadcrumb.Item>App</Breadcrumb.Item>
                            </Breadcrumb>
                            <Content
                                style={{
                                    background: '#fff',
                                    padding: 24,
                                    margin: 0,
                                    minHeight: 280,
                                }}
                            >
                                <RouterView routes={child} />
                            </Content>
                        </Layout>
                    </Layout>
                </Layout>

            </div>
        )
    }
}

mm.env(env) Mock env when starting


$ views//my

import React, { Component } from 'react'
import { Button, Modal, Form, Input, Upload, message, Icon, Popconfirm, Card, Col, Row, Pagination } from 'antd'
import { addlist, getlist, editlist, dellist } from '../../../api/api'
const { Meta } = Card;
class My extends Component {
    state = {
        visible: false,
        name: '',
        content: '',
        url: '',
        id: null,
        page: 1,
        pageSize: 10,
        total: 0, //总条数
        list: [], //列表
        search: '',//搜索
    }
    componentDidMount() {
        this.getinit();
    }
    async getinit() {
        const { page, pageSize, search } = this.state;
        let res = await getlist({
            page,
            pageSize,
            search
        });
        if (res.data.code == 0) {
            this.setState({
                list: res.data.data,
                total: res.data.total
            })
        }
    }
    showModal = () => {
        this.setState({
            visible: true,
        });
    };

    handleOk = async e => {
        console.log(e);
        let { name, content, url, id } = this.state;
        console.log(name, content, url);
        //调添加的接口
        let res = id ? await editlist({
            name,
            content,
            url,
            id
        }) : await addlist({
            name,
            content,
            url
        });
        if (res.data.code == 0) {
            this.setState({
                visible: false,
                name: '',
                content: '',
                url: '',
                id: null
            },
                () => {
                    this.getinit();
                });
        }

    };

    handleCancel = e => {
        console.log(e);
        this.setState({
            visible: false,
        });
    };
    handleSubmit = e => {
        e.preventDefault();

    };
    handleInput = (e) => {
        this.setState({
            [e.target.name]: e.target.value
        })
    }
    onShowSizeChange = (current, pageSize) => { //页码发生变化的时候或者pageSize发生变化的时候触发的事件
        console.log(current, pageSize, '********');
        this.setState({
            page: current,
            pageSize
        }, () => { //更新数据
            this.getinit();
        })
    }
    handleSearch = () => {
        // let {search} = this.state;
        this.setState({
            page: 1
        }, () => {
            this.getinit(); //更新数据
        })
    }
    handleEdit = (item) => {
        //点击编辑
        console.log(item);
        //1.显示弹框 2,回显数据
        this.setState({
            visible: true,
            name: item.name,
            content: item.content,
            url: item.url,
            id: item.id
        })
    }
    handleDel = async (id) => {

    }
    confirm = async (id) => { //点击确定删除
        console.log(id);
        let res = await dellist({ id });
        if (res.data.code == 0) {
            this.getinit(); //更新数据
            message.success('Click on Yes');
        }
    }

    cancel = (e) => {
        console.log(e);
        message.error('Click on No');
    }
    render() {
        const { name, content, url, list, total, page, search } = this.state;
        const formItemLayout = {
            labelCol: { span: 6 },
            wrapperCol: { span: 14 },
        };
        const props = {
            name: 'file',
            action: '/upload',
            headers: {
                token: localStorage.userInfo ? JSON.parse(localStorage.userInfo).token : '',
            },
            onChange: (info) => {
                if (info.file.status !== 'uploading') {
                    console.log(info.file, info.fileList);
                }
                if (info.file.status === 'done') { //上传成功
                    console.log(info, 'info')
                    this.setState({
                        url: info.file.response.url
                    })
                    message.success(`${info.file.name} file uploaded successfully`);
                } else if (info.file.status === 'error') {
                    message.error(`${info.file.name} file upload failed.`);
                }
            },
        };
        return (
            <div>
                <Input placeholder="请输入搜索的名字" value={search} name="search" onChange={this.handleInput} />
                <Button onClick={this.handleSearch}>搜索</Button>
                <Button onClick={this.showModal}>新增</Button>
                <Modal
                    title="Basic Modal"
                    visible={this.state.visible}
                    onOk={this.handleOk}
                    onCancel={this.handleCancel}
                >
                    <Form {...formItemLayout} onSubmit={this.handleSubmit}>
                        <Form.Item label="名字">
                            <Input placeholder="请输入名字" value={name} name="name" onChange={this.handleInput}></Input>
                        </Form.Item>
                        <Form.Item label="描述">
                            <Input placeholder="请输入描述" value={content} name="content" onChange={this.handleInput}></Input>
                        </Form.Item>
                        <Form.Item label="图片">
                            {
                                url ? <img src={url} alt="" className="imgs" /> : null
                            }
                            <Upload {...props}>
                                <Button>
                                    <Icon type="upload" /> 上传
                                </Button>
                            </Upload>
                        </Form.Item>
                    </Form>
                </Modal>
                <div style={{ background: '#ECECEC', padding: '30px' }}>
                    <Row gutter={16}>
                        {
                            list && list.map(item => <Col key={item.id} span={8}>
                                <Card
                                    style={{ width: 300 }}
                                    cover={
                                        <img
                                            alt="example"
                                            src={item.url}
                                        />
                                    }
                                    actions={[
                                        <Icon type="setting" key="setting" />,
                                        <Icon type="edit" key="edit" onClick={() => this.handleEdit(item)} />,
                                        <Popconfirm
                                            title="确认要删除吗?"
                                            onConfirm={() => this.confirm(item.id)}
                                            onCancel={this.cancel}
                                            okText="Yes"
                                            cancelText="No"
                                        >
                                            <Icon type="delete" key="delete" />,
                                        </Popconfirm>
                                    ]}
                                >
                                    <Meta
                                        title={item.name}
                                        description={item.content}
                                    />
                                </Card>
                            </Col>)
                        }

                    </Row>
                </div>
                <Pagination
                    showSizeChanger
                    onChange={this.onShowSizeChange}
                    defaultCurrent={page}
                    total={total}
                />
            </div>
        )
    }
}


const WrappedDemo = Form.create({ name: 'validate_other' })(My);

export default WrappedDemo;

if process.env.NODE_DEBUG_OPTION is provided (WebStorm etc), will use it as debug options.

dev Start dev cluster on local env, it will start a master, an agent and a worker.

Command

All the commands support these specific v8 options

$ views//home

   import React, { Component } from 'react'
import { Upload, message, Button, Icon } from 'antd';
import { Document, Page, pdfjs } from 'react-pdf';
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.min.js`;
export default class Home extends Component {
    state = {
        url: '',
        pageNumber: 1,
        numPages: 1,
        flag: false
    }
    onDocumentLoadSuccess = ({ numPages }) => {
        this.setState({
            numPages
        })
    }
    handleClickPreview = () => {
        this.setState({
            flag: true
        })
    }
    handleChangePage =(num)=>{
        this.setState({
            pageNumber:num
        })
    }
    render() {
        const { numPages, pageNumber, url, flag } = this.state;
        const props = {
            name: 'file',
            action: '/upload',
            headers: {
                token: localStorage.userInfo ? JSON.parse(localStorage.userInfo).token : '',
            },
            onChange: (info) => {
                if (info.file.status !== 'uploading') {
                    console.log(info.file, info.fileList);
                }
                if (info.file.status === 'done') {
                    this.setState({
                        url: info.file.response.url
                    })
                    message.success(`${info.file.name} file uploaded successfully`);
                } else if (info.file.status === 'error') {
                    message.error(`${info.file.name} file upload failed.`);
                }
            },
        };

        return (
            <div>
                <Upload {...props}>
                    <Button>
                        <Icon type="upload" /> pdf上传
    </Button>
                </Upload>
                <button disabled={!this.state.url} onClick={this.handleClickPreview}>预览</button>
                {
                    flag ? <div>
                        <Document
                            file={url}
                            onLoadSuccess={this.onDocumentLoadSuccess}
                        >
                            <Page pageNumber={pageNumber} />
                        </Document>
                        <p>Page {pageNumber} of {numPages}</p>
                        <button onClick={()=> this.handleChangePage(pageNumber-1)}>上一页</button>
                        <button onClick={()=> this.handleChangePage(pageNumber+1)}>下一页</button>
                    </div> : null
                }
            </div>
        )
    }
}