Skip to content

Commit

Permalink
Improve examples loading feedback (#355)
Browse files Browse the repository at this point in the history
This is a proposal for #338.

- Builds on top of the code by @ickk using `TransformStream`.
- Adds loading feedback on examples.
- The solution is hacky, it monkey-patches `fetch` in the example template.

https://user-images.githubusercontent.com/188612/163875627-b11bf330-0fb8-4991-a710-e12e8657fe07.mp4

Co-Authored-By: ickk <17050131+ickk@users.noreply.github.com>


Co-authored-by: ickk <git@ickk.io>
  • Loading branch information
doup and ickk committed May 10, 2022
1 parent e807dba commit a4f6d34
Show file tree
Hide file tree
Showing 8 changed files with 4,929 additions and 8 deletions.
9 changes: 9 additions & 0 deletions generate-wasm-examples/generate_wasm_examples.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ add_category()
cp examples/$category_path/$example.rs ../../content/examples/$category_path/$example/
cargo build --release --target wasm32-unknown-unknown --example $example
wasm-bindgen --out-dir ../../content/examples/$category_path/$example --no-typescript --target web target/wasm32-unknown-unknown/release/examples/$example.wasm

# Patch generated JS to allow to inject custom `fetch` with loading feedback.
# See: https://github.com/bevyengine/bevy-website/pull/355
sed -i.bak \
-e 's/function init(input) {/function init(customFetch, input) { customFetch = customFetch || fetch;/' \
-e 's/input = fetch(/input = customFetch(/' \
-e 's/getObject(arg0).fetch(/customFetch(/' \
../../content/examples/$category_path/$example/$example.js

echo "+++
title = \"$example\"
template = \"example.html\"
Expand Down
51 changes: 51 additions & 0 deletions sass/components/_bevy-instance.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
.bevy-instance {
position: relative;

&__progress-status {
display: flex;
flex-direction: column;
position: absolute;
bottom: 50%;
left: 50%;
width: 250px;
transform: translateX(-50%);

&:empty {
display: none;
}
}

&__progress-file {
margin-bottom: 4px;
font-weight: normal;
text-shadow: 1px 1px 1px #000;
font-size: 0.85rem;
word-break: break-all;
}

&__progress-track {
width: 100%;
height: 4px;
border-radius: 4px;
background-color: #555;

&:not(:last-child) {
margin-bottom: 2px;
}
}

&__progress-bar {
height: 4px;
min-width: 4px;
background-color: #799bbb;
border-radius: 4px;
width: 0px;
}

&__canvas {
width: 100% !important;
height: auto !important;
border-radius: $border-radius;
background: #2b2c2f;
}
}
6 changes: 0 additions & 6 deletions sass/components/_example.scss
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,4 @@
grid-area: github;
text-align: right;
}

&__canvas {
width: 100% !important;
height: auto !important;
border-radius: $border-radius;
}
}
1 change: 1 addition & 0 deletions sass/site.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
// - Repeating visual patterns: buttons, cards, menus…
// - Components can be composed between them to create new components
// - These should be self contained and shouldn't affect other styling
@import "components/bevy-instance";
@import "components/book-footer";
@import "components/book-nav";
@import "components/card";
Expand Down
53 changes: 53 additions & 0 deletions static/tools.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { ReadableStream as PolyfillReadableStream, TransformStream as PolyfillTransformStream } from '/web-streams-polyfill-3.2.1.mjs';
import { createReadableStreamWrapper } from '/web-streams-adapter-0.1.0.mjs';

function getFilename(resource) {
const pathname = (typeof resource === 'string')
? resource
: (resource instanceof URL)
? resource.pathname
: '';

const parts = pathname.split('/');

return parts[parts.length - 1];
}

// `progressiveFetch` is a wrapper over `window.fetch`. It allows you to insert middle-ware that is
// polled as the fetch completes. See bevy-website/issues/338 for details.
async function progressiveFetch(resource, callbacks={}) {
const toPolyfillReadable = createReadableStreamWrapper(PolyfillReadableStream);
const toNativeReadable = createReadableStreamWrapper(window.ReadableStream);
const filename = getFilename(resource);
const cb = Object.assign({
start: (filename, length) => {},
update: (filename, loaded, length) => {},
finish: (filename, length) => {},
}, callbacks);

let response = await fetch(resource);
const lengthBytes = response.headers.get('content-length');
let loadedBytes = 0;

const transform = new PolyfillTransformStream({
start() {
cb.start(filename, lengthBytes);
},
transform(chunk, controller) {
loadedBytes += chunk.byteLength;
cb.update(filename, loadedBytes, lengthBytes);
controller.enqueue(chunk);
},
flush() {
cb.update(filename, lengthBytes, lengthBytes);
cb.finish(filename, lengthBytes);
},
});

return new Response(
toNativeReadable(toPolyfillReadable(response.body).pipeThrough(transform)),
response,
);
}

export { progressiveFetch };
Loading

0 comments on commit a4f6d34

Please sign in to comment.