Releases: mozilla/reflex
Large cleanup
Upgrade to flow@0.49
Switched to flow syntax
New version no longer uses flow comment and separate .js.flow
files for interface definitions. Instead interface definitions have moved to same named .js
files and standard type syntax is used for type annotations.
Switched to never type
flow@0.34 introduced empty
as a "bottom type" that actually does what our custom Never
type used to do. This release removes Never
in favor of empty
.
Better code coverage
In this release flow code coverage has being greatly improved so expect a lot more errors cough than in older versions.
Driver interface moved to reflex-driver
In this release driver interface got greatly simplified to reduce requirements for the driver implementer. In addition built-in driver got replaced by one that just throws exception if used, this would make sure that built-in driver isn't used initially and then re-rendered with actual driver. This implies that you can't create nodes outside of the view function, but given that it greatly simplifies API we decided it was worth it. If you do happen to create nodes outside of regular application loop, you still can do that but instead you'd have to create those with a actual driver instead of API exposed by reflex.
node
got renamed to element
In the past reflex referred to elements nodes as nodes and to nodes as virtual nodes it also enforced very specific interface for every node type. In this release reflex no longer distinguishes between node types, but functions node
got renamed to element
for more clarity.
A Farewell to FRP
In this release we're finally catching up with Elm making signals unnecessary (Linked article does a great job explaining why). In this release reflex no longer has notion of signals and all of the associated constructs had being removed.
Simpler application bootstrap
Removal of signals required a breaking API change as signal subscriptions used to be a way to wire DOM and Effect drivers:
import {init, update, view} from "./main"
import {start, Effects} from "reflex"
import {Renderer} from "reflex-virtual-dom-driver"
const rederer = new Renderer({ target: document.body })
const app = start({ init, update, view })
app.view.subscribe(renderer.address)
app.task.subscribe(Effects.driver(app.address))
API that replaced it is as follows:
import {init, update, view} from "./main"
import {start, Task} from "reflex"
import {Renderer} from "reflex-virtual-dom-driver"
const rederer = new Renderer({ target: document.body })
const app = start({ init, update, view }, ({view, task}) => {
renderer.render(view)
Task.perform(task)
})
Experimental support for subscriptions
This release contains experimental and undocumented support for subscriptions which were a major missing piece from Elm. Unlike subscriptions Elm, reflex will have no special "effect manager" modules that get wired up at compile time, instead there will be notion of services that have API somewhat similar to application (but without view) that components will be able to subscribe to. For this reason we'll take few more cycles to iron out the API before finalizing it. So if you want to play and provide feedback, feel free otherwise wait until they're fully baked.
Compatibility with flow 0.25 & 0.26
- Update to flow@0.25
- Opt into required type arguments that will be default in flow@0.26
Cancellable tasks & bug fixes
- Fix regression introduced by 4e13b24 & ba21bbb that cause misbehaviors on synchronous tasks.
- Factor out
requestAnimationFrame
scheduler fromEffects
library and expose it via tasks instead. Having it part ofEffects
did not really made much sense. - Renamed
Effects.task(task)
toEffects.perform(task)
as former was pretty confusing. - Changed API for creating cancellable tasks so they won't perform extra allocations on execution. Most relevant for
requestAnimationFrame
task that are used a lot during animations. - Change class hierarchies to avoid passing own methods to super calls.
- Add
Task.prototype.recover
API so that task failures can more efficiently & intuitively be translated to error actions.
Fix flow type checker on travis
0.3.0 was breaking failing type checker on travis, this version fixes that.
Faster task scheduler
This version introduced performance optimizations:
- Now Task scheduler is no longer implemented in pure functional style as number of allocations caused by it was in top 5 for browser.html code base. Instead now forking a task creates a mutable
Process
instance that attempts to do almost no allocations while stepping through tasks. - Several code paths used try / finally blocks which hit unoptimized path on spider-monkey. Use of try / catch on the other hand is optimized, there for with this change we should hit the optimized path.
Breaking API changes
- Now
Task.create
is deprecated in favor ofnew Task
Task.fork(task)
now returnsProcess
instance (it used return void)- Now
execute
innew Task(execute)
may return anabort
function which scheduler may use to abort running task.
Large cleanup
What's new
Migration to flow@0.49 proper
While back library started using flow type checker, but opted into via comment style annotations. At this point it made little sense to continue using commented syntax if anything it just made things more difficult for no benefit.
Factoring out driver
Interface definition between reflex and it's drivers has being part of reflex library itself, but that only made things difficult as driver implementations had to depend on reflex itself & update every time thing changed there. By factoring driver interface into own package allows for less frequent synchronization requirements between reflex & it's drivers.
Driver interface has also being simplified greatly. Reflex used to over-specify structure of the nodes but that provided no benefit for increased complexity. Now drivers have much looser interface & are able to represent node implementations as they're pleased.
A Farewell to FRP
Catching up with Elm's removing signals. Signals were always internal implementation details except they were used to bootstrap application event loops:
Before
import {init, update, view} from "./app"
import {start, Effects} from "reflex"
import {Renderer} from "reflex-virtual-dom-driver"
const renderer = new Renderer({target:document.body})
const app = start({init, update, view, flags:null})
app.view.subscribe(renderer.address)
app.task.subscribe(Effects.driver(app.address))
After
import {init, update, view} from "./app"
import {start, Task} from "reflex"
import {Renderer} from "reflex-virtual-dom-driver"
const renderer = new Renderer({target:document.body})
const app = start({init, update, view, flags:null}, ({view, task}) => {
renderer.render(view)
Task.perform(task)
})
Experimental support of subscriptions has also being added, but for now they're not documented as the API is not fully fleshed out, but you can look at the source & start playing around with them if you like.
Breaking changes
Startup API has changed
Before
import {init, update, view} from "./app"
import {start, Effects} from "reflex"
import {Renderer} from "reflex-virtual-dom-driver"
const renderer = new Renderer({target:document.body})
const app = start({init, update, view, flags:null})
app.view.subscribe(renderer.address)
app.task.subscribe(Effects.driver(app.address))
After
import {init, update, view} from "./app"
import {start, Task} from "reflex"
import {Renderer} from "reflex-virtual-dom-driver"
const renderer = new Renderer({target:document.body})
const app = start({init, update, view, flags:null}, ({view, task}) => {
renderer.render(view)
Task.perform(task)
})
No more signals
If you used to create your own signals or map / reduce them they are gone, so you'll need to stop doing that.
No more driver
If you used reflex driver code you should look at reflex-driver it has being factored out.
Better type inference
Before we used to have our own Never
type which got replaced by flow built-in empty
type, migration will require some work but mostly should be smooth. New flow also catches far more errors and code has being updated to provide better code coverage which means far more errors maybe caught after update.
Add Effects.receive
Only change in this release is addition of Effects.receive(action)
which is just a shortcut of Effects.task(Task.succeed(action))
Make effects concurrent
Up until now tasks scheduled via Effects
used to run sequentially, meaning if one task was blocked next task would not run until first one was complete. With this change each task is spawned concurrently.
Make view drivers pluggable.
- Made significant changes to the (mostly internal) API to have Virtual Node, Text & Thunk types compatible with different drivers.
render
is calledthunk
now.- application now has
view
,model
,task
properties in form of signals that drivers / services can subscribe to do associated IO.
hot-reload support
Reflex had issue with hot reloading namely when view function got swapped, reflex would end up generating new Thunk components for those causing react to remount (see facebook/react#4826 for further details).
This release employees caching for generated Thunk components so that react component types will match up even across code hot swaps (assuming same react is used).