KeystoneJS 源码分析(1)

KeystoneJS 是一个优秀的并且非常有个性的 Node CMS,数据库使用 MongoDB,而手头的一个项目,因为主要数据库便是 MongoDB,结合当时的需求,评估后采用了 KeystoneJS 作为运营后台的基础。在较短的时间内,达到了不错的应用效果,满足了初期的各项业务迭代需求。

应用过程中,感受到 KeystoneJS 的文档算是优秀,但作为一个快速发展的开源项目,文档中有些缺失也在所难免,并且文档偏重于纯使用,若有更多改造的需求,分析源码便是个必修课。

为了更好的满足后续的业务改进需求,便计划分析下 KeystoneJS 的源码,也希望从中学习优秀框架的设计思想。


一. 沿调用栈(纵向)分析

1. 调用示例

  • keystone.js

    keystone.import('models')
    ...
    keystone.start()
    
  • models/Project.js

    var Project = new keystone.List('Project', {
        schema: { collection: 't_project' },
        label: '项目',
    })
    
    Project.add({
      name: { type: String, required: true, label: '项目名称'},
      pv: { type: Number, label: 'PV' }
    })
    
    ...
    Project.register()
    

2. keystone 源码中的核心类型

List

  • lib/list.js

    module.exports = function (keystone) {
      function List (key, options) {
        var defaultOptions = { 
          schema: {
                    collection: keystone.prefixModel(key),
                },
                ...
        };
        ...
        this.options = utils.options(defaultOptions, options)
        ...
        this.schema = new keystone.mongoose.Schema({}, this.options.schema);
        ...
      }
      
      ...
      // 笔记:依赖到 mongo Schema
          Object.defineProperty(this, 'nameIsVirtual', { 
            get: function () {
                return this.model.schema.virtuals[this.mappings.name] ? true : false
            } 
          })
      ...
      
      List.prototype.add = require('./list/add')
      ...
      List.prototype.field = require('./list/field')
      ...
      return List
    }
    
  • lib/list/add.js

    function add () {
      var add = function(obj, prefix) {
        ...
        var keys = Object.keys(obj)
        for(...keys) {
          // 笔记:addField(path, fieldOptions)
          addField(prefix + key, obj[key])
        }
      }
        
      var addField = function (path, options) {
        ...
        this.uiElements.push({
          type: 'field',
          field: this.field(path, options)
        })
      }.bind(this)
      
      var args = Array.prototype.slice.call(arguments)
      ...
      
      _forEach(args, function (def) {
        
        ...
        add(def);
      }
    }
    

Field (belongs to List)

  • lib/list/field.js

    function field (path, options) {
      ...
      if (options.type === String) {
        options.type = Field.Types.Number
      }
      ...
      
      // 笔记:new Field(list, path, options)
      var field = new options.type(this, path, options)
      ...
      return field
    }
    
    module.exports = field
    

Field Type

  • fields/types/number/NumberType.js

    var FieldType = require('../Type');
    ...
    
    function number (list, path, options) {
      this._nativeType = Number
      ...
    }
    
    util.inherits(number, FieldType)
    
  • fields/types/Type.js

    function Field (list, path, options) {
      ...
      this.addToSchema(this.list.schema)
      ...
    }
    
    ...
    
    Field.prototype.addToSchema = function (schema) {
      var ops = (this._nativeType) ? _.defaults({ type: this._nativeType }, this.options) : this.options;
      // 笔记:listSchema.path(field.path, field.options)
      schema.path(this.path, ops)
      ...
    }
    

二. 沿搜索(横向)分析

1. 关键词 schema.

  • 依赖 schema 的属性/方法
    • add()
    • path()
    • nested[]
    • virtual()
    • pre()
    • methods
    • paths[]
    • statics
    • collection
    • url
    • mimetype
    • size
  • 依赖 schema 的模块
    • List
      • list.js
      • list/add.js
      • list/buildSearchTextIndex.js
      • list/declaresTextIndex.js
      • list/expandColumns.js
      • list/register.js
    • 一些非基本 Field 类型的 field type, 如 NameType, PasswordType, SelectType, RelationType
    • 一些高级 Field 类型, 如 LocalFilesType, LocationType, MarkdownType
    • schemaPlugins
      • autokey
      • history
      • sortable
      • track
    • lib/storage.js

2. 关键词 query.{ $(query 相关)

  • fields/types/number/NumberType.js
  • lib/core/createItem.js
  • lib/list/addSearchToQuery.js
  • lib/list/apiForGet.js
  • lib/list/pageinate.js
  • lib/middleware/api.js
  • lib/schemaPlugins/methods/getRelated.js
  • lib/view.js
  • fidleds/types/*Type.js
  • lib/list/addFiltersToQuery.js
  • lib/list/getSearchFilter.js

.exec

  • lib/core/createItems.js
  • lib/list/apiForGet.js
  • lib/list/getUniqueValue.js
  • lib/list/paginate.js
  • lib/list/updateItem.js
  • lib/schemaPlugins/autokey.js
  • lib/schemaPlugins/methods/getRelated.js
  • lib/schemaPlugins/sortable.js
  • lib/session.js
  • lib/view.js
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,930评论 1 332
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,642评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,928评论 0 225
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,639评论 0 193
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,806评论 3 272
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,698评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,139评论 2 293
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,864评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,485评论 0 230
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,955评论 2 233
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,355评论 1 243
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,811评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,300评论 3 221
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,840评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,464评论 0 181
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,577评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,628评论 2 249

推荐阅读更多精彩内容