Skip to content

Commit fd0a21f

Browse files
authored
v2 better state-management and routing (#30)
1 parent 0275eb8 commit fd0a21f

30 files changed

+9538
-434
lines changed

.circleci/config.yml

+2
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,6 @@ jobs:
3333
- node_modules
3434
key: v1-dependencies-{{ checksum "package.json" }}
3535

36+
- run: npm run lint
37+
3638
- run: npm test

.eslintrc.yml

-46
This file was deleted.

README.md

+59-89
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,16 @@ Here are the different package that make Tram-One possible...
4848

4949
For Rendering:
5050
- [hyperx](https://github.com/substack/hyperx)
51-
- [bel](https://github.com/shama/bel)
51+
- [bel-create-element](https://github.com/JRJurman/bel-create-element)
5252
- [rbel](https://github.com/aaaristo/rbel)
53+
- [nanomorph](https://github.com/choojs/nanomorph)
5354

5455
For Routing:
55-
- [nanorouter](https://github.com/choojs/nanorouter)
56+
- [rlite](https://github.com/chrisdavies/rlite)
5657
- [url-listener](https://github.com/JRJurman/url-listener)
5758

5859
For State Management:
59-
- [nanomorph](https://github.com/choojs/nanomorph)
60-
- [minidux](https://github.com/freeman-lab/minidux)
61-
- [xtend](https://github.com/Raynos/xtend)
60+
- [hover-engine](https://github.com/JRJurman/hover-engine)
6261

6362
While not used in this project, Tram-One is heavily inspired by the
6463
[choo](https://github.com/choojs/choo) view framework.
@@ -67,6 +66,17 @@ creator, [Yoshua Wuyts](https://github.com/yoshuawuyts).
6766
If you like some of the things here, definitely
6867
[go check out that project](https://github.com/choojs).
6968

69+
## Size
70+
```
71+
┌──────────────────────────────────────────────────┐
72+
│ │
73+
│ Module size: 3.42 KB, Gzipped size: 1.34 KB │
74+
│ │
75+
│ UMD size: 23.75 KB, Gzipped size: 7.96 KB │
76+
│ │
77+
└──────────────────────────────────────────────────┘
78+
```
79+
7080
## Video Tutorial
7181
This video tutorial goes through the process of build a Tram-One web app
7282
from start to finish.
@@ -136,28 +146,24 @@ const cHtml = Tram.html({
136146
'color-button': colorElement
137147
})
138148

139-
// create a reducer, that handles changing the color of the app
140-
const colorReducer = (state, action) => {
141-
switch(action.type) {
142-
case('SET_COLOR'):
143-
return action.color
144-
default:
145-
return state // you must ALWAYS return the state by default
146-
}
149+
// create a set of actions, that handles changing the color of the app
150+
const colorActions = {
151+
init: () => 'blue',
152+
setColor: (currentColor, newColor) => newColor
147153
}
148154

149155
// home page to load on the main route
150-
const home = (state) => {
156+
const home = (store, actions) => {
151157

152158
// actionCreator that dispatches to the reducer
153159
const onSetColor = (color) => () => {
154-
state.dispatch({type: 'SET_COLOR', color})
160+
actions.setColor(color)
155161
}
156162

157163
// we use cHtml so that we have color-button available in the template
158164
return cHtml`
159165
<div>
160-
I think the best color for this wall is... ${state.color}!
166+
I think the best color for this wall is... ${store.color}!
161167
or maybe it's...
162168
<color-button onclick=${onSetColor('blue')}>blue</color-button>
163169
<color-button onclick=${onSetColor('red')}>red</color-button>
@@ -166,22 +172,12 @@ const home = (state) => {
166172
`
167173
}
168174

169-
// page to render on the unmatched routes (which by default go to 404)
170-
const noPage = (state) => {
171-
return cHtml`
172-
<div>
173-
<h1>404!</h1>
174-
Sorry pal, no page here...
175-
</div>
176-
`
177-
}
178-
179175
// add routes, by using path matchers with function components
180176
app.addRoute('/', home)
181177
app.addRoute('/404', noPage)
182178

183-
// add reducer, map all state values to 'color', and set the initial value to 'blue'
184-
app.addReducer('color', colorReducer, 'blue')
179+
// add actions and save the state as `color` on the store
180+
app.addActions({color: colorActions})
185181
app.start('.main')
186182
```
187183

@@ -201,7 +197,7 @@ Tram-One has a simple interface to help build your web app.
201197

202198
### `Tram.html([registry])`
203199
_Reference: [hyperx](https://github.com/substack/hyperx),
204-
[bel](https://github.com/shama/bel),
200+
[bel-create-element](https://github.com/JRJurman/bel-create-element),
205201
[rbel](https://github.com/aaaristo/rbel)_
206202

207203
`Tram.html` returns a function that can be used to transform
@@ -243,7 +239,7 @@ const html = Tram.html({
243239
'wrap': pageWraper
244240
})
245241

246-
const home = (state) => {
242+
const home = () => {
247243
return html`
248244
<wrap>
249245
This is my shiny app!
@@ -281,21 +277,13 @@ app.addRoute('/', home)
281277

282278
</details>
283279

284-
### `app.addReducer(key, reducer, state)`
285-
_Reference: [minidux](https://github.com/freeman-lab/minidux)_
280+
### `app.addActions(actionGroups)`
281+
_Reference: [hover-engine](https://github.com/JRJurman/hover-engine)_
286282

287-
`app.addReducer` adds a reducer onto the current instance of Tram.
288-
It takes in three arguments:<br>
289-
`key`, which is where the state will be exposed,<br>
290-
`reducer`, the function that updates state,<br>
291-
`state`, the initial state of the reducer.
292-
293-
Note, `state` here will be exposed in the views as `state[key]`.
294-
295-
The `reducer` should be a function, that takes in `state`, and an `action`.<br>
296-
`state` can be anything you want, a number, object, whatever. At the end of the
297-
reducer, you should ALWAYS return this by default.<br>
298-
`action` should be an object, with a `type` property.
283+
`app.addActions` adds a set of actions that can be triggered in the instance of Tram-One.
284+
It takes in one argument, an object where:<br>
285+
the keys are values that can be pulled in the view<br>
286+
the values are actions that can be triggered in the view<br>
299287

300288
<details>
301289
<summary>
@@ -307,26 +295,21 @@ Example:
307295
const app = new Tram()
308296
const html = Tram.html()
309297

310-
// in this example, state is a number (the votes)
298+
// in this example, `vote` is a number
311299
// but in a larger app, this could be an object
312300
// with multiple key-value pairs
313-
const counterReducer = (state, action) => {
314-
switch(action.type) {
315-
case('UP'):
316-
return state + 1
317-
case('DOWN'):
318-
return state - 1
319-
default:
320-
return state
321-
}
301+
const voteActions = {
302+
init: () => 0,
303+
up: (vote) => vote + 1,
304+
down: (vote) => vote - 1
322305
}
323306

324-
const home = (state) => {
307+
const home = (state, actions) => {
325308
const upvote = () => {
326-
state.dispatch({type: 'UP'})
309+
actions.up()
327310
}
328311
const downvote = () => {
329-
state.dispatch({type: 'DOWN'})
312+
actions.down()
330313
}
331314

332315
return html`
@@ -338,21 +321,21 @@ const home = (state) => {
338321
`
339322
}
340323

341-
app.addReducer('votes', counterReducer, 0)
324+
app.addActions({votes: voteActions})
342325
```
343326

344327
</details>
345328

346329
### `app.addRoute(path, page)`
347-
_Reference: [nanorouter](https://github.com/yoshuawuyts/nanorouter)_
330+
_Reference: [rlite](https://github.com/chrisdavies/rlite)_
348331

349332
`app.addRoute` will associate a component with a route.<br>
350333
`path` should be a matchable route for the application. Look up
351-
[nanorouter](https://github.com/yoshuawuyts/nanorouter)
334+
[rlite](https://github.com/chrisdavies/rlite)
352335
to see all the possible options here.<br>
353-
`page` should be a function that takes in a `state` object for the entire app.
336+
`page` should be a function that takes in a `store`, `actions` and `params`.
354337

355-
The state passed into `page` will have any path parameters for the route as well.
338+
The `params` object passed into the `page` function will have any path parameters and query params.
356339

357340
<details>
358341
<summary>
@@ -364,20 +347,20 @@ Example:
364347
const app = new Tram()
365348
const html = Tram.html()
366349

367-
const homePage = (state) => {
350+
const homePage = () => {
368351
return html`<div>This is my shiny app!</div>`
369352
}
370353

371-
const colorPage = (state) => {
354+
const colorPage = (store, actions, params) => {
372355
const style = `
373-
background: ${state.color};
356+
background: ${params.color};
374357
width: 100px;
375358
height: 100px;
376359
`
377360
return html`<div style=${style}></div>`
378361
}
379362

380-
const noPage = (state) => {
363+
const noPage = () => {
381364
return html`<div>Oh no! We couldn't find what you were looking for</div>`
382365
}
383366

@@ -388,23 +371,10 @@ app.addRoute('/404', noPage)
388371

389372
</details>
390373

391-
### `app.dispatch(action)`
392-
_Reference: [minidux](https://github.com/freeman-lab/minidux)_
393-
394-
**WARNING: EXPERIMENTAL METHOD**<br>
395-
_This method is currently under discussion:<br>
396-
https://github.com/JRJurman/tram-one/issues/8 ._
397-
398-
`app.dispatch` will dispatch an action to the combined reducers. This should
399-
**only be used outside of components**. When inside of a component, you have
400-
access to `state.dispatch`. `app.dispatch` should only be used when you need to
401-
dispatch an action in testing.
402-
`action` should be an object with a property `type`.
403-
404374
### `app.start(selector, [pathName])`
405375

406-
`app.start` will kick off the app. Once this is called, all the reducers
407-
are combined, and the app is mounted onto the `selector`.<br>
376+
`app.start` will kick off the app. Once this is called the app is mounted onto the
377+
`selector`.<br>
408378
`selector` can be a node or a css selector (which is fed into
409379
`document.querySelector`).<br>
410380
`pathName` can be an initial path, if you don't want to check the browser's
@@ -449,29 +419,29 @@ app.start('.main')
449419

450420
</details>
451421

452-
### `app.mount(selector, pathName, state)`
422+
### `app.mount(selector, pathName, store, actions)`
453423
**WARNING: INTENDED FOR INTERNAL USE ONLY**
454424

455-
`app.mount` matches a route from `pathName`, passes in a `state` object,
425+
`app.mount` matches a route from `pathName`, passes in a `store` and `actions` object,
456426
and either creates a child div, or updates a child div under `selector`.
457427

458428
This was created to clean up the code in the library, but may be useful for
459429
testing.
460430

461431
**YOU SHOULD NEVER CALL THIS DIRECTLY FOR YOUR APP**
462432

463-
### `app.toNode(pathName, [state])`
433+
### `app.toNode(pathName[, store, actions])`
464434

465-
`app.toNode` returns a HTMLNode of the app for a given route and state. The
466-
function matches a route from `pathName`, and either takes in a `state`, or
467-
uses the default state (that's been created by adding reducers).
435+
`app.toNode` returns a HTMLNode of the app for a given route and store. The
436+
function matches a route from `pathName`, and either takes in a `store`, or
437+
uses the default store (that's been created by adding reducers).
468438

469439
While initially created to clean up the code in the library, this can be useful
470440
if you want to manually attach the HTMLNode that Tram-One builds to whatever.
471441

472-
### `app.toString(pathName, [state])`
442+
### `app.toString(pathName[, store])`
473443

474-
`app.toString` returns a string of the app for a given route and state. It has
444+
`app.toString` returns a string of the app for a given route and store. It has
475445
the same interface at `app.toNode`, and basically just calls `.outerHTML` (or
476446
`toString` on the server) on the node.
477447

Original file line numberDiff line numberDiff line change
@@ -1,25 +1,33 @@
1-
const uglify = require('rollup-plugin-uglify')
21
const babel = require('rollup-plugin-babel')
32
const filesize = require('rollup-plugin-filesize')
4-
3+
const uglify = require('rollup-plugin-uglify')
54
const pkg = require('../package.json')
5+
66
const external = Object.keys(pkg.dependencies)
77

88
const plugins = [
99
babel({
1010
presets: [
11-
'es2015-rollup'
12-
]
11+
['env', {
12+
modules: false,
13+
targets: {
14+
node: '4'
15+
}
16+
}]
17+
],
18+
plugins: ['external-helpers']
1319
}),
1420
uglify(),
1521
filesize()
1622
]
1723

1824
export default {
19-
entry: 'tram-one.js',
25+
input: 'tram-one.js',
2026
external: external,
21-
dest: pkg.main,
22-
format: 'es',
2327
plugins: plugins,
24-
sourceMap: true
28+
output: {
29+
sourcemap: true,
30+
format: 'es',
31+
file: pkg.module
32+
}
2533
}

0 commit comments

Comments
 (0)