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

你可能感兴趣的:(KeystoneJS 源码分析(1))