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

@limejs/core

v0.4.5

Published

lime framework

Downloads

49

Readme

npm version downloads Build Status License

LIME

lime.js 是一个轻量的基于 Koa2 的 Node.js Web开发框架,它基于经典的 MVC 范式,致力于提供简单易用的 Web 应用开发体验。

Feature

  • 内核简单、优雅, 易上手

    lime.js 可以无缝衔接 Koa 和 npm 的现有生态;在灵活与标准之间,lime 以 中庸 的态度做出权衡,并不断面向用户体验和未来而演进

  • 经典 MVC 范式,约定大于配置

    采用最经典的分层架构、约定大于配置的设计理念

  • 可扩展性强, 功能完备

    尽管保持了小而精致的内核,但通过插件机制和社区生态打造的脚手架, lime 完全可以胜任复杂项目的开发

  • 面向未来的架构和工具链

    对于服务器端而言,升级运行环境的成本要比客户端小的多。也正因如此,lime.js 会毫不客气的废弃对老版本 Node.js 的支持。lime 会用面向未来的态度随时进化

Guide

只要你熟悉 Node.js 基本语法并了解 Koa 框架中的基本概念(如中间件),即可 3 秒钟快速上手 lime.js 框架

下面,我们通过简单的 3 个步骤,开启 LIME.JS 的 Web 开发之旅

  1. 创建项目并安装 lime.js
  # 创建一个项目目录 lime-demo
  mkdir lime-demo
  cd lime-demo
  # 初始化 package.json
  npm init -y
  # 安装 lime.js 核心作为项目依赖
  npm install @limejs/core --save
  1. 创建 LIME 框架运行所需的项目结构
  # 创建一系列目录和文件
  mkdir -p config plugin mvc/controller mvc/view mvc/model
  touch mvc/router.js mvc/controller/home.js
  touch app.js

  # 此时 目录结构如下所示
  |-config # 站点配置,本示例不涉及
  |-plugins # 站点插件,本示例不涉及
  |-src
    |-controller
      |-home.js # 一个叫做 Home首页 的 控制器
    |-view
      |-home.hbs
    |-model
    |-router.js # 站点路由
  |-app.js # 站点应用入口
  |-package.json
  1. 分别对 app.js、router.js、home.js 编写代码。内容如下:
  // router.js 中定义路由
  module.exports = (router) => {
    router.get('/', 'home@index')
  }

  // home.js 中定义index首页请求的逻辑
  module.exports = {
    async index() {
      this.ctx.body = 'hello lime' // 通过 this.ctx 可以访问到 Koa 上下文对象
    }
  }

  // app.js 中引入 lime 框架内核并启动
  const Lime = require('@limejs/core')
  const app = new Lime()
  app.listen()

控制器代码中的 index 函数叫做控制器的 action,它本质上是一个完全意义上的 Koa 中间件函数,该函数所传入的 ctx 和 next 参数分别表示 Koa 的 ctx 上下文对象以及下一个中间件函数。

如果一切顺利,此时打开浏览器访问 http://localhost:3000 便可以看到

hello lime! # 看到它 说明已经运行成功

Boileplate

尽管创建一个基于 LIME 框架的项目如此简单,但事实上要开发一个生产环境的站点还需要大量其他的能力,例如使用模板引擎进行视图渲染、使用mongoose进行数据存取、打印日志等等;而LIME内核通过灵活的插件机制让你可以通过插拔插件的方式,应对复杂的Web应用开发。只要你引入对应的LIME插件,LIME就可以变得无所不能。

我们知道选择插件组装应用是一件纠结的事情,所以事实上你无须自己手工创建项目样板。LIME 官方提供了一坨开箱即用的项目样板供您享用。无论是开发 Rest API 项目,还是基于 Vue.js 的前后端分离项目,还是传统的MVC模式的站点,LIME 都有一套完备且易用的样板。目前有以下这些样板项目:

  • MVC 这是传统的 MVC 开发模式的项目样板,包含完整的MVC模块,服务端通过模板引擎来渲染视图。[立刻启动一个传统MVC模式的开发](https://github.com/limejs/lime-template-standard)
  • SPA 基于 Lime+Vue 的前后端分离的项目样板,兼顾单页应用运行和API开发。通过 lime 框架作为中间层来托管 Vue 资源文件,并在 limejs 中通过 webpack-dev-middleware 等插件完成Vue的热加载和热替换。[立刻启动一个用 Node.js 作为中间层的SPA项目](https://github.com/limejs/lime-template-spa)
  • SSR Lime+VueSSR 服务端同构渲染的项目样板,适合面向消费者、对首屏加载性能和SEO有一定要求的站点;同样实现了热加载热替换、异常处理、cookie处理、api开发等。[立刻启动一个用 Node.js 作为中间层的同构VueSSR项目](https://github.com/limejs/lime-template-spa)
  • API API 项目样板,去除了 model层、view层,增加了services层,适合开发REST API项目。

通过 lime-cli 初始化时进行交互选择,您可以轻松创建一个 Web 应用样板来开发复杂应用;当然你也无需担心 cli 工具蒙蔽了你的双眼,事实上它仅仅是帮你引入了合适的 LIME 插件而已,内部发生的一切都很容易理解。了解更多的话你需要去参考对应项目样板的 README,当然继续读完本文档对你上手开发总是有益的。

Convention

LIME 是 约定大于配置 的,所以 LIME 内部有一些惯例(约定),我们在这里做简要说明。

  • 站点目录结构必须符合规范
|-- config
  |-- site.js 站点配置文件
|-plugins
  |- ua.js 一个插件
|-- src
  |-- router.js 路由
  |-- controllers 控制器
  |-- models 模型
  |-- views 视图
|-- app.js 站点启动入口
|-- package.json

你无法通过配置文件来修改 LIME 所要求的目录结构。如确有必要的话,可通过 Lime 构造函数的参数来配置(但不建议这么做),如:

const app = new Lime({
  root: __dirname,
  config: path.join(__dirname, './myconfig') // 修改默认配置文件的目录
})
  • 控制器的物理文件名就是 controller 的名字

假如我们要创建一个 新闻 的控制器 news,并在控制器中提供一个获取 新闻列表list 函数。那么,我们应该创建一个 mvc/controller/news.js 的文件,并在 news.js 中这样编写一个控制器对象:

const NewsController = {
  // 返回新闻列表
  async list(ctx, next) {
    ctx.body = []
  }
  // 返回一个新闻详情
  async detail(ctx, next) {
    let id = ctx.query.id
    // ...
    ctx.body = {}
  }
}

module.exports = NewsController

这样,news 就是控制器的名字,list 就是 action 的名字。在路由中,可以通过 news@list 映射到这个新闻列表函数。

  • 路由

路由的约定是: 路由行为用@符号来分割 controller 和 action

举个栗子: 我们希望客户端发送的 http://domain.com/news 请求可以返回上面的 新闻列表,也就是说要把 /news 路径的 get 请求交给 news controllerlist action 来处理。那么我们应该这样编写路由:

module.exports = (router) => {
  router.get('/', 'news@list')
}

这里 router 对象的所有 API 都可以参考 koa-router 来使用。

Router

Lime 的默认使用 src/router.js 进行路由规则配置,Lime 的路由在底层基于 koa-router 实现。支持如下实例方法:

router.get|put|post|patch|delete|del ⇒ Router
router.routes ⇒ function
router.use([path], middleware) ⇒ Router
router.prefix(prefix) ⇒ Router
router.allowedMethods([options]) ⇒ function
router.redirect(source, destination, [code]) ⇒ Router
router.route(name) ⇒ Layer | false
router.url(name, params, [options]) ⇒ String | Error
router.param(param, middleware) ⇒ Router

Config

config目录中存放 LIME 的框架基础配置,其中有四个配置文件,分别影响不同环境的配置:

common.js 公共配置,即各个环境都会使用的配置
dev.js 开发环境配置
test.js 测试环境配置
prod.js 生产环境配置

配置的覆盖规则是这样的: common配置是最底层的配置,如果特定环境里面指定了相同的配置项导致冲突,则优先使用 环境配置文件 里所指定的配置。

LIME中的最终配置不仅会指导 LIME内核的行为,同时你也可以在业务开发过程中通过 ctx.config 获取到这个配置对象,从而可以基于配置进行相关业务逻辑的开发。

可配置的参数字段有:

module.exports = {
  env: process.env.NODE_ENV, // env变量用于指导内核如何输出调试信息。支持 development、test、production三种字符串。建议您在业务开发过程中也使用 ctx.config.env 获取该变量,这样便与内核保持相同的环境判断方法。
  port: process.env.PORT || 3000, // 监听端口。你可以根据自己实际业务逻辑进行修改
  host: process.env.HOST || '127.0.0.1', // 监听地址
  publicPath: '/', // 站点的域名访问目录,默认是`/`表示站点运行在根path下。如果你要将本项目运行在 `www.baidu.com/bbs` 这样的目录下,你需要将此处配置为 `/bbs`
  plugins: [
    'logger', // 插件名称标识符
    'plugin-lime-cors',
    // 也可以用一个对象来表示一个插件
    {
      name: 'session',
      options: {
        key: 'abc'
      }
    }
  ]
}

插件配置在下文 Plugin 一节详细解释

Plugin

LIME 通过插件的机制来扩展框架的能力。通过编写插件,可以实现:

  • 挂载 global 对象上的辅助函数。例如全局的looger函数: global.logger()
  • 在请求生命周期中注入Koa原生的中间件
  • 扩展 MVC 模块中的方法,例如在controller中注入一个 this.http 的方法用来发起http请求

为了更你能编写出更优雅的插件,有必要在这里解释下 Lime 初始化时注册插件的过程:

  • Lime 首先会按顺序收集站点 config 配置中指定的 plugins 字段中所有插件
  • 接下来,Lime 会按照插件顺序依次执行各个插件的 global函数,再依次执行所有插件的 install 函数,再依次执行各个插件的 middleware 函数,以此类推到 controller、view、model。

这个机制对编写 middleware 类型的插件会有影响,因为很多中间件对执行顺序有要求,所以你可以通过配置插件的顺序来影响中间件的执行顺序。

下面,我们来编写一个插件,插件的编写简直不要太简单,一个 plugin 插件就是一个 JavaScript 文件,插件的基本框架如下所示:

module.exports = function(options) {
  global(g) {
    // 在这里往 global 对象上挂载方法;因为global函数会在 Lime 生命周期的最开始执行挂载,因此可以确保你在
  },
  install(app, context) {
    // 在这里修改 Koa 的 app 和 context 对象原型
  },
  middleware(app) {
    // 在这里通过 app.use() 注入中间件
  },
  controller(proto) {
    // 在这里扩展 控制器 的能力
  },
  model(proto) {
    // 在这里扩展 模型能力
  },
  view(proto) {
    // 在这里扩展 视图能力
  }
}

这里的middleware字段所注入的中间件 实际上就是 Koa 的原生中间件,因此我们可以复用 npm 仓库中数以万计的中间件模块。

举个栗子,我们以编写一个 logger 插件为例:

const logger = require('koa-logger') // 引入一个 Koa2 原生中间件
module.exports = function(options) {
  middleware(app) {
    // 在这里使用 Koa 中间件语法把 logger 中间件注入到 lime 框架中
    app.use(logger)
  }
}

编写完成之后,我们把该文件命名为 logger.js 放置到项目根目录的 plugins 目录下:

|- src
|- plugins
  |- logger.js

当你的插件比较复杂(有多个文件时),也可以以目录的形式组织起来,命名为目录放置在 plugins 目录下:

|- src
|- plugins
  |- logger
    |- index.js
    |- dep.js

不过要注意确保 logger/index.js 正确导出 lime 所要求的插件对象。

插件代码编写完成后,需要配置才能启用。我们去项目根目录的 config 目录下,在 common.js 公共配置中的 plugins 字段加入该插件:

module.exports = {
  // plugins是个数组,依次填写插件名称或插件对象
  plugins: [
    'logger'
  ]
}

注意: 通常情况下,Koa 的一些中间件是有顺序要求的。例如 koa-logger 中间件的官方建议:

Recommended that you .use() this middleware near the top to "wrap" all subsequent middleware.

而 limejs 框架是依靠你在 plugins 字段上配置的前后顺序来依次加载的。因此,在 common.js 的配置中你要注意把 logger 插件放置在靠前的位置就好了。

使用 npm 模块插件

有些插件是其他人开发好,并且发布到 npm 仓库的,此时你不需要把插件下载到自己项目中。你只需要安装它:

npm install @limejs/plugin-cors

然后在插件配置中这样指定上插件的npm包名

module.exports = {
  // plugins是个数组,依次填写插件名称或插件对象
  plugins: [
    '@limejs/plugin-cors'
  ]
}

Lime 注册插件的机制是: 优先寻找本项目 plugins 目录下的同名插件,如果无法找到,则寻找 node_modules 下的同名插件。如果都找不到,则抛出错误。

插件配置选项

在 config 中配置插件时,除了使用字符串的形式指定插件名称,还可以使用对象形式。对象形式可以允许你给插件传入 options 选项参数

例如,我们使用 koa-csrf 中间件来编写一个 Lime 插件:

// 插件名称: lime-csrf
const CSRF = require('koa-csrf')
module.exports = function (options){
  middleware(app) {
    // 把 options 传入 koa-csrf 构造器
    app.use(new CSRF(options))
  }
}

那么,在使用该插件时,便可以在配置中加入选项配置:

// common.js
module.exports = {
  plugins: [
    {
      name: 'lime-csrf',
      options: {
        invalidTokenMessage: '非法的token',
        invalidTokenStatusCode: 403
      }
    }
  ]
}

API

[Class] Lime

Lime 构造函数可以支持传入选项,以控制框架的初始化逻辑:

const app = new Lime({
  root: __dirname, // 站点的项目目录
  config: '', // 站点配置文件目录
  mvc: '', // 站点 mvc 代码放置目录
  plugin: '', // LIME 插件 的放置目录
})

默认情况下,LIME 使用当前的 工作目录 (process.cwd) 作为站点的根目录,同时站点的配置、路由、控制器路径也都是基于 root 的位置进行解析的. 因此,如果你的工作目录不在站点根目录下,或者你需要修改默认目录的位置,可在初始化时通过 Lime 构造函数选项来修改

对于使用 pm2、supervisor 等工具启动的 LIME 站点,我们建议你设置 root 参数为 __dirname (即当前站点项目的根目录), 以减少你错误配置 pm2、supervisor 的工作目录带来的问题。

[Instance] app

Lime 的实例在 plugin 中经常碰到,lime 实例有以下属性和方法

  • [prop] options 初始化 Lime 所用的选项配置
  • [prop] config 基于站点配置文件site.js的站点信息
  • [method] global 注入一个中间件处理函数. 该方法代理自 Koa

[Global] global

Lime 除了核心类和实例方法之外,为了方便用户可以随时随地调用,还侵入性的在 Node.js global 对象添加了少量的辅助函数。他们有:

  • [method] logger.[warn|ok|error|info](<msg>) 打印不同级别的信息到输出流(一般用来主动记录日志)

Misc

环境变量说明

  • DEBUG=lime:* 打开lime框架内核的调试日志;你也可以选择性地打开 lime:store, lime:controller, lime:router 等模块的调试日志
  • PORT: http server 监听的端口号
  • HOST: http server 监听的 host 地址

集成到已有的服务

除了前文讲到的通过 app.listen 来启动 LIME 服务,LIME 也可以单纯作为一个 http 处理器来用。这适用于把 LIME 集成到已有的 Node.js http 服务中(如腾讯公司的 tsw)。

集成方式非常简单,只需把 app.callback() 的返回值作为 http 请求的 handler 处理器即可。示例:

// your server code
const http = require('http')
const Lime = require('@limejs/core')
const app = new Lime()
http.createServer(app.callback()).listen(8080)

CONTRIBUTE

欢迎帮助 LIME 进化和修复 issue,您可遵循 CONTRIBUTE 规范来参与开发。

todo任务分为 内核、工具、生态、插件,这是我们的 TODO 列表:

  • [内核] 插件支持配置和options
  • [内核] 优化启动方式,启动的port和host改成从配置文件获取,减轻启动时代码复杂度
  • [内核] 路由、插件解析报错的处理
  • [内核] 异常处理优化
  • [内核] 内置插件移除 转为limejs/plugin-x 的npm包
  • [生态] 更多脚手架模板完善
  • [内核] view、model、service层完善
  • [内核] 支持 global 挂载
  • [工具] PM2 和 nginx 配置
  • [内核] host,port,publicPath,env 配置支持
  • [工具] docker支持
  • [插件] redis,mongoose插件
  • [内核] 利用app.onerror 实现优雅的让用户定制500 404页面。
  • [内核] 加载插件时,对于需要绑定this的函数,检测其是否使用了箭头函数(无法绑定this),有的话则提醒并退出

CHANGELOG

LIME 正在不断进化迭代中,你可以在 这里 查看版本变更细节

License

MIT License