Skip to content

Commit 0d565ad

Browse files
authored
Move loader to react mobx (#759)
* move loader and initialization to react * lazy load the terriajs so loader shows immediately * rename files to minimize change scope * restore some more changes * mobx version
1 parent 04be8fe commit 0d565ad

File tree

13 files changed

+158
-69
lines changed

13 files changed

+158
-69
lines changed

buildprocess/webpack.config.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,6 @@ module.exports = function (devMode) {
8080
}
8181
}
8282
},
83-
// handle css files - inject in html tag
84-
{
85-
test: /loader\.css$/,
86-
include: [path.resolve(__dirname, "..", "lib", "Styles")],
87-
use: ["style-loader", "css-loader"]
88-
},
8983
// handle scss files
9084
{
9185
test: /\.scss$/,
@@ -100,6 +94,7 @@ module.exports = function (devMode) {
10094
defaultExport: true
10195
}
10296
},
97+
{ loader: "terriajs-typings-for-css-modules-loader" },
10398
{
10499
loader: "css-loader",
105100
options: {

entry.js

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,3 @@
1-
import globeGif from "./lib/Styles/globe.gif";
2-
import "./lib/Styles/loader.css";
1+
import { renderUi } from "./lib/Views/render";
32

4-
async function loadMainScript() {
5-
return import("terriajs/lib/Core/prerequisites")
6-
.then(() => import("./index"))
7-
.then(({ default: terriaPromise }) => terriaPromise);
8-
}
9-
10-
function createLoader() {
11-
const loaderDiv = document.createElement("div");
12-
loaderDiv.classList.add("loader-ui");
13-
const loaderGif = document.createElement("img");
14-
loaderGif.src = globeGif;
15-
loaderDiv.appendChild(loaderGif);
16-
17-
loaderDiv.style.backgroundColor = "#383F4D";
18-
document.body.appendChild(loaderDiv);
19-
20-
loadMainScript()
21-
.catch((_err) => {
22-
// Ignore errors and try to show the map anyway
23-
})
24-
.then(() => {
25-
loaderDiv.classList.add("loader-ui-hide");
26-
setTimeout(() => {
27-
document.body.removeChild(loaderDiv);
28-
}, 2000);
29-
});
30-
}
31-
32-
createLoader();
3+
renderUi();

index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import registerCustomComponentTypes from "terriajs/lib/ReactViews/Custom/registe
99
import updateApplicationOnHashChange from "terriajs/lib/ViewModels/updateApplicationOnHashChange";
1010
import updateApplicationOnMessageFromParentWindow from "terriajs/lib/ViewModels/updateApplicationOnMessageFromParentWindow";
1111
import loadPlugins from "./lib/Core/loadPlugins";
12-
import render from "./lib/Views/render";
1312
import showGlobalDisclaimer from "./lib/Views/showGlobalDisclaimer";
1413
import plugins from "./plugins";
1514

@@ -97,10 +96,11 @@ export default terria
9796
styleSheet.innerText = fontImports;
9897
document.head.appendChild(styleSheet);
9998
}
100-
101-
render(terria, [], viewState);
10299
} catch (e) {
103100
console.error(e);
104101
console.error(e.stack);
105102
}
103+
})
104+
.then(() => {
105+
return { terria, viewState };
106106
});

lib/Views/Loader.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import globeGif from "../Styles/globe.gif";
2+
import Styles from "./loader.scss";
3+
4+
export const Loader = () => {
5+
return (
6+
<div
7+
className={Styles.loaderUi}
8+
style={{
9+
backgroundColor: "#383F4D"
10+
}}
11+
>
12+
<img src={globeGif} />
13+
</div>
14+
);
15+
};

lib/Views/UserInterface.jsx

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
import PropTypes from "prop-types";
2-
import React from "react";
32
import RelatedMaps from "terriajs/lib/ReactViews/RelatedMaps/RelatedMaps";
4-
import {
5-
ExperimentalMenu,
6-
MenuLeft
7-
} from "terriajs/lib/ReactViews/StandardUserInterface/customizable/Groups";
3+
import { MenuLeft } from "terriajs/lib/ReactViews/StandardUserInterface/customizable/Groups";
84
import MenuItem from "terriajs/lib/ReactViews/StandardUserInterface/customizable/MenuItem";
95
import StandardUserInterface from "terriajs/lib/ReactViews/StandardUserInterface/StandardUserInterface";
106
import version from "../../version";
11-
import "./global.scss";
127

13-
export default function UserInterface(props) {
14-
const relatedMaps = props.viewState.terria.configParameters.relatedMaps;
8+
export const TerriaUserInterface = ({ terria, viewState, themeOverrides }) => {
9+
const relatedMaps = viewState.terria.configParameters.relatedMaps;
1510
const aboutButtonHrefUrl =
16-
props.viewState.terria.configParameters.aboutButtonHrefUrl;
11+
viewState.terria.configParameters.aboutButtonHrefUrl;
1712

1813
return (
19-
<StandardUserInterface {...props} version={version}>
14+
<StandardUserInterface
15+
terria={terria}
16+
viewState={viewState}
17+
themeOverrides={themeOverrides}
18+
version={version}
19+
>
2020
<MenuLeft>
2121
{aboutButtonHrefUrl ? (
2222
<MenuItem
@@ -29,12 +29,12 @@ export default function UserInterface(props) {
2929
<RelatedMaps relatedMaps={relatedMaps} />
3030
) : null}
3131
</MenuLeft>
32-
<ExperimentalMenu />
3332
</StandardUserInterface>
3433
);
35-
}
34+
};
3635

37-
UserInterface.propTypes = {
38-
terria: PropTypes.object,
39-
viewState: PropTypes.object
36+
TerriaUserInterface.propTypes = {
37+
terria: PropTypes.object.isRequired,
38+
viewState: PropTypes.object.isRequired,
39+
themeOverrides: PropTypes.object
4040
};

lib/Views/global.scss.d.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
declare namespace GlobalScssNamespace {
2+
export interface IGlobalScss {
3+
rcSliderTooltipZoomDownIn: string;
4+
rcSliderTooltipZoomDownOut: string;
5+
"react-datepicker__month--selecting-range": string;
6+
"react-datepicker__year--selecting-range": string;
7+
reactDatepickerMonthSelectingRange: string;
8+
reactDatepickerYearSelectingRange: string;
9+
}
10+
}
11+
12+
declare const GlobalScssModule: GlobalScssNamespace.IGlobalScss & {
13+
/** WARNING: Only available when `css-loader` is used without `style-loader` or `mini-css-extract-plugin` */
14+
locals: GlobalScssNamespace.IGlobalScss;
15+
};
16+
17+
export = GlobalScssModule;
File renamed without changes.

lib/Views/loader.scss.d.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
declare namespace LoaderScssNamespace {
2+
export interface ILoaderScss {
3+
"loader-ui": string;
4+
"loader-ui-hide": string;
5+
loaderUi: string;
6+
loaderUiHide: string;
7+
}
8+
}
9+
10+
declare const LoaderScssModule: LoaderScssNamespace.ILoaderScss & {
11+
/** WARNING: Only available when `css-loader` is used without `style-loader` or `mini-css-extract-plugin` */
12+
locals: LoaderScssNamespace.ILoaderScss;
13+
};
14+
15+
export = LoaderScssModule;

lib/Views/render.jsx

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,48 @@
1+
import { observer } from "mobx-react";
2+
import PropTypes from "prop-types";
3+
import React, { Suspense } from "react";
14
import { createRoot } from "react-dom/client";
2-
import { flushSync } from "react-dom";
35
import Variables from "../Styles/variables.scss";
4-
import UI from "./UserInterface";
6+
import "./global.scss";
7+
import { Loader } from "./Loader";
8+
import { terriaStore } from "./terriaStore";
59

6-
export default function renderUi(terria, allBaseMaps, viewState) {
7-
const container = document.getElementById("ui");
8-
const root = createRoot(container);
10+
// Lazy load the entire TerriaUserInterface component
11+
const LazyTerriaUserInterface = React.lazy(() =>
12+
import("./UserInterface").then((module) => ({
13+
default: module.TerriaUserInterface
14+
}))
15+
);
16+
17+
const Root = observer(({ themeOverrides }) => {
18+
const { terria, viewState, status } = terriaStore;
919

10-
// Ensure that the initial render is synchronous so there is no a white flash visible between loading and rendering
11-
flushSync(() =>
12-
root.render(
13-
<UI
20+
if (status === "loading") {
21+
return <Loader />;
22+
}
23+
24+
return (
25+
<Suspense fallback={<Loader />}>
26+
<LazyTerriaUserInterface
1427
terria={terria}
15-
allBaseMaps={allBaseMaps}
1628
viewState={viewState}
17-
themeOverrides={Variables}
29+
themeOverrides={themeOverrides}
1830
/>
19-
)
31+
</Suspense>
2032
);
21-
}
33+
});
34+
35+
Root.propTypes = {
36+
themeOverrides: PropTypes.object
37+
};
38+
39+
export const renderUi = () => {
40+
const container = document.getElementById("ui");
41+
if (!container) {
42+
console.error("Container element with id 'ui' not found.");
43+
return;
44+
}
45+
46+
const root = createRoot(container);
47+
root.render(<Root themeOverrides={Variables} />);
48+
};

lib/Views/terriaStore.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { makeObservable, observable, action } from "mobx";
2+
import type Terria from "terriajs/lib/Models/Terria";
3+
import type ViewState from "terriajs/lib/ReactViewModels/ViewState";
4+
5+
class TerriaStore {
6+
terria: Terria | undefined = undefined;
7+
viewState: ViewState | undefined = undefined;
8+
status: "loading" | "ready" = "loading";
9+
10+
constructor() {
11+
makeObservable(this, {
12+
terria: observable,
13+
viewState: observable,
14+
status: observable,
15+
setReady: action
16+
});
17+
18+
this.init();
19+
}
20+
21+
async init() {
22+
//@ts-expect-error: need to convert to TS
23+
await import("terriajs/lib/Core/prerequisites");
24+
25+
const { terria, viewState } = await import("../../index.js").then(
26+
(module) => module.default
27+
);
28+
29+
this.setReady(terria, viewState);
30+
}
31+
32+
setReady(terria: Terria, viewState: ViewState) {
33+
this.terria = terria;
34+
this.viewState = viewState;
35+
this.status = "ready";
36+
}
37+
}
38+
39+
export const terriaStore = new TerriaStore();

0 commit comments

Comments
 (0)