This commit is contained in:
travis 2016-03-16 23:29:17 -07:00
Родитель 8df7602f6b
Коммит 90eccc044e
12 изменённых файлов: 299 добавлений и 204 удалений

12
examples/counter/.babelrc Normal file
Просмотреть файл

@ -0,0 +1,12 @@
{
"sourceMaps": "inline",
"comments": false,
"presets": [
"es2015"
],
"plugins": [
"syntax-flow",
"transform-flow-strip-types",
"remove-comments"
]
}

Просмотреть файл

@ -1,16 +1,14 @@
[ignore]
.*/src/test/.*
.*/dist/.*
.*/node_modules/reflex/examples/.*
.*/node_modules/reflex-virtual-dom-driver/lib/.*
.*/node_modules/reflex/lib/.*
.*/node_modules/babel.*
.*/node_modules/tap/.*
.*/node_modules/reflex-virtual-dom-driver/examlpes/.*
[libs]
./node_modules/reflex/interfaces/
./node_modules/reflex-virtual-dom-driver/interfaces/
[include]
[options]
module.name_mapper='reflex-virtual-dom-driver' -> 'reflex-virtual-dom-driver/src/index'
module.name_mapper='reflex' -> 'reflex/src/index'
suppress_comment= \\(.\\|\n\\)*\\@FlowIssue
suppress_comment= \\(.\\|\n\\)*\\@FlowIgnore

Просмотреть файл

@ -0,0 +1,14 @@
# Counter
### Demo
```
npm start
```
Navigate to [demo][]
[demo]:http://localhost:6061/

Просмотреть файл

@ -1,5 +1,3 @@
'use strict';
import browserify from 'browserify';
import gulp from 'gulp';
import source from 'vinyl-source-stream';
@ -16,120 +14,119 @@ import sequencial from 'gulp-sequence';
import ecstatic from 'ecstatic';
import hmr from 'browserify-hmr';
import hotify from 'hotify';
import manifest from './package.json';
var settings = {
port: process.env.DEV_PORT || '6061',
cache: {},
plugin: [],
transform: [
babelify.configure({
"optional": [
"spec.protoToAssign",
"runtime"
],
"blacklist": []
})
],
debug: true,
watch: false,
compression: null
};
class Bundler {
constructor(options) {
this.options = options
var Bundler = function(entry) {
this.entry = entry
this.compression = settings.compression
this.build = this.build.bind(this);
this.build = this.build.bind(this);
this.plugin = []
this.transform = []
this.cache = {}
this.entry = path.join
( options.input
, options.main
)
this.bundler = browserify({
entries: ['./src/' + entry],
debug: settings.debug,
cache: {},
transform: settings.transform,
plugin: settings.plugin
});
this.watcher = settings.watch &&
watchify(this.bundler)
.on('update', this.build);
}
Bundler.prototype.bundle = function() {
gutil.log(`Begin bundling: '${this.entry}'`);
return this.watcher ? this.watcher.bundle() : this.bundler.bundle();
if (options.babel != null) {
this.transform.push(babelify)
}
if (options.hotreload != null) {
this.transform.push(hotify)
this.plugin.push(hmr)
}
this.bundler = browserify
( { entries: [this.entry]
, debug:
( options.sourceMaps != null
? false
: options.sourceMaps === false
? false
: true
)
, cache: this.cache
, transform: this.transform
, plugin: this.plugin
}
)
if (options.watch) {
this.watcher =
watchify(this.bundler)
.on('update', this.build)
}
}
bundle() {
gutil.log(`Begin bundling: '${this.entry}'`);
const output =
( this.options.watch
? this.watcher.bundle()
: this.bundler.bundle()
)
return output
}
build() {
const transforms =
[ source(this.options.main)
, buffer()
, ( this.options.sourceMaps == null
? null
: sourcemaps.init({loadMaps: true})
)
, ( this.options.compression == null
? null
: uglify(this.options.compression)
)
, ( this.options.sourceMaps == null
? null
: sourcemaps.write(this.options.sourceMaps.output)
)
, gulp.dest(this.options.output)
]
const output =
transforms.reduce
( (input, transform) =>
( transform != null
? input.pipe(transform)
: input
)
, this
.bundle()
.on('error', (error) => {
gutil.beep();
console.error(`Failed to browserify: '${this.entry}'`, error.message)
})
)
return output.on('end', () => gutil.log(`Completed bundling: '${this.options.input}'`))
}
}
Bundler.prototype.build = function() {
var bundle = this
.bundle()
.on('error', (error) => {
gutil.beep();
console.error(`Failed to browserify: '${this.entry}'`, error.message);
})
.pipe(source(this.entry + '.js'))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true}))
.on('error', (error) => {
gutil.beep();
console.error(`Failed to make source maps for: '${this.entry}'`,
error.message);
});
return (this.compression ? bundle.pipe(uglify(this.compression)) : bundle)
.on('error', (error) => {
gutil.beep();
console.error(`Failed to bundle: '${this.entry}'`,
error.message);
})
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest('./dist/'))
.on('end', () => {
gutil.log(`Completed bundling: '${this.entry}'`);
});
}
var bundler = function(entry) {
return gulp.task(entry, function() {
return new Bundler(entry).build();
});
}
// Starts a static http server that serves browser.html directory.
gulp.task('server', function() {
var server = config => () => {
var server = http.createServer(ecstatic({
root: path.join(module.filename, '../'),
cache: 0
root: path.join(module.filename, config.root),
cache: config.cache
}));
server.listen(settings.port);
});
server.listen(config.port);
gutil.log(`Navigate to http://localhost:${config.port}/`)
}
var bundler = config => () => new Bundler(config).build()
gulp.task('compressor', function() {
settings.compression = {
mangle: true,
compress: true,
acorn: true
};
});
gulp.task('watcher', function() {
settings.watch = true
});
Object.keys(manifest.builds).forEach(name => {
const config = manifest.builds[name]
gulp.task('hotreload', function() {
settings.plugin.push(hmr);
settings.transform.push(hotify);
});
bundler('index');
gulp.task('build', [
'compressor',
'index'
]);
gulp.task('watch', [
'watcher',
'index'
]);
gulp.task('develop', sequencial('watch', 'server'));
gulp.task('live', ['hotreload', 'develop']);
gulp.task('default', ['live']);
if (config.server) {
gulp.task(`serve ${name}`, server(config.server))
gulp.task(`build ${name}`, bundler(config))
gulp.task(name, sequencial(`build ${name}`, `serve ${name}`))
}
else {
gulp.task(name, bundler(config))
}
})

Просмотреть файл

@ -1,10 +1,11 @@
<html>
<head>
<title>Sample App</title>
<title></title>
</head>
<body>
<div id='root'>
</div>
<script src="./dist/index.js"></script>
<main>
</main>
<script src="./dist/virtual-dom-driver.js"></script>
<scrit src="./dist/reflex-driver.js"></script>
</body>
</html>

Просмотреть файл

@ -1,34 +1,58 @@
{
"name": "counter",
"description": "Reflex counter example",
"version": "0.0.0",
"scripts": {
"test": "flow check",
"start": "gulp live",
"build": "NODE_ENV=production gulp build"
"start": "gulp"
},
"dependencies": {
"reflex": "latest",
"reflex-virtual-dom-driver": "latest"
"reflex": "0.2.0",
"reflex-virtual-dom-driver": "0.2.0"
},
"devDependencies": {
"browserify": "11.0.1",
"watchify": "3.3.1",
"babelify": "6.1.3",
"browserify-hmr": "0.3.0",
"hotify": "0.0.1",
"babel-core": "5.8.23",
"babel-runtime": "5.8.20",
"babel-core": "6.7.2",
"babel-plugin-remove-comments": "2.0.0",
"babel-plugin-syntax-flow": "6.3.13",
"babel-plugin-transform-es2015-modules-umd": "6.4.3",
"babel-plugin-transform-flow-strip-types": "6.4.0",
"babel-preset-es2015": "6.3.13",
"babelify": "7.2.0",
"browserify": "13.0.0",
"browserify-hmr": "0.3.1",
"ecstatic": "0.8.0",
"flow-bin": "0.17.0",
"gulp": "3.9.0",
"gulp-sequence": "0.4.1",
"gulp-sourcemaps": "1.5.2",
"gulp-uglify": "^1.2.0",
"gulp-util": "^3.0.6",
"flow-bin": "0.22.1",
"gulp": "3.9.1",
"gulp-sequence": "0.4.5",
"gulp-sourcemaps": "1.6.0",
"gulp-uglify": "1.5.3",
"gulp-util": "3.0.7",
"hotify": "0.1.0",
"vinyl-buffer": "1.0.0",
"vinyl-source-stream": "1.1.0"
"vinyl-source-stream": "1.1.0",
"watchify": "3.7.0"
},
"builds": {
"default": {
"//compression": {
"mangle": true,
"compress": true,
"acorn": true
},
"babel": true,
"hotreload": true,
"watch": true,
"server": {
"port": 6061,
"cache": 0,
"root": "../"
},
"sourceMaps": {
"output": "./"
},
"main": "./virtual-dom-driver.js",
"input": "./src/",
"output": "./dist/"
}
}
}

Просмотреть файл

@ -1,25 +1,36 @@
/* @flow */
import {html, forward} from "reflex";
import {html, forward} from "reflex"
/*::
import * as type from "../type/counter"
import type {Model, Action} from "./counter"
import type {Address, VirtualTree} from "reflex"
*/
export const asIncrement/*:type.asIncrement*/ = () =>
({type: "Counter.Increment"})
export const asDecrement/*:type.asDecrement*/ = () =>
({type: "Counter.Decrement"})
const Increment =
{ type: "Increment"
, create: () => Increment
}
const Decrement =
{ type: "Decrement"
, create: () => Decrement
}
export const create/*:type.create*/ = ({value}) =>
({type: "Counter.Model", value})
export const init =
(value/*:number*/)/*:Model*/ =>
({ value })
export const update/*:type.update*/ = (model, action) =>
action.type === "Counter.Increment" ?
{type:model.type, value: model.value + 1} :
action.type === "Counter.Decrement" ?
{type:model.type, value: model.value - 1} :
model
export const update =
( model/*:Model*/
, action/*:Action*/
)/*:Model*/ =>
( action.type === Increment.type
? { value: model.value + 1 }
: action.type === Decrement.type
? { value: model.value - 1 }
: model
)
const counterStyle = {
value: {
@ -27,19 +38,31 @@ const counterStyle = {
}
}
// View
export const view/*:type.view*/ = (model, address) =>
html.span({key: "counter"}, [
html.button({
key: "decrement",
onClick: forward(address, asDecrement)
}, ["-"]),
html.span({
key: "value",
style: counterStyle.value,
}, [String(model.value)]),
html.button({
key: "increment",
onClick: forward(address, asIncrement)
}, ["+"])
])
export const view =
( model/*:Model*/
, address/*:Address<Action>*/
)/*:VirtualTree*/ =>
html.span
( { key: "counter"
}
, [ html.button
( { key: "decrement"
, onClick: forward(address, Decrement.create)
}
, ["-"]
)
, html.span
( { key: "value"
, style: counterStyle.value
}
, [ `${model.value}` ]
)
, html.button
( { key: "increment"
, onClick: forward(address, Increment.create)
}
, ["+"]
)
]
)

Просмотреть файл

@ -0,0 +1,28 @@
/* @flow */
import type {Address, VirtualTree} from "reflex"
type Tag <type> =
{ type: type
}
export type Model =
{ value: number
}
export type Action
= Tag<"Increment">
| Tag<"Decrement">
declare export var Increment:Tag<"Increment">
declare export var Decrement:Tag<"Decrement">
declare export function init (value:number):
Model
declare export function update (model:Model, action:Action):
Model
declare export function view (model:Model, address:Address<Action>):
VirtualTree

Просмотреть файл

@ -1,18 +0,0 @@
/* @flow */
import * as Counter from "./counter"
import {start} from "reflex"
import {Renderer} from "reflex-virtual-dom-driver"
const app = start({
initial: Counter.create(window.app != null ?
window.app.model.value :
{value: 0}),
update: Counter.update,
view: Counter.view
});
window.app = app
const renderer = new Renderer({target: document.body})
app.view.subscribe(renderer.address)

Просмотреть файл

@ -0,0 +1,18 @@
/* @flow */
import {init, update, view} from "./counter"
import {start, beginner} from "reflex"
export const app = start
( beginner
( { model:
( window.app == null
? init(0)
: window.app.model.value
)
, update: update
, view: view
}
)
)
window.app = app

Просмотреть файл

@ -0,0 +1,13 @@
/* @flow */
import {app} from "./main"
import {Renderer} from "reflex-virtual-dom-driver"
const renderer = new Renderer
( { target: document.body
}
)
app.view.subscribe
( renderer.address
)

Просмотреть файл

@ -1,15 +0,0 @@
/* @flow */
import type {Address, VirtualNode} from "reflex/type"
export type Model = {type: "Counter.Model", value:number}
export type Increment = {type: "Counter.Increment"}
export type Decrement = {type: "Counter.Decrement"}
export type Action = Increment|Decrement
export type asIncrement = () => Increment
export type asDecrement = () => Decrement
export type create = (options:{value:number}) => Model
export type update = (model:Model, action:Action) => Model
export type view = (model:Model, address:Address<Action>) => VirtualNode