Skip to content

Commit 46e38fb

Browse files
authored
feat: add dynamic imports for .json assets (#2740)
Change the default way asset discovery and loading works from static ES6 imports of .json files to dynamic ES6 imports of .json files.
1 parent f2f3889 commit 46e38fb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+532
-500
lines changed

packages/base/bundle.esm.js

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { registerThemeProperties } from "./dist/AssetRegistry.js";
1+
import { registerThemePropertiesLoader } from "./dist/AssetRegistry.js";
22

33
// ESM bundle targets browsers with native support
44
import "./dist/features/OpenUI5Support.js";
@@ -20,11 +20,10 @@ import { isIE } from "./dist/Device.js";
2020
window.isIE = isIE; // attached to the window object for testing purposes
2121

2222
// used for tests - to register a custom theme
23-
window.registerThemeProperties = registerThemeProperties;
23+
window.registerThemePropertiesLoader = registerThemePropertiesLoader;
2424

2525
// i18n
26-
import "./dist/features/PropertiesFormatSupport.js";
27-
import { registerI18nBundle, fetchI18nBundle, getI18nBundle } from "./dist/i18nBundle.js";
26+
import { registerI18nLoader, fetchI18nBundle, getI18nBundle } from "./dist/i18nBundle.js";
2827

2928
// Note: keep in sync with rollup.config value for IIFE
3029
import { getAnimationMode } from "./dist/config/AnimationMode.js";
@@ -34,7 +33,7 @@ import { getTheme, setTheme } from "./dist/config/Theme.js";
3433
import { getNoConflict, setNoConflict } from "./dist/config/NoConflict.js";
3534
import { getRTL } from "./dist/config/RTL.js";
3635
import { getFirstDayOfWeek } from "./dist/config/FormatSettings.js";
37-
import { getRegisteredNames as getIconNames } from "./dist/SVGIconRegistry.js"
36+
import { _getRegisteredNames as getIconNames } from "./dist/asset-registries/Icons.js"
3837
window["sap-ui-webcomponents-bundle"] = {
3938
configuration : {
4039
getAnimationMode,
@@ -48,7 +47,7 @@ window["sap-ui-webcomponents-bundle"] = {
4847
getFirstDayOfWeek,
4948
},
5049
getIconNames,
51-
registerI18nBundle,
50+
registerI18nLoader,
5251
fetchI18nBundle,
5352
getI18nBundle,
5453
renderFinished,

packages/base/src/AssetRegistry.js

+8-9
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
import { registerI18nBundle } from "./asset-registries/i18n.js";
2-
import { registerCldr, _registerMappingFunction as registerCldrMappingFunction } from "./asset-registries/LocaleData.js";
3-
import { registerThemeProperties } from "./asset-registries/Themes.js";
4-
import { registerAssetPathMappingFunction } from "./util/EffectiveAssetPath.js";
1+
import { registerI18nLoader } from "./asset-registries/i18n.js";
2+
import { registerLocaleDataLoader } from "./asset-registries/LocaleData.js";
3+
import { registerThemePropertiesLoader } from "./asset-registries/Themes.js";
4+
import { registerIconLoader } from "./asset-registries/Icons.js";
55

66
export {
7-
registerCldr,
8-
registerCldrMappingFunction,
9-
registerThemeProperties,
10-
registerI18nBundle,
11-
registerAssetPathMappingFunction,
7+
registerI18nLoader,
8+
registerLocaleDataLoader,
9+
registerThemePropertiesLoader,
10+
registerIconLoader,
1211
};

packages/base/src/util/parseProperties.js renamed to packages/base/src/PropertiesFileFormat.js

+6
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ const mEscapes = {
1515
"\\t": "\t",
1616
};
1717

18+
/**
19+
* Parses a .properties format
20+
* @param {string} sText the contents a of a .properties file
21+
* @returns a object with key/value pairs parsed from the .properties file format
22+
* @public
23+
*/
1824
const parseProperties = sText => {
1925
const properties = {},
2026
aLines = sText.split(rLines);

packages/base/src/SVGIconRegistry.js

-73
This file was deleted.
+94-14
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,33 @@
1-
import { registerIcon, registerCollectionPromise } from "../SVGIconRegistry.js";
2-
import { fetchJsonOnce } from "../util/FetchHelper.js";
3-
import { getEffectiveAssetPath } from "../util/EffectiveAssetPath.js";
1+
import getSharedResource from "../getSharedResource.js";
42

3+
const loaders = new Map();
4+
const registry = getSharedResource("SVGIcons.registry", new Map());
5+
const iconCollectionPromises = getSharedResource("SVGIcons.promises", new Map());
6+
7+
const ICON_NOT_FOUND = "ICON_NOT_FOUND";
8+
const DEFAULT_COLLECTION = "SAP-icons";
9+
10+
/**
11+
* @deprecated
12+
*/
513
const registerIconBundle = async (collectionName, bundleData) => {
6-
let resolveFn;
7-
const collectionFetched = new Promise(resolve => {
8-
resolveFn = resolve;
9-
});
10-
registerCollectionPromise(collectionName, collectionFetched);
14+
throw new Error("This method has been removed. Use `registerIconLoader` instead.");
15+
};
1116

12-
if (typeof bundleData !== "object") { // not inlined from build -> fetch it
13-
bundleData = await fetchJsonOnce(getEffectiveAssetPath(bundleData));
17+
const registerIconLoader = async (collectionName, loader) => {
18+
loaders.set(collectionName, loader);
19+
};
20+
21+
const _loadIconCollectionOnce = async collectionName => {
22+
if (!iconCollectionPromises.has(collectionName)) {
23+
const loadIcons = loaders.get(collectionName);
24+
iconCollectionPromises.set(collectionName, loadIcons(collectionName));
1425
}
15-
fillRegistry(bundleData);
16-
resolveFn();
26+
27+
return iconCollectionPromises.get(collectionName);
1728
};
1829

19-
const fillRegistry = bundleData => {
30+
const _fillRegistry = bundleData => {
2031
Object.keys(bundleData.data).forEach(iconName => {
2132
const iconData = bundleData.data[iconName];
2233

@@ -29,4 +40,73 @@ const fillRegistry = bundleData => {
2940
});
3041
};
3142

32-
export { registerIconBundle }; // eslint-disable-line
43+
// set
44+
const registerIcon = (name, { pathData, ltr, accData, collection } = {}) => { // eslint-disable-line
45+
if (!collection) {
46+
collection = DEFAULT_COLLECTION;
47+
}
48+
49+
const key = `${collection}/${name}`;
50+
registry.set(key, { pathData, ltr, accData });
51+
};
52+
53+
const _parseName = name => {
54+
// silently support ui5-compatible URIs
55+
if (name.startsWith("sap-icon://")) {
56+
name = name.replace("sap-icon://", "");
57+
}
58+
59+
let collection;
60+
[name, collection] = name.split("/").reverse();
61+
collection = collection || DEFAULT_COLLECTION;
62+
// hardcoded alias in case icon explorer is used, resolve `SAP-icons-TNT` to `tnt`
63+
// aliases can be made a feature in the future if more collections need it or more aliases are needed.
64+
if (collection === "SAP-icons-TNT") {
65+
collection = "tnt";
66+
}
67+
const registryKey = `${collection}/${name}`;
68+
return { name, collection, registryKey };
69+
};
70+
71+
const getIconDataSync = nameProp => {
72+
const { registryKey } = _parseName(nameProp);
73+
return registry.get(registryKey);
74+
};
75+
76+
const getIconData = async nameProp => {
77+
const { collection, registryKey } = _parseName(nameProp);
78+
79+
let iconData = ICON_NOT_FOUND;
80+
try {
81+
iconData = await _loadIconCollectionOnce(collection);
82+
} catch (e) {
83+
console.error(e.message); /* eslint-disable-line */
84+
}
85+
86+
if (iconData === ICON_NOT_FOUND) {
87+
return iconData;
88+
}
89+
90+
if (!registry.has(registryKey)) {
91+
// not filled by another await. many getters will await on the same loader, but fill only once
92+
_fillRegistry(iconData);
93+
}
94+
return registry.get(registryKey);
95+
};
96+
97+
// test page usage only
98+
const _getRegisteredNames = async () => {
99+
// fetch one icon of each collection to trigger the bundle load
100+
await getIconData("edit");
101+
await getIconData("tnt/arrow");
102+
return Array.from(registry.keys());
103+
};
104+
105+
export {
106+
registerIconBundle,
107+
registerIconLoader,
108+
getIconData,
109+
getIconDataSync,
110+
registerIcon,
111+
_getRegisteredNames,
112+
};

0 commit comments

Comments
 (0)