๐ฑ see also catstack, dogstack's smarter, slimmer, more cunning partner in crime
- 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
- dogstack.netlify.com: dogstack-example deployed to netlify / heroku
starts api server
dog api
starts asset server
dog asset
Runs knex
command, with any arguments.
dog db
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: {}
}
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
:
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/'
}
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
}
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'
])
}
}
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
}
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',
}
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)
}
]
your top-level rendered React component, which accepts routes
as props
example:
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"
]
}
}
]
]
}
...