Skip to content

Instantly share code, notes, and snippets.

@DylanPiercey
Last active February 23, 2021 00:20
Show Gist options
  • Select an option

  • Save DylanPiercey/9d65759ffa4ff7752a2bc8aa74f5da40 to your computer and use it in GitHub Desktop.

Select an option

Save DylanPiercey/9d65759ffa4ff7752a2bc8aa74f5da40 to your computer and use it in GitHub Desktop.
static var isBrowser = typeof window !== "undefined";
static var LOADING = 0;
static var RESOLVED = 1;
static var REJECTED = 2;
static function isPromise(val) {
return val && val.then;
}
static function syncSSRPromise(state, value) {
if (value && "_settled" in value) {
if (value._settled === 0) {
throw new Error("Was unable to serialize promise data from server");
}
state.settled = value._settled;
state.value = value._value;
return true;
}
}
class {
onCreate(input) {
var value = input.from;
if (isBrowser) {
var state = { settled: LOADING, value: undefined };
syncSSRPromise(state, value);
this.state = state;
} else if (isPromise(value)) {
var resolvedData = { _settled: LOADING, _value: undefined };
value.toJSON = function() {
return resolvedData;
};
value.then(
function(value) {
resolvedData._settled = RESOLVED;
resolvedData._value = value;
},
function(err) {
resolvedData._settled = REJECTED;
resolvedData._value = err;
}
);
}
}
onInput(input) {
if (isBrowser && this.hasMounted) {
var state = this.state;
var value = input.from;
if (!syncSSRPromise(state, value)) {
if (isPromise(value)) {
state.settled = LOADING;
value.then(
function(value) {
state.settled = RESOLVED;
state.value = value;
},
function(err) {
state.settled = REJECTED;
state.value = value;
}
);
} else {
state.settled = RESOLVED;
state.value = value;
}
}
}
}
onMount() {
this.hasMounted = true;
}
}
<if(isBrowser)>
$ var renderer = (
state.settled === RESOLVED
? input.then
: state.settled === REJECTED
? input.catch
: input.placeholder
);
$ renderer && renderer.renderBody && renderer.renderBody((out), state.value);
</if>
<else>
<await(input.from) then=input.then catch=input.catch timeout=input.timeout/>
</else>
@mlrawlings
Copy link
Copy Markdown

<if(isBrowser)>
    $ const renderer = state.loading ? input.placeholder : state.err ? input.catch : input.then;
    $ const data = state.err || state.value;
    <${renderer}(data)/>
</if>

@tigt
Copy link
Copy Markdown

tigt commented Feb 21, 2021

Some questions about the isBrowser check:

  • What outcome would you want in a WebWorker? I assume false, in which case no change is needed (other than maybe a more-specific variable name).

  • I think you can get it even shorter with window != null? But maybe the true end-goal is some sort of __BROWSER__ build-time var so entire branches are compiled out.

@DylanPiercey
Copy link
Copy Markdown
Author

DylanPiercey commented Feb 22, 2021

What outcome would you want in a WebWorker?

I think false, so yeah the name could be better.

I think you can get it even shorter with window != null?

This would yield Uncaught ReferenceError: window is not defined in eg Node. Also, it's usually pretty easy to configure a bundler to strip out typeof window checks, like we're doing here: https://github.com/marko-js/examples/blob/master/examples/webpack-express/webpack.config.js#L76

@tigt
Copy link
Copy Markdown

tigt commented Feb 23, 2021

Rad on both counts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment