Skip to content

Commit 4ad7f7d

Browse files
committed
lazy load the terriajs so loader shows immediately
1 parent 3e6558a commit 4ad7f7d

File tree

4 files changed

+169
-143
lines changed

4 files changed

+169
-143
lines changed

index.js

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import ConsoleAnalytics from "terriajs/lib/Core/ConsoleAnalytics";
2+
import GoogleAnalytics from "terriajs/lib/Core/GoogleAnalytics";
3+
import registerCatalogMembers from "terriajs/lib/Models/Catalog/registerCatalogMembers";
4+
import registerSearchProviders from "terriajs/lib/Models/SearchProviders/registerSearchProviders";
5+
import ShareDataService from "terriajs/lib/Models/ShareDataService";
6+
import Terria from "terriajs/lib/Models/Terria";
7+
import ViewState from "terriajs/lib/ReactViewModels/ViewState";
8+
import registerCustomComponentTypes from "terriajs/lib/ReactViews/Custom/registerCustomComponentTypes";
9+
import updateApplicationOnHashChange from "terriajs/lib/ViewModels/updateApplicationOnHashChange";
10+
import updateApplicationOnMessageFromParentWindow from "terriajs/lib/ViewModels/updateApplicationOnMessageFromParentWindow";
11+
import loadPlugins from "./lib/Core/loadPlugins";
12+
import showGlobalDisclaimer from "./lib/Views/showGlobalDisclaimer";
13+
import plugins from "./plugins";
14+
15+
const terriaOptions = {
16+
baseUrl: "build/TerriaJS"
17+
};
18+
19+
// we check exact match for development to reduce chances that production flag isn't set on builds(?)
20+
if (process.env.NODE_ENV === "development") {
21+
terriaOptions.analytics = new ConsoleAnalytics();
22+
} else {
23+
terriaOptions.analytics = new GoogleAnalytics();
24+
}
25+
26+
// Construct the TerriaJS application, arrange to show errors to the user, and start it up.
27+
const terria = new Terria(terriaOptions);
28+
29+
// Create the ViewState before terria.start so that errors have somewhere to go.
30+
const viewState = new ViewState({
31+
terria: terria
32+
});
33+
34+
// Register all types of catalog members in the core TerriaJS. If you only want to register a subset of them
35+
// (i.e. to reduce the size of your application if you don't actually use them all), feel free to copy a subset of
36+
// the code in the registerCatalogMembers function here instead.
37+
registerCatalogMembers();
38+
39+
// Register custom search providers in the core TerriaJS. If you only want to register a subset of them, or to add your own,
40+
// insert your custom version of the code in the registerSearchProviders function here instead.
41+
registerSearchProviders();
42+
43+
// Register custom components in the core TerriaJS. If you only want to register a subset of them, or to add your own,
44+
// insert your custom version of the code in the registerCustomComponentTypes function here instead.
45+
registerCustomComponentTypes(terria);
46+
47+
if (process.env.NODE_ENV === "development") {
48+
window.viewState = viewState;
49+
}
50+
51+
export default terria
52+
.start({
53+
applicationUrl: window.location,
54+
configUrl: "config.json",
55+
shareDataService: new ShareDataService({
56+
terria: terria
57+
}),
58+
beforeRestoreAppState: () => {
59+
// Load plugins before restoring app state because app state may
60+
// reference plugin components and catalog items.
61+
return loadPlugins(viewState, plugins).catch((error) => {
62+
console.error(`Error loading plugins`);
63+
console.error(error);
64+
});
65+
}
66+
})
67+
.catch(function (e) {
68+
terria.raiseErrorToUser(e);
69+
})
70+
.finally(function () {
71+
// Override the default document title with appName. Check first for default
72+
// title, because user might have already customized the title in
73+
// index.ejs
74+
if (document.title === "Terria Map") {
75+
document.title = terria.appName;
76+
}
77+
78+
// Load init sources like init files and share links
79+
terria.loadInitSources().then((result) => result.raiseError(terria));
80+
81+
try {
82+
// Automatically update Terria (load new catalogs, etc.) when the hash part of the URL changes.
83+
updateApplicationOnHashChange(terria, window);
84+
updateApplicationOnMessageFromParentWindow(terria, window);
85+
86+
// Show a modal disclaimer before user can do anything else.
87+
if (terria.configParameters.globalDisclaimer) {
88+
showGlobalDisclaimer(viewState);
89+
}
90+
91+
// Add font-imports
92+
const fontImports = terria.configParameters.theme?.fontImports;
93+
if (fontImports) {
94+
const styleSheet = document.createElement("style");
95+
styleSheet.type = "text/css";
96+
styleSheet.innerText = fontImports;
97+
document.head.appendChild(styleSheet);
98+
}
99+
} catch (e) {
100+
console.error(e);
101+
console.error(e.stack);
102+
}
103+
})
104+
.then(() => {
105+
return { terria, viewState };
106+
});

lib/Views/TerriaUserInterface.jsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import PropTypes from "prop-types";
2+
import RelatedMaps from "terriajs/lib/ReactViews/RelatedMaps/RelatedMaps";
3+
import { MenuLeft } from "terriajs/lib/ReactViews/StandardUserInterface/customizable/Groups";
4+
import MenuItem from "terriajs/lib/ReactViews/StandardUserInterface/customizable/MenuItem";
5+
import StandardUserInterface from "terriajs/lib/ReactViews/StandardUserInterface/StandardUserInterface";
6+
import version from "../../version";
7+
8+
export const TerriaUserInterface = ({ terria, viewState, themeOverrides }) => {
9+
const relatedMaps = viewState.terria.configParameters.relatedMaps;
10+
const aboutButtonHrefUrl =
11+
viewState.terria.configParameters.aboutButtonHrefUrl;
12+
13+
return (
14+
<StandardUserInterface
15+
terria={terria}
16+
viewState={viewState}
17+
themeOverrides={themeOverrides}
18+
version={version}
19+
>
20+
<MenuLeft>
21+
{aboutButtonHrefUrl ? (
22+
<MenuItem
23+
caption="About"
24+
href={aboutButtonHrefUrl}
25+
key="about-link"
26+
/>
27+
) : null}
28+
{relatedMaps && relatedMaps.length > 0 ? (
29+
<RelatedMaps relatedMaps={relatedMaps} />
30+
) : null}
31+
</MenuLeft>
32+
</StandardUserInterface>
33+
);
34+
};
35+
36+
TerriaUserInterface.propTypes = {
37+
terria: PropTypes.object.isRequired,
38+
viewState: PropTypes.object.isRequired,
39+
themeOverrides: PropTypes.object
40+
};

lib/Views/UserInterface.jsx

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

8+
// Lazy load the entire TerriaUserInterface component
9+
const LazyTerriaUserInterface = React.lazy(() =>
10+
import("./TerriaUserInterface").then((module) => ({
11+
default: module.TerriaUserInterface
12+
}))
13+
);
14+
1215
export const UserInterface = ({ themeOverrides }) => {
1316
const { terria, viewState, status } = useSyncExternalStore(
1417
terriaStore.subscribe,
@@ -18,31 +21,15 @@ export const UserInterface = ({ themeOverrides }) => {
1821
if (status === "loading") {
1922
return <Loader />;
2023
}
21-
const relatedMaps = viewState.terria.configParameters.relatedMaps;
22-
const aboutButtonHrefUrl =
23-
viewState.terria.configParameters.aboutButtonHrefUrl;
2424

2525
return (
26-
<StandardUserInterface
27-
terria={terria}
28-
viewState={viewState}
29-
themeOverrides={themeOverrides}
30-
version={version}
31-
>
32-
<MenuLeft>
33-
{aboutButtonHrefUrl ? (
34-
<MenuItem
35-
caption="About"
36-
href={aboutButtonHrefUrl}
37-
key="about-link"
38-
/>
39-
) : null}
40-
{relatedMaps && relatedMaps.length > 0 ? (
41-
<RelatedMaps relatedMaps={relatedMaps} />
42-
) : null}
43-
</MenuLeft>
44-
{/* <ExperimentalMenu /> */}
45-
</StandardUserInterface>
26+
<Suspense fallback={<Loader />}>
27+
<LazyTerriaUserInterface
28+
terria={terria}
29+
viewState={viewState}
30+
themeOverrides={themeOverrides}
31+
/>
32+
</Suspense>
4633
);
4734
};
4835

lib/Views/terriaStore.ts

Lines changed: 8 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,5 @@
1-
import ConsoleAnalytics from "terriajs/lib/Core/ConsoleAnalytics";
2-
import GoogleAnalytics from "terriajs/lib/Core/GoogleAnalytics";
3-
import registerCatalogMembers from "terriajs/lib/Models/Catalog/registerCatalogMembers";
4-
import registerSearchProviders from "terriajs/lib/Models/SearchProviders/registerSearchProviders";
5-
import ShareDataService from "terriajs/lib/Models/ShareDataService";
6-
import Terria from "terriajs/lib/Models/Terria";
7-
import ViewState from "terriajs/lib/ReactViewModels/ViewState";
8-
import registerCustomComponentTypes from "terriajs/lib/ReactViews/Custom/registerCustomComponentTypes";
9-
import updateApplicationOnHashChange from "terriajs/lib/ViewModels/updateApplicationOnHashChange";
10-
import updateApplicationOnMessageFromParentWindow from "terriajs/lib/ViewModels/updateApplicationOnMessageFromParentWindow";
11-
12-
import loadPlugins from "../Core/loadPlugins";
13-
import showGlobalDisclaimer from "./showGlobalDisclaimer";
14-
import plugins from "../../plugins";
15-
16-
const initTerria = async () => {
17-
console.log("Initializing TerriaJS...", Date.now());
18-
await import("terriajs/lib/Core/prerequisites");
19-
20-
const terriaOptions: ConstructorParameters<typeof Terria>[0] = {
21-
baseUrl: "build/TerriaJS"
22-
};
23-
24-
// we check exact match for development to reduce chances that production flag isn't set on builds(?)
25-
if (process.env.NODE_ENV === "development") {
26-
terriaOptions.analytics = new ConsoleAnalytics();
27-
} else {
28-
terriaOptions.analytics = new GoogleAnalytics();
29-
}
30-
31-
// Construct the TerriaJS application, arrange to show errors to the user, and start it up.
32-
const terria = new Terria(terriaOptions);
33-
34-
// Create the ViewState before terria.start so that errors have somewhere to go.
35-
// @ts-expect-error: test
36-
const viewState = new ViewState({
37-
terria: terria
38-
});
39-
40-
// Register all types of catalog members in the core TerriaJS. If you only want to register a subset of them
41-
// (i.e. to reduce the size of your application if you don't actually use them all), feel free to copy a subset of
42-
// the code in the registerCatalogMembers function here instead.
43-
registerCatalogMembers();
44-
45-
// Register custom search providers in the core TerriaJS. If you only want to register a subset of them, or to add your own,
46-
// insert your custom version of the code in the registerSearchProviders function here instead.
47-
registerSearchProviders();
48-
49-
// Register custom components in the core TerriaJS. If you only want to register a subset of them, or to add your own,
50-
// insert your custom version of the code in the registerCustomComponentTypes function here instead.
51-
registerCustomComponentTypes(terria);
52-
53-
if (process.env.NODE_ENV === "development") {
54-
// @ts-expect-error: test
55-
window.viewState = viewState;
56-
}
57-
58-
await terria
59-
.start({
60-
applicationUrl: window.location,
61-
configUrl: "config.json",
62-
shareDataService: new ShareDataService({
63-
terria: terria
64-
}),
65-
beforeRestoreAppState: () => {
66-
// Load plugins before restoring app state because app state may
67-
// reference plugin components and catalog items.
68-
return loadPlugins(viewState, plugins).catch((error) => {
69-
console.error(`Error loading plugins`);
70-
console.error(error);
71-
});
72-
}
73-
})
74-
.catch(function (e) {
75-
terria.raiseErrorToUser(e);
76-
})
77-
.finally(function () {
78-
// Override the default document title with appName. Check first for default
79-
// title, because user might have already customized the title in
80-
// index.ejs
81-
if (document.title === "Terria Map") {
82-
document.title = terria.appName;
83-
}
84-
85-
// Load init sources like init files and share links
86-
terria.loadInitSources().then((result) => result.raiseError(terria));
87-
88-
try {
89-
// Automatically update Terria (load new catalogs, etc.) when the hash part of the URL changes.
90-
updateApplicationOnHashChange(terria, window);
91-
updateApplicationOnMessageFromParentWindow(terria, window);
92-
93-
// Show a modal disclaimer before user can do anything else.
94-
if (terria.configParameters.globalDisclaimer) {
95-
showGlobalDisclaimer(viewState);
96-
}
97-
98-
// Add font-imports
99-
const fontImports = terria.configParameters.theme?.fontImports;
100-
if (fontImports) {
101-
const styleSheet = document.createElement("style");
102-
styleSheet.type = "text/css";
103-
styleSheet.innerText = fontImports;
104-
document.head.appendChild(styleSheet);
105-
}
106-
} catch (e) {
107-
console.error(e);
108-
console.error((e as Error).stack);
109-
}
110-
});
111-
112-
console.log("TerriaJS initialized successfully");
113-
return { terria, viewState };
114-
};
1+
import type Terria from "terriajs/lib/Models/Terria";
2+
import type ViewState from "terriajs/lib/ReactViewModels/ViewState";
1153

1164
type State =
1175
| {
@@ -141,7 +29,12 @@ const emitChange = () => {
14129

14230
export const terriaStore = {
14331
async init() {
144-
const { terria, viewState } = await initTerria();
32+
await import("terriajs/lib/Core/prerequisites");
33+
34+
const { terria, viewState } = await import("../../index.js").then(
35+
(module) => module.default
36+
);
37+
14538
state = {
14639
terria,
14740
viewState,

0 commit comments

Comments
 (0)