/catstack

[ON HOLD] :cat2: :cat2: :cat2: A modular mad science framework for teams working on production web apps.

Primary LanguageJavaScript

catstack on a post-it note
catstack

🐈 🐈 🐈 A modular framework for teams working on production web apps.

stability npm version build status test coverage Downloads standard style
table of contents
  • features
  • demos
  • concepts
  • bin
  • api
  • install
  • inspiration
  • sponsored by Enspiral Root Systems

    inspired by ahdinosaur/mad-science-handbook

    for previous version, see catstack@1

    features

    • provides development architecture which linearly scales complexity as your app evolves.
    • provides prescriptive opinions to bootstap teams onto a consistent development platform across projects.
    • everything is a depject module that can be overridden or combined.
    • app file structure maps to app modules, making it easy to separate concerns and get things done.
    • provides full stack app server for both development and production.
    • consistent concepts across front and back end.

    demos

    concepts

    bin

    gen

    TODO

    generate new project

    catstack generate:project

    start

    dev

    starts development server

    catstack dev server

    server

    starts production server

    catstack server

    test

    runs pull-test tests

    can optionally take a glob

    npm run test -- './todos/**/*.test.js'

    default glob is ./**/*.test.js ignoring node_modules

    lint

    checks for standard style

    can optionally take a glob

    npm run lint -- './todos/**/*.js'

    default glob is ./**/*.js ignoring node_modules

    directory structure

    the catstack files are organized in the following hierarchy:

    ${topic} / ${type} / ${module}.js

    • config/
      • config/index.js
      • config/${ NODE_ENV }.js
    • ${ topic }/
    • tests are any files that end in .test.js

    topic overview

    in contrast to frameworks like Rails which split our app into directories for each "type" of file (models, views, controllers), our app is split into directories for each conceptual topic, where each topic contains the various types of files within that topic.

    each topic directory may contain any of:

    • state.js: exports initial store state
    • action/*.js: exports store actions
    • effect/*.js: exports effects
    • getter/*.js: exports reselect getters
    • page/*.js: exports routed views
    • element/*.js: exports presentation views
    • helper/*.js: exports helper functions
    • service.js: exports vas service

    ${ topic }/state.js

    // cats/state.js`
    module.exports = {
      create: () => ({
        init: () => ({
          model: {},
          effect: null
        })
      })
    }

    /${ topic }/action/*.js

    // cats/action/create.js
    module.exports = {
      create: () => ({
        update: (model, action) => {
          console.log('cat:create', model, action)
          return model
        }
      })
    }

    /${ topic }/effect/*.js

    // cats/effect/fetch.js
    module.exports = {
      create: () => ({
        run: (model, effect) => {
          console.log('cat:fetch', effect)
        }
      })
    }

    /${ topic }/get/*.js

    // cats/get/cats.js
    module.exports = {
      create: () => (state) => state.cats
    }

    /${ topic }/page/*.js

    // cats/page/show.js
    module.exports = {
      needs: {
        'app.layout.main': 'first',
        cats: {
          'element.profile': 'first',
          'get.show': 'first'
        }
      },
      create: (api) => ({
        route: '/cats/:catId',
        layout: api.layout.main,
        get: api.cats.get.show,
        view: api.cats.element.profile
      })
    }

    /${ topic }/element/*.js

    // cats/element/profile.js
    module.exports = {
      needs: {
        'inu.html': 'first'
      },
      create: (api) => ({
        view: (cat) => api.html`
          <div>${cat.name}</div>
        `
      })
    }

    /${ topic }/service.js

    // cats/service.js
    module.exports = {
      needs: {
        data: 'first'
      },
      manifest: {
        all: 'source',
        get: 'async'
      },
      create: function (api) {
        const cats = [{
          name: 'Fluffy'
        }, {
          name: 'Zoe'
        }]
    
        return {
          methods: { all, get }
        }
    
        function all () {
          return pull.values(cats)
        }
    
        function get (id, cb) {
          cb(null, data[id])
        }
      }
    })

    FAQ

    how do i do relations between models?

    implement them in your getters.js file as selectors.

    in the future, we should extract common relations into helper creators.

    license

    The Apache License

    Copyright © 2016-2017 Michael Williams

    Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0
    

    Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.