Skip to content

Manager

Our manager is in charge of storing all of our assets and libraries’ instances across our whole platform. To do this in the most efficient way, we have three files:

This file is a class containing all the methods and storage we need.

constructor(payload) {
this.libraries = {};
this.instances = {};
this.librariesHeight = []
this.terraDebug = payload.terraDebug || false;
}

We make room for our libraries, our instances and the libraries that will make an effect on our page height to load them instantly when we make an anchor-to.

  • addLibrary({libraryName, lib}) is in charge of adding a new library to the Manager if it is not already present
  • getLibrary(libraryName) returns the library if it is present in the Manager
  • allocateInstances(libraryName) creates a key in our instances object and assigns an empty array to it, so we have memory space to store instances for that library in the future. This is done in Project.js.
  • addInstance(libraryName, instance) pushes an instance into the array assigned to that library in the instances object
  • getInstances(libraryName) obtains all instances for a library
  • cleanInstances(libraryName) empties the array for that library
  • modifyHeight(arrayOfLibraryNames) assigns the libraries to the array of libraries that modify the height of the page, only if they are already allocated

This file contains a function that charges our preload helpers and loads our additional assets, as well as making up our real progress bar.

const DOM = {
images: "img",
lotties: ".js--lottie-element",
videos: "video",
};
const DOM_in_Transition = {
images: "main img",
lotties: "main .js--lottie-element",
videos: "main video",
};
// Choose the DOM according to our 'where' parameter
const currentDOM = where === "preload" ? DOM : DOM_in_Transition;

We choose different elements depending on the moment when we execute this asset manager. When executing it from our Project.js, which would be the preload option, we capture all elements in the page that need to be preloaded. Instead, when we do it from our transition index.js, we capture only those elements inside our main, because that is what our swup is replacing and any elements outside of it are already present.

const libraries = await loadLibraries({ currentDOM });
const filteredLibraries = libraries.filter((lib) => !lib.type || (lib.type === "preload" && types.includes(lib.name)));

We get the libraries from our loadLibraries method called in Project and index.js from transition, and filter the preloaders we do not want

Here we get importations for all of our libraries and filter the ones we are going to use according to the ones the user selected in our types argument.

for (let asset of filteredLibraries) {
try {
let library = libraryManager.getLibrary(asset.name);
const isPresent = NodeList.prototype.isPrototypeOf(asset.domElement)
? asset.domElement.length > 0
: asset.domElement;
if (isPresent && asset.resource) {
if (!library) {
library = await asset.resource();
libraryManager.addLibrary({ name: asset.name, lib: library });
debug && console.log(`Library ${asset.name} imported and added to the Manager`);
} else {
debug && console.log(`Library ${asset.name} already in the Manager`);
}
if (asset.type === "preload") {
library({ selector: asset.selectors, debug: asset.debug, callback: asset.callback });
}
}

Here we go through our list of libraries and:

  • check if they are in the Manager already
  • check if they are present on the page to import and add them to the Manager
  • if they weren’t already in the Manager and they are needed in the page, import them and add them to the Manager
  • afterwards, if they are preloaders, load them immediately
loaded++;
if (progress) {
const newPercentage = (loaded / total) * 100;
const previousPercentage = ((loaded - 1) / total) * 100;
await animateProgress(previousPercentage, newPercentage, progress);
}

For each library we load, we update our progress bar.

This function loads all the additional libraries we might need to use in our site. It consists of our main function:

export const loadExtraAssets = async (payload) => {
const heros = getHeros();
const modules = getModules();
const thirdParty = getThirdParty();
const terra = getTerraInternal();
const preloaders = getPreloaders(payload);
return [...heros, ...modules, ...thirdParty, ...terra, ...preloaders];
};

Which gets all of our libraries coming from an extra file called extraAssets and returns them into our assetManager.

export const getHeros = () => {
return [
{
name: "heroA",
domElement: document.querySelector(".c--hero-a"),
resource: async () => {
const { default: HeroA } = await import("../motion/hero/HeroA.js");
return HeroA;
},
},
];
};
export const getModules = () => {
return [
{
name: "moveItem",
domElement: document.querySelectorAll(".js--moveItem"),
resource: async () => {
const { default: MoveItem } = await import("../motion/modules/MoveItem.js");
return MoveItem;
},
},
];
};

This extraAssets file contains four functions that will make all the imports we need to execute in our page.

If we need an asset to be loaded in every page, instead of passing an element selector, we pass the body so it is always present

{
name: "isElementInViewport",
domElement: "body",
resource: async () => {
const { isElementInViewport } = await import(
"@terrahq/helpers/isElementInViewport"
);
return isElementInViewport;
},
},

Our preloaders will always be present in our extraAssets:

export const getPreloaders = (payload) => {
const {currentDOM} = payload;
return [
{
name: "preloadImages",
selectors: currentDOM.images,
domElement: document.querySelector(currentDOM.images),
resource: async () => {
const { preloadImages } = await import("@terrahq/helpers/preloadImages");
return preloadImages;
},
type: 'preload'
},
{
name: "preloadLotties",
selectors: currentDOM.lotties,
domElement: document.querySelector(currentDOM.lotties),
resource: async () => {
const { preloadLotties } = await import("@terrahq/helpers/preloadLotties");
return preloadLotties;
},
type: 'preload'
},
{
name: "preloadVideos",
selectors: currentDOM.videos,
domElement: document.querySelector(currentDOM.videos),
resource: async () => {
const { preloadVideos } = await import("@terrahq/helpers/preloadVideos");
return preloadVideos;
},
type: 'preload'
},
];
};

They receive the currentDOM from Project.js and index.js from transition.

The manager and its helpers are in charge of the storage and execution of all of our libraries. This is a key process in our framework and we will be using the Manager methods frequently.