Skip to content

Commit

Permalink
Reduce bundlesize - lazy loading for Settings, Advanced share deck, c…
Browse files Browse the repository at this point in the history
…omponent catalog, luxon date libraryr (#22)
  • Loading branch information
kubk authored Mar 9, 2024
1 parent 5df00ee commit a799d1a
Show file tree
Hide file tree
Showing 11 changed files with 226 additions and 29 deletions.
9 changes: 0 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
"mobx-log": "^2.2.3",
"mobx-persist-store": "^1.1.3",
"mobx-react-lite": "^4.0.5",
"mobx-utils": "^6.0.8",
"react": "^18.2.0",
"react-content-loader": "^6.2.1",
"react-dom": "^18.2.0",
Expand Down
131 changes: 131 additions & 0 deletions src/lib/mobx-from-promise/from-promise.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Copied from mobx-utils because it doesn't support tree shaking
/* eslint-disable */
import { action, extendObservable } from "mobx";
import { assert } from "../typescript/assert";

export const PENDING = "pending";
export const FULFILLED = "fulfilled";
export const REJECTED = "rejected";

type CaseHandlers<U, T> = {
pending?: (t?: T) => U;
fulfilled?: (t: T) => U;
rejected?: (e: any) => U;
};

export interface IBasePromiseBasedObservable<T> extends PromiseLike<T> {
isPromiseBasedObservable: true;
case<U>(handlers: CaseHandlers<U, T>, defaultFulfilled?: boolean): U;
}

export type IPendingPromise<T> = {
readonly state: "pending";
readonly value: T | undefined;
};

export type IFulfilledPromise<T> = {
readonly state: "fulfilled";
readonly value: T;
};

export type IRejectedPromise = {
readonly state: "rejected";
readonly value: unknown;
};

export type IPromiseBasedObservable<T> = IBasePromiseBasedObservable<T> &
(IPendingPromise<T> | IFulfilledPromise<T> | IRejectedPromise);

function caseImpl<U, T>(
this: IPromiseBasedObservable<T>,
handlers: CaseHandlers<U, T>,
): U | T | undefined {
switch (this.state) {
case PENDING:
return handlers.pending && handlers.pending(this.value);
case REJECTED:
return handlers.rejected && handlers.rejected(this.value);
case FULFILLED:
return handlers.fulfilled ? handlers.fulfilled(this.value) : this.value;
}
}

export function fromPromise<T>(
origPromise: PromiseLike<T>,
oldPromise?: IPromiseBasedObservable<T>,
): IPromiseBasedObservable<T> {
assert(arguments.length <= 2, "fromPromise expects up to two arguments");
assert(
typeof origPromise === "function" ||
(typeof origPromise === "object" &&
origPromise &&
typeof origPromise.then === "function"),
"Please pass a promise or function to fromPromise",
);
if ((origPromise as any).isPromiseBasedObservable === true)
return origPromise as any;

if (typeof origPromise === "function") {
// If it is a (reject, resolve function, wrap it)
origPromise = new Promise(origPromise as any);
}

const promise = origPromise as any;
origPromise.then(
action("observableFromPromise-resolve", (value: any) => {
promise.value = value;
promise.state = FULFILLED;
}),
action("observableFromPromise-reject", (reason: any) => {
promise.value = reason;
promise.state = REJECTED;
}),
);

promise.isPromiseBasedObservable = true;
promise.case = caseImpl;
const oldData =
oldPromise &&
(oldPromise.state === FULFILLED || oldPromise.state === PENDING)
? oldPromise.value
: undefined;
extendObservable(
promise,
{
value: oldData,
state: PENDING,
},
{},
{ deep: false },
);

return promise;
}
export namespace fromPromise {
export const reject = action("fromPromise.reject", function <
T,
>(reason: any): IRejectedPromise & IBasePromiseBasedObservable<T> {
const p: any = fromPromise(Promise.reject(reason));
p.state = REJECTED;
p.value = reason;
return p;
});

function resolveBase<T>(
value: T,
): IFulfilledPromise<T> & IBasePromiseBasedObservable<T>;
function resolveBase<T>(
value?: T,
): IFulfilledPromise<T | undefined> & IBasePromiseBasedObservable<T>;
function resolveBase<T>(
value: T | undefined = undefined,
): IFulfilledPromise<T | undefined> &
IBasePromiseBasedObservable<T | undefined> {
const p: any = fromPromise(Promise.resolve(value));
p.state = FULFILLED;
p.value = value;
return p;
}

export const resolve = action("fromPromise.resolve", resolveBase);
}
25 changes: 10 additions & 15 deletions src/screens/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import { DeckFormStoreProvider } from "./deck-form/store/deck-form-store-context
import { QuickAddCardFormPage } from "./deck-form/quick-add-card-form-page.tsx";
import { VersionWarning } from "./shared/version-warning.tsx";
import React from "react";
import { UserSettingsStoreProvider } from "./user-settings/store/user-settings-store-context.tsx";
import { UserSettingsMain } from "./user-settings/user-settings-main.tsx";
import { deckListStore } from "../store/deck-list-store.ts";
import { FullScreenLoader } from "../ui/full-screen-loader.tsx";
import {
Expand All @@ -21,14 +19,17 @@ import { DeckCatalog } from "./deck-catalog/deck-catalog.tsx";
import { DeckOrFolderChoose } from "./deck-or-folder-choose/deck-or-folder-choose.tsx";
import { FolderForm } from "./folder-form/folder-form.tsx";
import { DeckCatalogStoreContextProvider } from "./deck-catalog/store/deck-catalog-store-context.tsx";
import { ShareDeckScreen } from "./share-deck/share-deck-screen.tsx";
import { ShareDeckOrFormStoreProvider } from "./share-deck/store/share-deck-store-context.tsx";
import { FolderFormStoreProvider } from "./folder-form/store/folder-form-store-context.tsx";
import { FolderScreen } from "./folder-review/folder-screen.tsx";
import { useSettingsButton } from "../lib/telegram/use-settings-button.ts";
import { ComponentCatalogPage } from "./component-catalog/component-catalog-page.tsx";
import { UserStatisticsStoreProvider } from "./user-statistics/store/user-statistics-store-context.tsx";
import { UserStatisticsScreen } from "./user-statistics/user-statistics-screen.tsx";
import { UserSettingsLazy } from "./user-settings/user-settings-lazy.tsx";
import { ComponentCatalogPageLazy } from "./component-catalog/component-catalog-page-lazy.tsx";
import {
ShareDeckScreenLazy,
ShareFolderScreenLazy,
} from "./share-deck/share-deck-screen-lazy.tsx";

export const App = observer(() => {
useRestoreFullScreenExpand();
Expand Down Expand Up @@ -91,16 +92,12 @@ export const App = observer(() => {
)}
{screenStore.screen.type === "shareDeck" && (
<PreventTelegramSwipeDownClosingIos>
<ShareDeckOrFormStoreProvider type={"deck"}>
<ShareDeckScreen />
</ShareDeckOrFormStoreProvider>
<ShareDeckScreenLazy />
</PreventTelegramSwipeDownClosingIos>
)}
{screenStore.screen.type === "shareFolder" && (
<PreventTelegramSwipeDownClosingIos>
<ShareDeckOrFormStoreProvider type={"folder"}>
<ShareDeckScreen />
</ShareDeckOrFormStoreProvider>
<ShareFolderScreenLazy />
</PreventTelegramSwipeDownClosingIos>
)}
{screenStore.screen.type === "cardQuickAddForm" && (
Expand All @@ -110,9 +107,7 @@ export const App = observer(() => {
)}
{screenStore.screen.type === "userSettings" && (
<PreventTelegramSwipeDownClosingIos>
<UserSettingsStoreProvider>
<UserSettingsMain />
</UserSettingsStoreProvider>
<UserSettingsLazy />
</PreventTelegramSwipeDownClosingIos>
)}
{screenStore.screen.type === "deckCatalog" && (
Expand All @@ -124,7 +119,7 @@ export const App = observer(() => {
)}
{screenStore.screen.type === "componentCatalog" && (
<PreventTelegramSwipeDownClosingIos>
<ComponentCatalogPage />
<ComponentCatalogPageLazy />
</PreventTelegramSwipeDownClosingIos>
)}
{screenStore.screen.type === "userStatistics" && (
Expand Down
16 changes: 16 additions & 0 deletions src/screens/component-catalog/component-catalog-page-lazy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { lazy, Suspense } from "react";
import { FullScreenLoader } from "../../ui/full-screen-loader.tsx";

const ComponentCatalogPage = lazy(() =>
import("./component-catalog-page.tsx").then((module) => ({
default: module.ComponentCatalogPage,
})),
);

export const ComponentCatalogPageLazy = () => {
return (
<Suspense fallback={<FullScreenLoader />}>
<ComponentCatalogPage />
</Suspense>
);
};
5 changes: 4 additions & 1 deletion src/screens/deck-catalog/store/deck-catalog-store.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { makeAutoObservable } from "mobx";
import { deckCatalogRequest, deckCategoriesRequest } from "../../../api/api.ts";
import { fromPromise, IPromiseBasedObservable } from "mobx-utils";
import {
fromPromise,
IPromiseBasedObservable,
} from "../../../lib/mobx-from-promise/from-promise.ts";
import { DeckCatalogResponse } from "../../../../functions/catalog-decks.ts";
import { TextField } from "mobx-form-lite";
import { cachePromise } from "../../../lib/cache/cache-promise.ts";
Expand Down
5 changes: 4 additions & 1 deletion src/screens/folder-form/store/folder-form-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import { screenStore } from "../../../store/screen-store.ts";
import { assert } from "../../../lib/typescript/assert.ts";
import { decksMineRequest, folderUpsertRequest } from "../../../api/api.ts";
import { deckListStore } from "../../../store/deck-list-store.ts";
import { fromPromise, IPromiseBasedObservable } from "mobx-utils";
import {
fromPromise,
IPromiseBasedObservable,
} from "../../../lib/mobx-from-promise/from-promise.ts";
import { DeckWithoutCardsDbType } from "../../../../functions/db/deck/decks-with-cards-schema.ts";

const createFolderTitleField = (title: string) => {
Expand Down
29 changes: 29 additions & 0 deletions src/screens/share-deck/share-deck-screen-lazy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React, { lazy, Suspense } from "react";
import { FullScreenLoader } from "../../ui/full-screen-loader.tsx";
import { ShareDeckOrFormStoreProvider } from "./store/share-deck-store-context.tsx";

const ShareDeckScreen = lazy(() =>
import("./share-deck-screen.tsx").then((module) => ({
default: module.ShareDeckScreen,
})),
);

export const ShareDeckScreenLazy = () => {
return (
<Suspense fallback={<FullScreenLoader />}>
<ShareDeckOrFormStoreProvider type={"deck"}>
<ShareDeckScreen />
</ShareDeckOrFormStoreProvider>
</Suspense>
);
};

export const ShareFolderScreenLazy = () => {
return (
<Suspense fallback={<FullScreenLoader />}>
<ShareDeckOrFormStoreProvider type={"folder"}>
<ShareDeckScreen />
</ShareDeckOrFormStoreProvider>
</Suspense>
);
};
5 changes: 4 additions & 1 deletion src/screens/share-deck/store/share-deck-form-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import {
addDeckAccessRequest,
getDeckAccessesOfDeckRequest,
} from "../../../api/api.ts";
import { fromPromise, IPromiseBasedObservable } from "mobx-utils";
import {
fromPromise,
IPromiseBasedObservable,
} from "../../../lib/mobx-from-promise/from-promise.ts";
import { DeckAccessesResponse } from "../../../../functions/deck-accesses.ts";
import { DeckAccessType } from "../../../../functions/db/custom-types.ts";
import { persistableField } from "../../../lib/mobx-form-lite-persistable/persistable-field.ts";
Expand Down
24 changes: 24 additions & 0 deletions src/screens/user-settings/user-settings-lazy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, { lazy, Suspense } from "react";
import { FullScreenLoader } from "../../ui/full-screen-loader.tsx";

const UserSettingsStoreProvider = lazy(() =>
import("./store/user-settings-store-context.tsx").then((module) => ({
default: module.UserSettingsStoreProvider,
})),
);

const UserSettingsMain = lazy(() =>
import("./user-settings-main.tsx").then((module) => ({
default: module.UserSettingsMain,
})),
);

export const UserSettingsLazy = () => {
return (
<Suspense fallback={<FullScreenLoader />}>
<UserSettingsStoreProvider>
<UserSettingsMain />
</UserSettingsStoreProvider>
</Suspense>
);
};
5 changes: 4 additions & 1 deletion src/screens/user-statistics/store/user-statistics-store.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { makeAutoObservable } from "mobx";
import { fromPromise, IPromiseBasedObservable } from "mobx-utils";
import {
fromPromise,
IPromiseBasedObservable,
} from "../../../lib/mobx-from-promise/from-promise.ts";
import { MyStatisticsResponse } from "../../../../functions/my-statistics.ts";
import { myStatisticsRequest } from "../../../api/api.ts";
import { PieChartData } from "../pie-chart-canvas.tsx";
Expand Down

0 comments on commit a799d1a

Please sign in to comment.