Improved client entry handling
parent
30357018c4
commit
7a97a74cd5
|
@ -0,0 +1,8 @@
|
||||||
|
interface Window {
|
||||||
|
__native_client_init_hook: () => void;
|
||||||
|
__native_client_init_shared: (webpackRequire: any) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare const __webpack_require__;
|
||||||
|
declare const __teaclient_preview_notice: any;
|
||||||
|
declare const __teaclient_preview_error: any;
|
|
@ -1,7 +1,4 @@
|
||||||
declare const __webpack_require__;
|
window.__native_client_init_shared(__webpack_require__);
|
||||||
window["shared-require"] = __webpack_require__;
|
|
||||||
|
|
||||||
import "./index.scss";
|
import "./index.scss";
|
||||||
|
import "tc-shared/main";
|
||||||
/* firstly assign the shared-require */
|
|
||||||
setTimeout(() => require("tc-shared/main"), 0);
|
|
|
@ -42,6 +42,8 @@ export type Task = {
|
||||||
function: (taskId?: number) => Promise<void>
|
function: (taskId?: number) => Promise<void>
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type InternalTask = Task & { initiator: string }
|
||||||
|
|
||||||
export enum Stage {
|
export enum Stage {
|
||||||
/*
|
/*
|
||||||
loading loader required files (incl this)
|
loading loader required files (incl this)
|
||||||
|
@ -88,7 +90,7 @@ export enum Stage {
|
||||||
|
|
||||||
let cache_tag: string | undefined;
|
let cache_tag: string | undefined;
|
||||||
let currentStage: Stage = undefined;
|
let currentStage: Stage = undefined;
|
||||||
const tasks: {[key:number]:Task[]} = {};
|
const tasks: {[key:number]: InternalTask[]} = {};
|
||||||
|
|
||||||
/* test if all files shall be load from cache or fetch again */
|
/* test if all files shall be load from cache or fetch again */
|
||||||
function loader_cache_tag() {
|
function loader_cache_tag() {
|
||||||
|
@ -129,18 +131,23 @@ export function finished() {
|
||||||
export function running() { return typeof(currentStage) !== "undefined"; }
|
export function running() { return typeof(currentStage) !== "undefined"; }
|
||||||
|
|
||||||
export function register_task(stage: Stage, task: Task) {
|
export function register_task(stage: Stage, task: Task) {
|
||||||
|
let callee = new Error().stack.split("\n")[2].replace(/^\s*at (Object\.\.\/)?/, "");
|
||||||
|
if(callee.match(/^.* \(([:\\/_\-+0-9a-zA-Z.]+):([0-9]+):([0-9]+)\)$/)) {
|
||||||
|
callee = callee.replace(/^.* \(([:\\/_\-+0-9a-zA-Z.]+):([0-9]+):([0-9]+)\)$/, "$1:$2:$3");
|
||||||
|
}
|
||||||
if(!task.function) {
|
if(!task.function) {
|
||||||
debugger;
|
debugger;
|
||||||
throw "tried to register a loader task without a function";
|
throw "tried to register a loader task without a function at " + callee;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(currentStage > stage) {
|
if(currentStage > stage) {
|
||||||
if(config.error)
|
if(config.error) {
|
||||||
console.warn("Register loading task, but it had already been finished. Executing task anyways!");
|
console.warn("Register loading task, but it had already been finished. Executing task anyways! Registerer: %s", callee);
|
||||||
|
}
|
||||||
|
|
||||||
const promise = task.function();
|
const promise = task.function();
|
||||||
if(!promise) {
|
if(!promise) {
|
||||||
console.error("Loading task %s hasn't returned a promise!", task.name);
|
console.error("Loading task %s (%s) hasn't returned a promise!", task.name, callee);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
promise.catch(error => {
|
promise.catch(error => {
|
||||||
|
@ -155,7 +162,9 @@ export function register_task(stage: Stage, task: Task) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const task_array = tasks[stage] || [];
|
const task_array = tasks[stage] || [];
|
||||||
task_array.push(task);
|
task_array.push(Object.assign({
|
||||||
|
initiator: callee
|
||||||
|
}, task));
|
||||||
tasks[stage] = task_array.sort((a, b) => a.priority - b.priority);
|
tasks[stage] = task_array.sort((a, b) => a.priority - b.priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +199,7 @@ export async function execute() {
|
||||||
let end: number = Date.now();
|
let end: number = Date.now();
|
||||||
while(currentStage <= Stage.LOADED || typeof(currentStage) === "undefined") {
|
while(currentStage <= Stage.LOADED || typeof(currentStage) === "undefined") {
|
||||||
|
|
||||||
let pendingTasks: Task[] = [];
|
let pendingTasks: InternalTask[] = [];
|
||||||
while((tasks[currentStage] || []).length > 0) {
|
while((tasks[currentStage] || []).length > 0) {
|
||||||
if(pendingTasks.length == 0 || pendingTasks[0].priority == tasks[currentStage][0].priority) {
|
if(pendingTasks.length == 0 || pendingTasks[0].priority == tasks[currentStage][0].priority) {
|
||||||
pendingTasks.push(tasks[currentStage].pop());
|
pendingTasks.push(tasks[currentStage].pop());
|
||||||
|
@ -199,7 +208,7 @@ export async function execute() {
|
||||||
|
|
||||||
const errors: {
|
const errors: {
|
||||||
error: any,
|
error: any,
|
||||||
task: Task
|
task: InternalTask
|
||||||
}[] = [];
|
}[] = [];
|
||||||
|
|
||||||
for(const task of pendingTasks) {
|
for(const task of pendingTasks) {
|
||||||
|
@ -210,8 +219,9 @@ export async function execute() {
|
||||||
} as RunningTask;
|
} as RunningTask;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if(config.verbose)
|
if(config.verbose) {
|
||||||
console.debug("Executing loader %s (%d)", task.name, task.priority);
|
console.debug("Executing loader %s (%d)", task.name, task.priority);
|
||||||
|
}
|
||||||
|
|
||||||
runningTasks.push(rTask);
|
runningTasks.push(rTask);
|
||||||
const promise = task.function(rTask.taskId);
|
const promise = task.function(rTask.taskId);
|
||||||
|
@ -256,9 +266,11 @@ export async function execute() {
|
||||||
if(errors.length > 0) {
|
if(errors.length > 0) {
|
||||||
if(config.loader_groups)
|
if(config.loader_groups)
|
||||||
console.groupEnd();
|
console.groupEnd();
|
||||||
|
|
||||||
console.error("Failed to execute loader. The following tasks failed (%d):", errors.length);
|
console.error("Failed to execute loader. The following tasks failed (%d):", errors.length);
|
||||||
for(const error of errors)
|
for(const error of errors) {
|
||||||
console.error(" - %s: %o", error.task.name, error.error);
|
console.error(" - %s (%s): %o", error.task.name, error.task.initiator, error.error);
|
||||||
|
}
|
||||||
|
|
||||||
throw "failed to process step " + Stage[currentStage];
|
throw "failed to process step " + Stage[currentStage];
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,23 +10,8 @@ declare global {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function cache_tag() {
|
function getCacheTag() {
|
||||||
const ui = ui_version();
|
return "?_ts=" + (__build.mode === "debug" ? Date.now() : __build.timestamp);
|
||||||
return "?_ts=" + (!!ui && ui !== "unknown" ? ui : Date.now());
|
|
||||||
}
|
|
||||||
|
|
||||||
let _ui_version;
|
|
||||||
export function ui_version() {
|
|
||||||
if(typeof(_ui_version) !== "string") {
|
|
||||||
const version_node = document.getElementById("app_version");
|
|
||||||
if(!version_node) return undefined;
|
|
||||||
|
|
||||||
const version = version_node.hasAttribute("value") ? version_node.getAttribute("value") : undefined;
|
|
||||||
if(!version) return undefined;
|
|
||||||
|
|
||||||
return (_ui_version = version);
|
|
||||||
}
|
|
||||||
return _ui_version;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const LoaderTaskCallback = taskId => (script: SourcePath, state) => {
|
const LoaderTaskCallback = taskId => (script: SourcePath, state) => {
|
||||||
|
@ -101,7 +86,7 @@ loader.register_task(loader.Stage.TEMPLATES, {
|
||||||
"templates/modal/musicmanage.html",
|
"templates/modal/musicmanage.html",
|
||||||
"templates/modal/newcomer.html",
|
"templates/modal/newcomer.html",
|
||||||
], {
|
], {
|
||||||
cache_tag: cache_tag(),
|
cache_tag: getCacheTag(),
|
||||||
max_parallel_requests: -1
|
max_parallel_requests: -1
|
||||||
}, LoaderTaskCallback(taskId));
|
}, LoaderTaskCallback(taskId));
|
||||||
},
|
},
|
||||||
|
@ -154,7 +139,6 @@ loader.register_task(loader.Stage.SETUP, {
|
||||||
loader.register_task(loader.Stage.SETUP, {
|
loader.register_task(loader.Stage.SETUP, {
|
||||||
name: "TeaClient tester",
|
name: "TeaClient tester",
|
||||||
function: async () => {
|
function: async () => {
|
||||||
//@ts-ignore
|
|
||||||
if(typeof __teaclient_preview_notice !== "undefined" && typeof __teaclient_preview_error !== "undefined") {
|
if(typeof __teaclient_preview_notice !== "undefined" && typeof __teaclient_preview_error !== "undefined") {
|
||||||
loader.critical_error("Why you're opening TeaWeb within the TeaSpeak client?!");
|
loader.critical_error("Why you're opening TeaWeb within the TeaSpeak client?!");
|
||||||
throw "we're already a TeaClient!";
|
throw "we're already a TeaClient!";
|
||||||
|
@ -165,34 +149,6 @@ loader.register_task(loader.Stage.SETUP, {
|
||||||
|
|
||||||
export default class implements ApplicationLoader {
|
export default class implements ApplicationLoader {
|
||||||
execute() {
|
execute() {
|
||||||
/* TeaClient */
|
|
||||||
if(window.require) {
|
|
||||||
if(__build.target !== "client") {
|
|
||||||
loader.critical_error("App seems not to be compiled for the client.", "This app has been compiled for " + __build.target);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
window.native_client = true;
|
|
||||||
|
|
||||||
const path = __non_webpack_require__("path");
|
|
||||||
const remote = __non_webpack_require__('electron').remote;
|
|
||||||
|
|
||||||
const render_entry = path.join(remote.app.getAppPath(), "/modules/", "renderer");
|
|
||||||
const render = __non_webpack_require__(render_entry);
|
|
||||||
|
|
||||||
loader.register_task(loader.Stage.INITIALIZING, {
|
|
||||||
name: "teaclient initialize",
|
|
||||||
function: render.initialize,
|
|
||||||
priority: 40
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if(__build.target !== "web") {
|
|
||||||
loader.critical_error("App seems not to be compiled for the web.", "This app has been compiled for " + __build.target);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
window.native_client = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
loader.execute_managed();
|
loader.execute_managed();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,97 +0,0 @@
|
||||||
import * as loader from "../loader/loader";
|
|
||||||
|
|
||||||
let is_debug = false;
|
|
||||||
|
|
||||||
/* all javascript loaders */
|
|
||||||
const loader_javascript = {
|
|
||||||
detect_type: async () => {
|
|
||||||
/* test if js/proto.js is available. If so we're in debug mode */
|
|
||||||
const request = new XMLHttpRequest();
|
|
||||||
request.open('GET', 'js/proto.js', true);
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
request.onreadystatechange = () => {
|
|
||||||
if (request.readyState === 4){
|
|
||||||
is_debug = request.status !== 404;
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
request.onerror = () => {
|
|
||||||
reject("Failed to detect app type");
|
|
||||||
};
|
|
||||||
request.send();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
load_scripts: async () => {
|
|
||||||
await loader.scripts.load_multiple(["vendor/jquery/jquery.min.js"], {});
|
|
||||||
await loader.scripts.load_multiple([
|
|
||||||
["dist/certificate-popup.js"],
|
|
||||||
], {});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const loader_style = {
|
|
||||||
load_style: async () => {
|
|
||||||
if(is_debug) {
|
|
||||||
await loader_style.load_style_debug();
|
|
||||||
} else {
|
|
||||||
await loader_style.load_style_release();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
load_style_debug: async () => {
|
|
||||||
await loader.style.load_multiple([
|
|
||||||
"css/static/main.css",
|
|
||||||
], {});
|
|
||||||
},
|
|
||||||
|
|
||||||
load_style_release: async () => {
|
|
||||||
await loader.style.load_multiple([
|
|
||||||
"css/static/main.css",
|
|
||||||
], {});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
loader.register_task(loader.Stage.INITIALIZING, {
|
|
||||||
name: "app type test",
|
|
||||||
function: loader_javascript.detect_type,
|
|
||||||
priority: 20
|
|
||||||
});
|
|
||||||
|
|
||||||
loader.register_task(loader.Stage.JAVASCRIPT, {
|
|
||||||
name: "javascript",
|
|
||||||
function: loader_javascript.load_scripts,
|
|
||||||
priority: 10
|
|
||||||
});
|
|
||||||
|
|
||||||
loader.register_task(loader.Stage.STYLE, {
|
|
||||||
name: "style",
|
|
||||||
function: loader_style.load_style,
|
|
||||||
priority: 10
|
|
||||||
});
|
|
||||||
|
|
||||||
/* register tasks */
|
|
||||||
loader.register_task(loader.Stage.INITIALIZING, {
|
|
||||||
name: "safari fix",
|
|
||||||
function: async () => {
|
|
||||||
/* safari remove "fix" */
|
|
||||||
if(Element.prototype.remove === undefined)
|
|
||||||
Object.defineProperty(Element.prototype, "remove", {
|
|
||||||
enumerable: false,
|
|
||||||
configurable: false,
|
|
||||||
writable: false,
|
|
||||||
value: function(){
|
|
||||||
this.parentElement.removeChild(this);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
priority: 50
|
|
||||||
});
|
|
||||||
|
|
||||||
if(!loader.running()) {
|
|
||||||
/* we know that we want to load the app */
|
|
||||||
loader.execute_managed();
|
|
||||||
}
|
|
||||||
|
|
||||||
export = {};
|
|
|
@ -5,8 +5,6 @@ import {loadManifest, loadManifestTarget} from "../maifest";
|
||||||
import {getUrlParameter} from "../loader/utils";
|
import {getUrlParameter} from "../loader/utils";
|
||||||
|
|
||||||
export default class implements ApplicationLoader {
|
export default class implements ApplicationLoader {
|
||||||
|
|
||||||
|
|
||||||
execute() {
|
execute() {
|
||||||
loader.register_task(Stage.SETUP, {
|
loader.register_task(Stage.SETUP, {
|
||||||
function: async taskId => {
|
function: async taskId => {
|
||||||
|
@ -67,26 +65,6 @@ export default class implements ApplicationLoader {
|
||||||
priority: 10
|
priority: 10
|
||||||
});
|
});
|
||||||
|
|
||||||
if(__build.target === "client") {
|
|
||||||
loader.register_task(Stage.SETUP, {
|
|
||||||
name: "native setup",
|
|
||||||
function: async () => {
|
|
||||||
const path = __non_webpack_require__("path");
|
|
||||||
const remote = __non_webpack_require__('electron').remote;
|
|
||||||
|
|
||||||
const render_entry = path.join(remote.app.getAppPath(), "/modules/", "renderer-manifest", "index");
|
|
||||||
const render = __non_webpack_require__(render_entry);
|
|
||||||
|
|
||||||
loader.register_task(loader.Stage.SETUP, {
|
|
||||||
name: "teaclient setup",
|
|
||||||
function: async () => await render.initialize(getUrlParameter("chunk")),
|
|
||||||
priority: 40
|
|
||||||
});
|
|
||||||
},
|
|
||||||
priority: 50
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
loader.execute_managed();
|
loader.execute_managed();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +1,6 @@
|
||||||
import * as loader from "../loader/loader";
|
import * as loader from "../loader/loader";
|
||||||
import {Stage} from "../loader/loader";
|
import {Stage} from "../loader/loader";
|
||||||
import {
|
import {BrowserInfo, detect as detectBrowser,} from "detect-browser";
|
||||||
BrowserInfo,
|
|
||||||
detect as detectBrowser,
|
|
||||||
} from "detect-browser";
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
|
@ -12,6 +9,30 @@ declare global {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loader.register_task(Stage.SETUP, {
|
||||||
|
name: "app init",
|
||||||
|
function: async () => {
|
||||||
|
/* TeaClient */
|
||||||
|
if(window.require || window.__native_client_init_hook) {
|
||||||
|
if(__build.target !== "client") {
|
||||||
|
loader.critical_error("App seems not to be compiled for the client.", "This app has been compiled for " + __build.target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.__native_client_init_hook();
|
||||||
|
window.native_client = true;
|
||||||
|
} else {
|
||||||
|
if(__build.target !== "web") {
|
||||||
|
loader.critical_error("App seems not to be compiled for the web.", "This app has been compiled for " + __build.target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.native_client = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
priority: 1000
|
||||||
|
});
|
||||||
|
|
||||||
if(__build.target === "web") {
|
if(__build.target === "web") {
|
||||||
loader.register_task(Stage.SETUP, {
|
loader.register_task(Stage.SETUP, {
|
||||||
name: "outdated browser checker",
|
name: "outdated browser checker",
|
||||||
|
|
|
@ -15,6 +15,10 @@ import {setupJSRender} from "../../../ui/jsrender";
|
||||||
import "../../../file/RemoteAvatars";
|
import "../../../file/RemoteAvatars";
|
||||||
import "../../../file/RemoteIcons";
|
import "../../../file/RemoteIcons";
|
||||||
|
|
||||||
|
if("__native_client_init_shared" in window) {
|
||||||
|
window.__native_client_init_shared(__webpack_require__);
|
||||||
|
}
|
||||||
|
|
||||||
let modalRenderer: ModalRenderer;
|
let modalRenderer: ModalRenderer;
|
||||||
let modalInstance: AbstractModal;
|
let modalInstance: AbstractModal;
|
||||||
let modalClass: new (events: RegistryMap, userData: any) => AbstractModal;
|
let modalClass: new (events: RegistryMap, userData: any) => AbstractModal;
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
@import "../../../css/static/mixin";
|
|
||||||
|
|
||||||
.globalContainer {
|
.globalContainer {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -140,7 +138,8 @@
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
|
|
||||||
@include user-select(none);
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
|
||||||
/* Hide the browser's default checkbox */
|
/* Hide the browser's default checkbox */
|
||||||
input {
|
input {
|
||||||
|
|
|
@ -16,8 +16,10 @@ export = () => config_base.config("client").then(config => {
|
||||||
throw "invalid config";
|
throw "invalid config";
|
||||||
|
|
||||||
config.externals.push((context, request, callback) => {
|
config.externals.push((context, request, callback) => {
|
||||||
if (request.startsWith("tc-backend/"))
|
if (request.startsWith("tc-backend/")) {
|
||||||
return callback(null, `window["backend-loader"].require("${request}")`);
|
return callback(null, `window["backend-loader"].require("${request}")`);
|
||||||
|
}
|
||||||
|
|
||||||
callback(undefined, undefined);
|
callback(undefined, undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue