Skip to content

Commit

Permalink
feat: wait for init tasks (up to 1s) in preload UI
Browse files Browse the repository at this point in the history
  • Loading branch information
lideming committed Jun 20, 2023
1 parent 7c02edf commit 788d386
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 83 deletions.
108 changes: 49 additions & 59 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,90 +41,65 @@
margin: 10px 5px;
}

#preload-overlay p {
#preload-infos p {
margin: 10px 5px;
}

#preload-infos p.info {
color: gray;
}
#preload-infos p.error {
color: red;
}
</style>
<!-- Preload script which waits for main script loading and displays status -->
<script>
(function () {
var preload = (window.preload = {
domLoaded: false,
jsLoaded: false,
jsError: false,
preLoginTask: null,
inputToken: null,
jsOk() {
this.jsLoaded = true;
this.update();
},
onJsLoad() {
setTimeout(
function (thiz) {
if (!thiz.jsLoaded) {
console.error("js loaded without calling callback");
thiz.jsError = true;
thiz.update();
}
},
1000,
this
this,
);
},
update() {
if (!this.domLoaded) return;
document.getElementById("js-ok").hidden = !preload.jsLoaded;
document.getElementById("js-error").hidden = !preload.jsError;
document.getElementById("js-error-msg").hidden = !preload.jsError;
if (this.jsLoaded) this.end();
jsOk() {
preload.jsLoaded = true;
},
end() {
mcloud.ui.endPreload();
window.removeEventListener("error", onerror);
},
preLogin() {
// Try to prefetch the user info even before we can run the main script.
// Make it about 1 RTT + 50 ms (script download + execution time) faster.
var strLogin = localStorage.getItem("mcloud-login");
if (!strLogin) return;
var login = JSON.parse(strLogin);
if (!login || !login.token || !login.lastBaseUrl) return;
preload.preLoginTask = fetch(login.lastBaseUrl + "users/me", {
credentials: "same-origin",
headers: {
Authorization: "Bearer " + login.token,
"Cache-Control": "no-store",
},
}).then(function (resp) {
if (!resp.ok) {
throw new Error("HTTP status " + resp.status);
}
return resp.json();
});
},
});

window.addEventListener("DOMContentLoaded", function () {
preload.domLoaded = true;
preload.update();
// Set the theme ASAP to avoid blinking
const preferDark = window.matchMedia('(prefers-color-scheme: dark)');
const themeColor =
(localStorage.getItem("mcloud-theme") || '')
.split('-')[0];
// Set the theme ASAP to avoid blinking in dark mode
const themeColor = (
localStorage.getItem("mcloud-theme") || "auto"
).split("-")[0];
const dark =
themeColor === 'dark' ||
(themeColor === 'auto'
&& window.matchMedia('(prefers-color-scheme: dark)').matches)
themeColor === "dark" ||
(themeColor === "auto" &&
window.matchMedia("(prefers-color-scheme: dark)").matches);
if (dark) {
document.body.classList.add("dark");
document.getElementById("meta-theme-color").content = "black";
}
});

var onerror = function (e) {
preload.jsError = true;
document.getElementById("js-error-msg").textContent = "" + e.error;
preload.update();
const p = document.createElement("p");
p.className = "error";
p.textContent = "" + e.error;
document.getElementById("preload-infos").appendChild(p);
};
window.addEventListener("error", onerror);

var handleToken = function () {
var splits = window.location.href.split("#token=");
Expand All @@ -134,14 +109,34 @@
}
};

window.addEventListener("error", onerror);
var preLogin = function () {
// Try to prefetch the user info even before we can run the main script.
// Make it about 1 RTT + 50 ms (script download + execution time) faster.
var strLogin = localStorage.getItem("mcloud-login");
if (!strLogin) return;
var login = JSON.parse(strLogin);
if (!login || !login.token || !login.lastBaseUrl) return;
preload.preLoginTask = fetch(login.lastBaseUrl + "users/me", {
credentials: "same-origin",
headers: {
Authorization: "Bearer " + login.token,
"Cache-Control": "no-store",
},
}).then(function (resp) {
if (!resp.ok) {
throw new Error("HTTP status " + resp.status);
}
return resp.json();
});
};

handleToken();
preload.preLogin();
preLogin();
})();
</script>
<!-- End of preload style and script -->
<script
src="bundle.js?v=_BUILD_DATE_"
src="bundle.js?v={{BUILD_DATE}}"
onload="window.preload && preload.onJsLoad()"
defer
async
Expand All @@ -151,12 +146,7 @@
<body>
<div id="preload-overlay" lang="en">
<h1>MusicCloud</h1>
<div style="min-height: 6em">
<p>Loading...</p>
<p hidden style="color: gray" id="js-ok">JavaScript OK</p>
<p hidden style="color: red" id="js-error">JavaScript Error</p>
<p hidden id="js-error-msg"></p>
</div>
<div id="preload-infos" style="min-height: 100px"></div>
<noscript>
<p>JavaScript is required to run this application.</p>
</noscript>
Expand Down
2 changes: 1 addition & 1 deletion resources/overlay.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
<title>MusicCloud Overlay</title>
</head>
<body>
<script src="./overlay.bundle.js?v=_BUILD_DATE_"></script>
<script src="./overlay.bundle.js?v={{BUILD_DATE}}"></script>
</body>
</html>
2 changes: 1 addition & 1 deletion rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const rollupConfig = (args) => {
src: ["index.html", "resources/overlay.html"],
dest: "./dist/",
transform: (content, path) =>
content.toString().replace("_BUILD_DATE_", _buildDate),
content.toString().replace("{{BUILD_DATE}}", _buildDate),
},
{
src: ["resources/app_icon.svg", "resources/manifest.json"],
Expand Down
25 changes: 18 additions & 7 deletions src/Infra/UI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,19 +145,30 @@ export const ui = new (class {
Toast.show(I`Error:` + "\n" + e.reason, 5000);
});
}
endPreload() {
setTimeout(() => {
ui.mainContainer.dom.classList.remove("no-transition");
fadeout(document.getElementById("preload-overlay")!);
}, 1);
}
isVisible() {
return !document["hidden"];
}
updateAllViews() {
mainContainer.updateAll();
bottomBar.updateAll();
}
preload = new (class {
domInfos = document.getElementById("preload-infos");
jsok() {
window["preload"]?.jsOk();
}
log(text: string, type: "info" | "error") {
const p = new TextView({ tag: `p.${type}`, text });
if (this.domInfos) mountView(this.domInfos, p);
return p;
}
end() {
setTimeout(() => {
ui.mainContainer.dom.classList.remove("no-transition");
fadeout(document.getElementById("preload-overlay")!);
}, 1);
}
});
theme = new (class {
colors = ['light', 'dark', 'auto'] as const;
styles = ['', '-rounded'] as const;
Expand All @@ -168,7 +179,7 @@ export const ui = new (class {
siTheme = new SettingItem<this["current"]>(
"mcloud-theme",
"str",
"light-rounded"
"auto-rounded" // the default value should be sync with the preload script
);

init() {
Expand Down
27 changes: 16 additions & 11 deletions src/Plugins/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,16 @@ export const plugins = new (class Plugins {
revision: 0,
});
private loadedPlugin = new Map<string, PluginInfo>();
private promiseLoadingPlugins: Promise<void> | null = null;

init() {
user.waitLogin().then(() => {
this.loadUserPlguins();
});
this.promiseLoadingPlugins = user
.waitLogin()
.then(() => this.loadUserPlguins());
}

async waitPluginsLoading() {
await this.promiseLoadingPlugins;
}

async getUserPlugins() {
Expand All @@ -40,25 +45,23 @@ export const plugins = new (class Plugins {
}

async loadUserPlguins() {
const promises: Promise<any>[] = [];
for (const plugin of await this.getUserPlugins()) {
if (plugin.enabled) {
let loaded = false;
const loadingTask = this.loadPlugin(plugin.url).finally(() => {
loaded = true;
});
Promise.race([
sleepAsync(5000),
loadingTask,
]).then(() => {
promises.push(loadingTask);
Promise.race([sleepAsync(5000), loadingTask]).then(() => {
if (!loaded) {
const toast = Toast.show(
I`Plugin "${plugin.name}" loading...`,
);
const toast = Toast.show(I`Plugin "${plugin.name}" loading...`);
loadingTask.finally(() => toast.close());
}
});
}
}
await Promise.allSettled(promises);
}

async addUserPlugin(url: string) {
Expand Down Expand Up @@ -96,7 +99,9 @@ export const plugins = new (class Plugins {
await this.userPluginList.concurrencyAwareUpdate((value) => {
return {
...value,
plugins: value.plugins.map((x) => x.url == url ? { ...x, enabled } : x),
plugins: value.plugins.map((x) =>
x.url == url ? { ...x, enabled } : x,
),
};
});
}
Expand Down
22 changes: 18 additions & 4 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,24 @@ function init() {
plugins.init();
infoProvider.init(playerCore);
console.timeEnd("[Main] app init()");

waitInitialLoading();
}

async function waitInitialLoading() {
try {
ui.preload.jsok();
const stateText = ui.preload.log("Logging in...", "info");
await Promise.race([
webfx.sleepAsync(1000),
user
.waitLogin(false)
.then(() => stateText.text = "Loading plugins...")
.then(() => plugins.waitPluginsLoading()),
]);
} finally {
ui.preload.end();
}
}

function checkMode() {
Expand Down Expand Up @@ -117,7 +135,3 @@ export {
};

init();

Promise.resolve().then(() => {
window["preload"]?.jsOk();
});

1 comment on commit 788d386

@vercel
Copy link

@vercel vercel bot commented on 788d386 Jun 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

music-cloud – ./

music-cloud-lideming.vercel.app
music-cloud-git-master-lideming.vercel.app

Please sign in to comment.