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 🙏

© 2025 – Pkg Stats / Ryan Hefner

anchundan

v2.0.7

Published

鹌鹑蛋框架

Downloads

12

Readme

鹌鹑蛋 🥚

使用方式 和 eggjs 类似
区别在于插件的设置,简化了插件的配置和使用。 进程管理交给 pm2 .管理 如果你具备一些eggjs ,koa ,的开发经验,以及对sequelize 有相对的了解,可以很轻松的看懂这个份readme 这个框架诞生的目的是为了简化初始化的过程,精简eggjs


npm install anchundan

or

yarn add anchundan

or 
yarn add https://github.com/shinku/anchundan

[toc]

项目初始化

anchundan-init

目录
├─ src
│ ├─ app
│ ├─ config
│ │ ├─ config.base.js
│ │ ├─ config.dev.js
│ │ ├─ config.pro.js
│ │ ├─ config.uat.js
│ ├─ middleware
│ ├─ modules
│ ├─ plugins
│ ├─ routers
│ │ ├─ index.js
│ ├─ static
│ ├─ controller
│ └─ index.js
├─ application.dev.config.js
├─ application.uat.config.js
├─ application.pro.config.js

启动应用:

yarn start
or
yarn start_uat
or
yarn start_prod

配置文件

/config/config.base.js

这个文件存储基本的配置信息。 其次,dev对应开发环境。uat 对应预发,pro对应 生产环境的配置 配置的相关过程跟eggjs类似。 application.{env}.config.js 对应的是pm2 启动项的配置

监听端口设置

/src/config/config.base.js

module.exports = {
  port:9000
}

新建 controller

//方式与eggjs 一致
/src/controller/index.js

const Controller = require('anchundan').Controller;
class Index extends Controller{
    async start(ctx){
        this.send("hello~",{
          "Content-Type":"text/plain"
        });    
    }
    
}
module.exports = Index;

同时 anchundan.Controller 内置了其他一些方法,方便某些场景的调用

  • [get/set] context 获取/设置 当前的上下文对象,context 是一个KOA 的context 对象。
    this.context.set("X-PATH",this.context.path);
  • send(content,option?)
    this.send("hello~")
  • [get] request 获取当前的request对象,post的场景下使用
    /// postdata  为 : {userid:"123"}
    let {userid} = this.request.body;
  • [get] query 获取当前的 query 对象,get 的场景下使用
     /// postdata  为 : {userid:"123"}
    let {userid} = this.query;
  • [get] params 路由格式类似为 /path/:id/:pagenum 使用
     /// postdata  为 : {userid:"123"}
    let {id,pagenum} = this.params;
  • [get] services 获取当前应用的所有service 组件时使用
    let userdata = this.services.userdata;
    let result = await userdata.find({where:{userid}});
  • [get] plugins 获取当前应用的所有application 插件

路由

//结合controller
/src/routers/index.js
module.exports = (router,app)=>{
    let {
        index,
    } = app.controllers;
    router.get(vpath+'/test',index.start);
    router.post(vpath+'/test',index.start);
}

路由增加中间件

const mid = async (ctx,next)=>{
  //do something
  await next();
}
module.exports = (router,app)=>{
    let {
        index,
    } = app.controllers;
    router.get(vpath+'/test',mid,index.start);
    router.post(vpath+'/test',mid,index.start);
}

中间件

  •  创建中间件
    /src/middleware/apiproxy.js
    module.exports =  (config,app)=>{
        return async (ctx,next)=>{
            //console.log("api proxy");
            //dosomething
            //这里可以使用 app 参数获取到 controllers,services,plugins
            let {index} = app.controllers;
            let {plugins,services} = app;
            //
            index.context = ctx;
            await index.start();
            await next();
        }
      }
  •  配置中间件 与eggjs 一致
    /src/config/config.base.js
    
    module.exports = {
      port:9000,
      middlewares:['apiproxy'],
      apiproxy:{
        abc:"test"
      }
    }

    插件

    • context 插件,挂载在context上下文

    • 插件可以是 一个Object 或者一个function

    • PS:如果想通过插件访问到 具体的 context 或者application 内部数据,定义函数插件的时候用 function(){}定义,而不() =>{}

      /src/plugins/sendresult/context.js
      //使用 function abc(){}  的方式新建函数,可以直接使用this 操作当前上下文
      //使用箭头函数无法操作,application 插件类似。
      module.exports =  function (result){
        this.body = result;
        this.set('Content-Type',"html/text");
      }
    
    • application 插件,挂载在application
      /src/plugins/getfile/application.js
      //使用 function abc(){}  的方式新建函数,可以直接使用this 操作当前上下文
      //使用箭头函数无法操作,application 插件类似。
      module.exports =  function (filepath){
        return fs.readFileSync(filepath);
      }
    
    • sample
      //方式与eggjs 一致
      /src/controller/index.js
    
      const Controller = require('anchundan').Controller;
      class Index extends Controller{
          async start(ctx){
              let file = this.app.plugins.getfile("/static/index.html");
              this.context.plugins.sendresult(file);
          }
            
      }
      module.exports = Index;

sequelize

anchundan 默认集成 sequelize,并在此基础上做了封装

  • 初始化sequelize 在配置文件中,配置sequelize 关键字
/src/config/config.base.js

let config  ={
  sequelize:{
      /** 基本配置*/
      host:"localhost",
      username:"root",
      password:"**********",
      database:'DATA_BASE',
      dialect:"mysql",
      port:'3306',
      /**其他配置 */
      options:{
          //开启连接池
          pool:{
              //开启10个连接池
              max: 10,
              idle: 30000
          }
      }
  }
}
module.exports = config;
  • 新建module
/src/modules/user.js
const { Sequelize, DataTypes, Model } = require('sequelize');
const SequelizeOperate = require('anchundan').Sequelize;
class users extends SequelizeOperate{
    init(){
        this.define('users',{
            id:{
                type:DataTypes.INTEGER,
                autoIncrement:true,
                primaryKey:true,
                allowNull: false,
                comment:"自增ID"
            },
            userid:{
                type:DataTypes.STRING(50),
                comment:"用户ID",
                allowNull: false,
            },
            pwd:{
                type:DataTypes.STRING(100),
                comment:"密码",
                allowNull: false,
            },
        },{
            comment:"是否有效",
            //增加索引
            indexes:[{
                unique:true,
                fields:['userid']
            }]
        });
        this.sync({force:false}).then(_res=>{})
    }
}
module.exports = users

该module 将以插件的形式挂载在application中,如下方式可直接使用,已封装了常规的sequelize 方法 find,count,update,query

// 在controller 中使用:
let userdatatable =  this.plugins.sequelize.DB.users;
let result = await userdatatable.find({where:{userid}});
result = await userdatatable.count({where:{userid}});
result = await userdatatable.query("select * from users");
  • module 结合services 使用
/src/services/users.js
const ADbService = require("anchundan").Services;
class users extends ADbService{
   constructor(app) {
      super(app);
      //绑定 users module
      this.tableName = 'users';
  }
  getInfo(userid,...params){
    return this.table.find({where:{userid}},...params)
  }
}
module.exports = users;

之后在controller 中使用services


let users = this.services.users;
let data = await users.getInfo(userid);

通过 service 操作数据的方式更加安全,也存在更好的可读性,并且可以集成除了操作数据库意外的其他方法。
通过 this.plugins.sequelize.DB[{MODULENAME}] 的方式直接操作sequelize对象,可以更加灵活的操作数据

数据库事务

以在controller中使用为例子

//假设建两个 module,users 和infos,需要通过数据库事务处理数据,并已经通过anchuandan.Services 实例做了绑定
let users =this.services.users;
let infos = this.service.infos;
let sequelize = this.plugins.sequelize.sequelize;
//以plugins.sequelize.sequelize; 获取数据库链接实例
let transaction = await  sequelize.transaction();
try{

  await users.addData({userid},{transaction});
  await infos.addData({userid},{transaction});
  //提交事务
  await transaction.commit();
  //something else
}
catch(e){
  //遇到报错,关闭事务
  await transaction.rollback();
}

跨域

在config 中配置cors属性

/src/config/config.dev.js
let base = require('./config.base')
let config = {
    ...base,
    port:9000,
    
    middlewares:['apiproxy']
    cors:{
        //允许你的域名,http和https需要分别设置
        origins:["http://test.local.com","https://www.anchundan.com"],
        //针对于headers中的:Access-Control-Allow-Headers 字段,已包含:Content-Type,Cookie,Content-Length, Authorization, Accept, X-Requested-With,如想设置允许所有的字段,则 headers为 ”*“,多过定向规定一些其他字段,则用逗号分割,例如:BIZ,Connection,
        headers:"",
        //针对于headers中的 Access-Control-Allow-Methods 字段,默认为 DELETE,PUT,POST,GET,OPTIONS,
        methods:"DELETE,PUT,POST,GET,OPTIONS",
        // 针对于headers中的 Access-Control-Allow-Credentials 字段,默认未空
        credentials:true,

    }
}
module.exports  = config;

启动其他应用

全局的application 中可以捆绑其他服务,比如性能的监听,socket服务等。


src/app/start/ {newapp}.js

module.exports = (application)=>{
    //console.log(application);
    let {config,server} = application;
    //获取到了当前应用的 config 和 koa 应用
    //server 为koa的一个实例,可以直接用server.use(XXX)的方式增加一个新的中间件,但不建议这么处理,
    //中间件的使用方式按照框架约定的方式处理最为安全
    
}

全局错误捕获

全局的报错由 processunhandledRejectionuncaughtException 捕获,并由config.js 配置 handleUncaughtExceptionhandleUncaughtException 配合业务做报错处理

../config.base.js
const config = {

    ....,
   handleUncaughtException:(app,error)=>{
        
        
        //全局未捕获的报错
        //app 为当前application 实例,可以在此调用 applicaation 的插件,例如注册的 log 插件,以下类似
        // app.plugins.logger().info('xxxxx');
    },
    handleUnhandledRejection:(app,error)=>{
       //app 为当前application 实例,可以在此调用 app 的插件。
        //全局未处理的Promise 的rejection 的报错处理
    }
}

增加扩展

// 首先安装扩展
app.addExtension({
  controllers:path.join(__dirname,'./controllers'),
  middlewares:path.join(__dirname,'./middlewares'),
  services:path.join(__dirname,'./services'),
  plugins:path.join(__dirname,'./plugins'),
})
// 启动app
app.startApp();

宏函数

  • getAppPlugins (): Object< string, Object | Function > 获取全局的app 插件

  • getAppPluginByName( pluginname ): Object | Function 根据插件名字获取插件内容

  • getAppConfig(): Object <string, any> 获取当前的应用配置信息

  • getControllers(): Object <string, anchuandan.Controller> 获取所有挂载的Controller字典

  • getServices() : Object <string, anchuandan.Service> 获取所有挂载的Service