Skip to content

Commit

Permalink
Convert renderDependency() to async
Browse files Browse the repository at this point in the history
  • Loading branch information
wch committed Oct 31, 2022
1 parent 20cc8e2 commit 8dfd8f5
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 14 deletions.
43 changes: 33 additions & 10 deletions srcts/src/shiny/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,24 @@ import { sendImageSizeFns } from "./sendImageSize";
import { renderHtml as singletonsRenderHtml } from "./singletons";
import type { WherePosition } from "./singletons";

function renderDependencies(dependencies: HtmlDep[] | null): void {
async function renderDependencies(
dependencies: HtmlDep[] | null
): Promise<void> {
if (dependencies) {
dependencies.forEach(renderDependency);
for (const dep of dependencies) {
await renderDependency(dep);
}
}
}

// Render HTML in a DOM element, add dependencies, and bind Shiny
// inputs/outputs. `content` can be null, a string, or an object with
// properties 'html' and 'deps'.
function renderContent(
async function renderContent(
el: BindScope,
content: string | { html: string; deps?: HtmlDep[] } | null,
where: WherePosition = "replace"
): void {
): Promise<void> {
if (where === "replace") {
shinyUnbindAll(el);
}
Expand All @@ -42,7 +46,7 @@ function renderContent(
dependencies = content.deps || [];
}

renderHtml(html, el, dependencies, where);
await renderHtml(html, el, dependencies, where);

let scope: BindScope = el;

Expand All @@ -66,13 +70,13 @@ function renderContent(
}

// Render HTML in a DOM element, inserting singletons into head as needed
function renderHtml(
async function renderHtml(
html: string,
el: BindScope,
dependencies: HtmlDep[],
where: WherePosition = "replace"
): ReturnType<typeof singletonsRenderHtml> {
renderDependencies(dependencies);
): Promise<ReturnType<typeof singletonsRenderHtml>> {
await renderDependencies(dependencies);
return singletonsRenderHtml(html, el, where);
}

Expand Down Expand Up @@ -148,7 +152,7 @@ function needsRestyle(dep: HtmlDepNormalized) {
}

// Client-side dependency resolution and rendering
function renderDependency(dep_: HtmlDep) {
async function renderDependency(dep_: HtmlDep) {
const dep = normalizeHtmlDependency(dep_);

// Convert stylesheet objs to links early, because if `restyle` is true, we'll
Expand Down Expand Up @@ -203,6 +207,9 @@ function renderDependency(dep_: HtmlDep) {
$head.append(stylesheetLinks);
}

const scriptPromises: Array<Promise<any>> = [];
const scriptElements: HTMLScriptElement[] = [];

dep.script.forEach((x) => {
const script = document.createElement("script");

Expand All @@ -214,9 +221,24 @@ function renderDependency(dep_: HtmlDep) {
script.setAttribute(attr, val ? val : "");
});

$head.append(script);
const p = new Promise((resolve) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
script.onload = (e: Event) => {
resolve(null);
};
});

scriptPromises.push(p);
scriptElements.push(script);
});

// Append the script elements all at once, so that we're sure they'll load in
// order. (We didn't append them individually in the `forEach()` above,
// because we're not sure that the browser will load them in order if done
// that way.)
document.head.append(...scriptElements);
await Promise.allSettled(scriptPromises);

dep.attachment.forEach((x) => {
const link = $("<link rel='attachment'>")
.attr("id", dep.name + "-" + x.key + "-attachment")
Expand All @@ -231,6 +253,7 @@ function renderDependency(dep_: HtmlDep) {
$newHead.html(dep.head);
$head.append($newHead.children());
}

return true;
}

Expand Down
6 changes: 3 additions & 3 deletions srcts/types/src/shiny/render.d.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type { BindScope } from "./bind";
import { renderHtml as singletonsRenderHtml } from "./singletons";
import type { WherePosition } from "./singletons";
declare function renderDependencies(dependencies: HtmlDep[] | null): void;
declare function renderDependencies(dependencies: HtmlDep[] | null): Promise<void>;
declare function renderContent(el: BindScope, content: string | {
html: string;
deps?: HtmlDep[];
} | null, where?: WherePosition): void;
declare function renderHtml(html: string, el: BindScope, dependencies: HtmlDep[], where?: WherePosition): ReturnType<typeof singletonsRenderHtml>;
} | null, where?: WherePosition): Promise<void>;
declare function renderHtml(html: string, el: BindScope, dependencies: HtmlDep[], where?: WherePosition): Promise<ReturnType<typeof singletonsRenderHtml>>;
declare type HtmlDepVersion = string;
declare type MetaItem = {
name: string;
Expand Down
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
{
"declaration": true,
"compilerOptions": {
"target": "ES5",
"target": "es2020",
"isolatedModules": true,
"esModuleInterop": true,
"declaration": true,
"declarationDir": "./srcts/types",
"emitDeclarationOnly": true,
"moduleResolution": "node",
// Can not use `types: []` to disable injecting NodeJS types. More types are
// needed than just the DOM's `window.setTimeout`
// "types": [],
Expand Down

0 comments on commit 8dfd8f5

Please sign in to comment.