Repository navigation
Doors 0.17 Release Notes
Doors 0.17 adds deferred Door operations: show a placeholder right away and replace it with slow content once it is rendered. With doors.IsDocument, the same code sends the slow content complete in the page response.
Highlights
Deferred operations
DeferredInner, DeferredOuter, and DeferredStatic work like Inner, Outer, and Static, but wait until the Door's current content is rendered and scheduled for delivery. Use them to show a placeholder first and replace it with content that is slow to render:
func (p *Page) showReport(ctx context.Context, period string) {
p.report.Inner(ctx, <div class="skeleton">Loading report...</div>)
p.report.DeferredInner(ctx, ReportTable{period: period})
}
Each is also a package function that targets the Door ctx renders in, so content in a Bind or route can defer its own slow part:
elem (p *Page) Main() {
~(p.period.Bind(elem(period string) {
<section class="report">
~(if doors.IsDocument(ctx) {
~ReportTable{period: period}
} else {
~~
doors.DeferredInner(ctx, ReportTable{period: period})
~~
<div class="skeleton">Loading report...</div>
})
</section>
}))
}
See Door.
IsDocument
doors.IsDocument(ctx) is true only while rendering the page response: the initial page render and every Door placed during it. Use it, as above, to send slow content complete with the page instead of as a skeleton followed by an update.
Behavior Changes
- Door updates follow
SolitaireDisableGzip. It was documented to, but Door updates followedServerDisableGzip.ServerDisableGzipnow covers HTML and resources only. - A Door rendered in a new place leaves its old place once the new content is queued, instead of at once.
Fixes
- Equality functions (
NewSourceEqual,NewSourceEqualNoSkip,DeriveSourceEqual,DeriveBeamEqual,RouteDeriveEqual,TabStateEqual) received(new, old)on updates, while internals used a different order. They now always get(old, new). - Door renders during the page render could race on CSP collection.
- A panic in cleanup code during a Door operation, such as in a beam watcher's
Cancel, could leave the operation's channel open for good. - Update stream:
- Ending an instance while updates were being written could crash the process or leave an operation's channel open.
- A result or gap report for a re-sent update that arrived while it was being written was lost, so the instance later ended with a sync timeout, or the stream panicked.
- Navigation actions (
ActionLocation*) were not re-sent after the frame carrying them was lost. - A late report of a lost update that had already been re-delivered could end the instance when many updates followed in between.
- A new stream could not take over while the previous one was stuck writing to a client that stopped reading.
- A request context canceled with a cause from outside Doors, such as a
BaseContextfromsignal.NotifyContext, made the stream panic. - A panic in one call's result callback left the other calls answered in the same report unresolved.
- The instance ended on reaching
SolitaireQueueinstead of on exceeding it.
ActionScrolloptions that cannot be encoded to JSON failed inside the update stream;Callnow reports the encoding error.
Breaking Changes
| Old | New |
|---|---|
CSP.ScriptStrictDynamic |
Removed: 'strict-dynamic' made browsers block the Doors client script, so pages did not work |
ServerDisableGzip turns off gzip for Door updates |
SolitaireDisableGzip does |
Keys: on AKeyDown and AKeyUp |
Key:, named like Scope and Indicator |
Migration
go get github.com/doors-dev/doors@v0.17.0Rename Keys: to Key: on AKeyDown and AKeyUp. Remove ScriptStrictDynamic from doors.CSP. If you turned off gzip with ServerDisableGzip and want Door updates uncompressed too, also set SolitaireDisableGzip.