add "timeline" system for measuring app start performance
This commit is contained in:
parent
be560e5510
commit
17e086769d
8 changed files with 72 additions and 1 deletions
|
@ -1,6 +1,7 @@
|
||||||
import gateway, { GatewayEventType } from "./gateway";
|
import gateway, { GatewayEventType } from "./gateway";
|
||||||
import { removeItem, setItem } from "./storage";
|
import { removeItem, setItem } from "./storage";
|
||||||
import { overlayStore, OverlayType } from "./stores";
|
import { overlayStore, OverlayType } from "./stores";
|
||||||
|
import { timeline } from "./timeline";
|
||||||
|
|
||||||
export function useAuthHandlers() {
|
export function useAuthHandlers() {
|
||||||
gateway.subscribe(GatewayEventType.Ready, () => {
|
gateway.subscribe(GatewayEventType.Ready, () => {
|
||||||
|
@ -14,6 +15,7 @@ export function useAuthHandlers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function authWithToken(token, shouldUpdate=false) {
|
export function authWithToken(token, shouldUpdate=false) {
|
||||||
|
timeline.addCheckpoint("Authentication started (authWithToken)");
|
||||||
if (shouldUpdate)
|
if (shouldUpdate)
|
||||||
setItem("auth:token", token);
|
setItem("auth:token", token);
|
||||||
gateway.init(token);
|
gateway.init(token);
|
||||||
|
|
|
@ -1,9 +1,19 @@
|
||||||
<script>
|
<script>
|
||||||
|
import { afterUpdate, beforeUpdate } from "svelte";
|
||||||
import { showSidebar, selectedChannel, smallViewport, showChannelView, theme, showPresenceSidebar } from "../stores";
|
import { showSidebar, selectedChannel, smallViewport, showChannelView, theme, showPresenceSidebar } from "../stores";
|
||||||
|
import { timeline } from "../timeline";
|
||||||
import ChannelView from "./ChannelView.svelte";
|
import ChannelView from "./ChannelView.svelte";
|
||||||
import OverlayProvider from "./overlays/OverlayProvider.svelte";
|
import OverlayProvider from "./overlays/OverlayProvider.svelte";
|
||||||
import PresenceSidebar from "./PresenceSidebar.svelte";
|
import PresenceSidebar from "./PresenceSidebar.svelte";
|
||||||
import Sidebar from "./Sidebar.svelte";
|
import Sidebar from "./Sidebar.svelte";
|
||||||
|
|
||||||
|
beforeUpdate(() => {
|
||||||
|
timeline.addCheckpoint("Main component update start");
|
||||||
|
});
|
||||||
|
|
||||||
|
afterUpdate(() => {
|
||||||
|
timeline.addCheckpoint("Main component update end");
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
|
|
|
@ -2,6 +2,7 @@ import gateway from './gateway';
|
||||||
import { getItem, init, setItem, removeItem } from './storage';
|
import { getItem, init, setItem, removeItem } from './storage';
|
||||||
import { allStores } from './stores';
|
import { allStores } from './stores';
|
||||||
import { authWithToken, logOut } from './auth';
|
import { authWithToken, logOut } from './auth';
|
||||||
|
import { timeline } from './timeline';
|
||||||
|
|
||||||
export function useDebuggingApi() {
|
export function useDebuggingApi() {
|
||||||
window.__waffle = {
|
window.__waffle = {
|
||||||
|
@ -16,6 +17,7 @@ export function useDebuggingApi() {
|
||||||
authWithToken,
|
authWithToken,
|
||||||
logOut
|
logOut
|
||||||
},
|
},
|
||||||
|
timeline,
|
||||||
stores: allStores,
|
stores: allStores,
|
||||||
app: null
|
app: null
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import logger from "./logging";
|
import logger from "./logging";
|
||||||
import { getItem } from "./storage";
|
import { getItem } from "./storage";
|
||||||
|
import { timeline } from "./timeline";
|
||||||
|
|
||||||
export const GatewayErrors = {
|
export const GatewayErrors = {
|
||||||
BAD_PAYLOAD: 4001,
|
BAD_PAYLOAD: 4001,
|
||||||
|
@ -58,6 +59,7 @@ export default {
|
||||||
handlers: new Map(),
|
handlers: new Map(),
|
||||||
disableReconnect: false,
|
disableReconnect: false,
|
||||||
init(token) {
|
init(token) {
|
||||||
|
timeline.addCheckpoint("Gateway connection start");
|
||||||
if (!token) {
|
if (!token) {
|
||||||
log("no auth token, skipping connection");
|
log("no auth token, skipping connection");
|
||||||
this.dispatch(GatewayEventType.Close, GatewayErrors.BAD_AUTH);
|
this.dispatch(GatewayEventType.Close, GatewayErrors.BAD_AUTH);
|
||||||
|
@ -67,6 +69,7 @@ export default {
|
||||||
log(`connecting to gateway - gatewayBase: ${getItem("server:gatewayBase")}`);
|
log(`connecting to gateway - gatewayBase: ${getItem("server:gatewayBase")}`);
|
||||||
this.ws = new WebSocket(getItem("server:gatewayBase"));
|
this.ws = new WebSocket(getItem("server:gatewayBase"));
|
||||||
this.ws.onopen = () => {
|
this.ws.onopen = () => {
|
||||||
|
timeline.addCheckpoint("Gateway connection open");
|
||||||
if (this.reconnectTimeout) {
|
if (this.reconnectTimeout) {
|
||||||
clearTimeout(this.reconnectTimeout);
|
clearTimeout(this.reconnectTimeout);
|
||||||
}
|
}
|
||||||
|
@ -80,6 +83,7 @@ export default {
|
||||||
|
|
||||||
switch (payload.t) {
|
switch (payload.t) {
|
||||||
case GatewayPayloadType.Hello: {
|
case GatewayPayloadType.Hello: {
|
||||||
|
timeline.addCheckpoint("Gateway hello");
|
||||||
this.send({
|
this.send({
|
||||||
t: GatewayPayloadType.Authenticate,
|
t: GatewayPayloadType.Authenticate,
|
||||||
d: {
|
d: {
|
||||||
|
@ -98,6 +102,8 @@ export default {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GatewayPayloadType.Ready: {
|
case GatewayPayloadType.Ready: {
|
||||||
|
timeline.addCheckpoint("Gateway ready");
|
||||||
|
|
||||||
this.user = payload.d.user;
|
this.user = payload.d.user;
|
||||||
this.channels = payload.d.channels;
|
this.channels = payload.d.channels;
|
||||||
|
|
||||||
|
@ -111,6 +117,7 @@ export default {
|
||||||
this.dispatch(payload.t, payload.d);
|
this.dispatch(payload.t, payload.d);
|
||||||
};
|
};
|
||||||
this.ws.onclose = ({ code }) => {
|
this.ws.onclose = ({ code }) => {
|
||||||
|
timeline.addCheckpoint("Gateway close");
|
||||||
this.authenticated = false;
|
this.authenticated = false;
|
||||||
this.user = null;
|
this.user = null;
|
||||||
this.channels = null;
|
this.channels = null;
|
||||||
|
|
|
@ -11,3 +11,11 @@ export default function logger(sink) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function tableLogger(sink) {
|
||||||
|
return (...args) => {
|
||||||
|
if (getItem(`log:${sink}`)) {
|
||||||
|
console.table(...args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -7,8 +7,13 @@ import gateway, { GatewayEventType } from './gateway';
|
||||||
import { pluginStore } from './stores';
|
import { pluginStore } from './stores';
|
||||||
|
|
||||||
import "@material-design-icons/font";
|
import "@material-design-icons/font";
|
||||||
|
import { timeline } from './timeline';
|
||||||
|
|
||||||
|
timeline.start();
|
||||||
|
|
||||||
function handleGatewaySettlement() {
|
function handleGatewaySettlement() {
|
||||||
|
timeline.addCheckpoint("Got gateway settlement");
|
||||||
|
|
||||||
const loadingElement = document.getElementById("pre--loading-screen");
|
const loadingElement = document.getElementById("pre--loading-screen");
|
||||||
if (loadingElement) {
|
if (loadingElement) {
|
||||||
loadingElement.parentElement.removeChild(loadingElement);
|
loadingElement.parentElement.removeChild(loadingElement);
|
||||||
|
@ -19,6 +24,8 @@ function handleGatewaySettlement() {
|
||||||
});
|
});
|
||||||
window.__waffle.app = app;
|
window.__waffle.app = app;
|
||||||
|
|
||||||
|
timeline.addCheckpoint("Created application");
|
||||||
|
|
||||||
pluginStore.consumePluginLoaders();
|
pluginStore.consumePluginLoaders();
|
||||||
const scripts = getItem("app:javascript");
|
const scripts = getItem("app:javascript");
|
||||||
scripts.forEach((script) => {
|
scripts.forEach((script) => {
|
||||||
|
@ -32,11 +39,17 @@ function handleGatewaySettlement() {
|
||||||
document.head.appendChild(style);
|
document.head.appendChild(style);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
timeline.addCheckpoint("Loaded custom user content");
|
||||||
|
|
||||||
gateway.unsubscribe(GatewayEventType.Ready, handleGatewaySettlement);
|
gateway.unsubscribe(GatewayEventType.Ready, handleGatewaySettlement);
|
||||||
gateway.unsubscribe(GatewayEventType.Close, handleGatewaySettlement);
|
gateway.unsubscribe(GatewayEventType.Close, handleGatewaySettlement);
|
||||||
|
|
||||||
|
timeline.addCheckpoint("All initialization finished");
|
||||||
|
timeline.dump();
|
||||||
}
|
}
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
|
timeline.addCheckpoint("Main reached");
|
||||||
useDebuggingApi();
|
useDebuggingApi();
|
||||||
useAuthHandlers();
|
useAuthHandlers();
|
||||||
initResponsiveHandlers();
|
initResponsiveHandlers();
|
||||||
|
|
|
@ -8,6 +8,7 @@ const defaults = {
|
||||||
"log:Gateway": false,
|
"log:Gateway": false,
|
||||||
"log:Store": false,
|
"log:Store": false,
|
||||||
"log:Messages": false,
|
"log:Messages": false,
|
||||||
|
"log:Timeline": false,
|
||||||
"ui:stateful:presistSelectedChannel": true,
|
"ui:stateful:presistSelectedChannel": true,
|
||||||
"ui:showSidebarToggle": false,
|
"ui:showSidebarToggle": false,
|
||||||
"ui:alwaysUseMobileChatBar": false,
|
"ui:alwaysUseMobileChatBar": false,
|
||||||
|
|
28
frontend/src/timeline.js
Normal file
28
frontend/src/timeline.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { tableLogger } from "./logging";
|
||||||
|
|
||||||
|
export class Timeline {
|
||||||
|
constructor() {
|
||||||
|
this.startedAt = -1;
|
||||||
|
this.checkpoints = [];
|
||||||
|
this.logger = tableLogger("Timeline");
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
this.startedAt = performance.now();
|
||||||
|
this.checkpoints.push({
|
||||||
|
offset: 0,
|
||||||
|
label: "Timeline Started"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addCheckpoint(label) {
|
||||||
|
const offset = performance.now() - this.startedAt;
|
||||||
|
this.checkpoints.push({ offset, label });
|
||||||
|
}
|
||||||
|
|
||||||
|
dump() {
|
||||||
|
this.logger(this.checkpoints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const timeline = new Timeline();
|
Loading…
Reference in a new issue