Awesome
<h1 align="center"> <img alt="dogstack on a post-it note" src="http://i.imgur.com/vjfouxn.jpg" height="250" /> <br /> dogstack </h1> <h4 align="center"> :dog: :dog: :dog: a popular-choice grab-bag framework for teams working on production web apps </h4> <h6 align="center"> :cat: see also <a href='https://github.com/enspiral-root-systems/cat-stack'>catstack</a>, dogstack's smarter, slimmer, more cunning partner in crime </h6>features
- abstracts away the app plumbing that you don't want to write again, and let's you focus on features
- prescribes enough opinion to reduce friction for your team
- is omakase, modules are hand-picked by expert chefs to deliver a consistent taste throughout
- gives prescriptive opinions for how to structure production-scale apps
examples
- dogstack.netlify.com: dogstack-example deployed to netlify / heroku
documentation
cli usage
api server
starts api server
dog api
asset server
starts asset server
dog asset
db
Runs knex
command, with any arguments.
dog db
api usage
server.js
export configuration for the feathers
server
services
: an array of functions that will be run withserver.configure(service)
example:
// server.js
export default {
services: [
require('./agents/service')
require('./accounts/service'),
require('./authentication/service'),
require('./profiles/service'),
require('./relationships/service')
]
}
// agents/service.js
import feathersKnex from 'feathers-knex'
export default function () {
const app = this
const db = app.get('db')
const name = 'dogs'
const options = { Model: db, name }
app.use(name, feathersKnex(options))
app.service(name).hooks(hooks)
}
const hooks = {
before: {},
after: {},
error: {}
}
browser.js
dogstack exports a function createBrowserEntry
out of browser.js
with which to generate your dogstack client app. a dogstack app should have a file which calls this function with the required arguments, and which has it's name passed to entry
as part of the asset
config.
example:
const createBrowserEntry = require('dogstack/browser')
const Config = require('dogstack/config')
const config = Config()()
window.config = config
// other imports of files needed for browser entry argument, as outlined in sections below
createBrowserEntry({
config,
store,
style,
client,
root,
intl,
routes,
Layout
})
explanations and examples of the parts that must be passed to createBrowserEntry
:
config
a feathers-configuration compatible config object. Dogstack provides dogstack/config
as a wrapper around feathers-configuration to make this easy
example:
// config/default.js
module.exports = {
favicon: 'app/favicon.ico',
app: {
name: 'Dogstack Example'
},
api: {
port: 3001,
url: 'http://localhost:3001/',
},
asset: {
port: 3000,
entry: 'browser.js',
root: 'app/assets',
url: 'http://localhost:3000/'
}
store
an object with updater
and epic
properties:
updater
: a function of shapeaction => state => nextState
, combined from each topic usingredux-fp.concat
epic
: a function of shape(action$, store, { feathers }) => nextAction$
, combined from each topic usingcombineEpics
example:
// store.js
import updater from './updater'
import epic from './epic'
export default {
updater,
epic
}
style
an object with theme
and setup
properties:
theme
: object passsed to<FelaThemeProvider theme={theme} />
setup
: function of shape(renderer) => {}
example:
// style.js
export default {
theme: {
colorPrimary: 'green',
colorSecondary: 'blue'
},
setup: (renderer) => {
renderer.renderStatic(
{ fontFamily: 'Lato' },
'html,body,#app'
)
renderer.renderFont('Lato', [
'https://fonts.gstatic.com/s/lato/v11/qIIYRU-oROkIk8vfvxw6QvesZW2xOQ-xsNqO47m55DA.woff'
])
}
}
client
configuration for feathers
client, as an object with services
and config
properties:
services
: an array of functions that will be run withclient.configure(plugin)
apiUrl
: the url of the api server for the client to connect to (normally this can be extracted from yourconfig
)
example:
// client.js
export default {
services: [
authentication
],
config
}
root
a configuration object for the root React component with appNode
and styleNode
properties:
appNode
: query selector string or dom node to render app contentstyleNode
: query selector string or dom node to render app styles
example:
// root.js
export default {
appNode: '#app',
styleNode: '#app-styles',
}
routes
an array of React routes to be rendered as props into your top-level Layout
component
example:
// routes.js
export default [
{
name: 'home',
path: '/',
exact: true,
Component: Home,
selector: getIsNotAuthenticated,
navigation: {
title: 'app.home',
icon: 'fa fa-home'
}
},
{
name: 'dogs',
path: '/',
exact: true,
Component: UserIsAuthenticated(DogsContainer),
selector: getIsAuthenticated,
navigation: {
title: 'dogs.dogs',
selector: getIsAuthenticated,
icon: 'fa fa-paw'
}
},
{
name: 'dog',
path: '/d/:dogId',
Component: UserIsAuthenticated(DogContainer)
}
]
Layout
your top-level rendered React component, which accepts routes
as props
example:
transform.js
exported browserify transform to be plugged in to your app's package.json
- can be configured to whitelist particular config key / values to be available to the browser
example:
// package.json
...
"browserify": {
"transform": [
// other transforms
[
"dogstack/transform",
{
"config": {
"keys": [
"api",
"asset",
"authentication"
]
}
}
]
]
}
...