🐱 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 apistarts asset server
dog assetRuns knex command, with any arguments.
dog dbexport 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.concatepic: 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"
]
}
}
]
]
}
...