sponsored by Enspiral Root Systems
inspired by ahdinosaur/mad-science-handbook
for previous version, see catstack@1
- 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.
- catstack.herokuapp.com: this repo's ./example deployed to heroku
TODO
generate new project
catstack generate:project
starts development server
catstack dev server
starts production server
catstack server
runs pull-test
tests
can optionally take a glob
npm run test -- './todos/**/*.test.js'
default glob is ./**/*.test.js
ignoring node_modules
checks for standard style
can optionally take a glob
npm run lint -- './todos/**/*.js'
default glob is ./**/*.js
ignoring node_modules
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
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 stateaction/*.js
: exports store actionseffect/*.js
: exports effectsgetter/*.js
: exportsreselect
getterspage/*.js
: exports routed viewselement/*.js
: exports presentation viewshelper/*.js
: exports helper functionsservice.js
: exportsvas
service
// cats/state.js`
module.exports = {
create: () => ({
init: () => ({
model: {},
effect: null
})
})
}
// cats/action/create.js
module.exports = {
create: () => ({
update: (model, action) => {
console.log('cat:create', model, action)
return model
}
})
}
// cats/effect/fetch.js
module.exports = {
create: () => ({
run: (model, effect) => {
console.log('cat:fetch', effect)
}
})
}
// cats/get/cats.js
module.exports = {
create: () => (state) => state.cats
}
// 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
})
}
// cats/element/profile.js
module.exports = {
needs: {
'inu.html': 'first'
},
create: (api) => ({
view: (cat) => api.html`
<div>${cat.name}</div>
`
})
}
// 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])
}
}
})
implement them in your getters.js
file as selectors.
in the future, we should extract common relations into helper creators.
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.