Load css async

This commit is contained in:
tobspr 2020-09-28 12:24:52 +02:00
parent 0d52793c27
commit 507121b886
2 changed files with 247 additions and 228 deletions

View File

@ -54,19 +54,19 @@ function gulptasksHTML($, gulp, buildFolder) {
document.head.appendChild(css); document.head.appendChild(css);
// Append async css // Append async css
const asyncCss = document.createElement("link"); // const asyncCss = document.createElement("link");
asyncCss.rel = "stylesheet"; // asyncCss.rel = "stylesheet";
asyncCss.type = "text/css"; // asyncCss.type = "text/css";
asyncCss.media = "none"; // asyncCss.media = "none";
asyncCss.setAttribute("onload", "this.media='all'"); // asyncCss.setAttribute("onload", "this.media='all'");
asyncCss.href = cachebust("async-resources.css"); // asyncCss.href = cachebust("async-resources.css");
if (integrity) { // if (integrity) {
asyncCss.setAttribute( // asyncCss.setAttribute(
"integrity", // "integrity",
computeIntegrityHash(path.join(buildFolder, "async-resources.css")) // computeIntegrityHash(path.join(buildFolder, "async-resources.css"))
); // );
} // }
document.head.appendChild(asyncCss); // document.head.appendChild(asyncCss);
if (app) { if (app) {
// Append cordova link // Append cordova link

View File

@ -1,215 +1,234 @@
/* typehints:start */ /* typehints:start */
import { Application } from "../application"; import { Application } from "../application";
/* typehints:end */ /* typehints:end */
import { Loader } from "./loader"; import { Loader } from "./loader";
import { createLogger } from "./logging"; import { createLogger } from "./logging";
import { Signal } from "./signal"; import { Signal } from "./signal";
import { SOUNDS, MUSIC } from "../platform/sound"; import { SOUNDS, MUSIC } from "../platform/sound";
import { AtlasDefinition, atlasFiles } from "./atlas_definitions"; import { AtlasDefinition, atlasFiles } from "./atlas_definitions";
import { initBuildingCodesAfterResourcesLoaded } from "../game/meta_building_registry"; import { initBuildingCodesAfterResourcesLoaded } from "../game/meta_building_registry";
import { cachebust } from "./cachebust";
const logger = createLogger("background_loader");
const logger = createLogger("background_loader");
const essentialMainMenuSprites = [
"logo.png", const essentialMainMenuSprites = [
...G_ALL_UI_IMAGES.filter(src => src.startsWith("ui/") && src.indexOf(".gif") < 0), "logo.png",
]; ...G_ALL_UI_IMAGES.filter(src => src.startsWith("ui/") && src.indexOf(".gif") < 0),
const essentialMainMenuSounds = [ ];
SOUNDS.uiClick, const essentialMainMenuSounds = [
SOUNDS.uiError, SOUNDS.uiClick,
SOUNDS.dialogError, SOUNDS.uiError,
SOUNDS.dialogOk, SOUNDS.dialogError,
SOUNDS.swishShow, SOUNDS.dialogOk,
SOUNDS.swishHide, SOUNDS.swishShow,
]; SOUNDS.swishHide,
];
const essentialBareGameAtlases = atlasFiles;
const essentialBareGameSprites = G_ALL_UI_IMAGES.filter(src => src.indexOf(".gif") < 0); const essentialBareGameAtlases = atlasFiles;
const essentialBareGameSounds = [MUSIC.theme]; const essentialBareGameSprites = G_ALL_UI_IMAGES.filter(src => src.indexOf(".gif") < 0);
const essentialBareGameSounds = [MUSIC.theme];
const additionalGameSprites = [];
// @ts-ignore const additionalGameSprites = [];
const additionalGameSounds = [...Object.values(SOUNDS), ...Object.values(MUSIC)]; // @ts-ignore
const additionalGameSounds = [...Object.values(SOUNDS), ...Object.values(MUSIC)];
export class BackgroundResourcesLoader {
/** export class BackgroundResourcesLoader {
* /**
* @param {Application} app *
*/ * @param {Application} app
constructor(app) { */
this.app = app; constructor(app) {
this.app = app;
this.registerReady = false;
this.mainMenuReady = false; this.registerReady = false;
this.bareGameReady = false; this.mainMenuReady = false;
this.additionalReady = false; this.bareGameReady = false;
this.additionalReady = false;
this.signalMainMenuLoaded = new Signal();
this.signalBareGameLoaded = new Signal(); this.signalMainMenuLoaded = new Signal();
this.signalAdditionalLoaded = new Signal(); this.signalBareGameLoaded = new Signal();
this.signalAdditionalLoaded = new Signal();
this.numAssetsLoaded = 0;
this.numAssetsToLoadTotal = 0; this.numAssetsLoaded = 0;
this.numAssetsToLoadTotal = 0;
// Avoid loading stuff twice
this.spritesLoaded = []; // Avoid loading stuff twice
this.soundsLoaded = []; this.spritesLoaded = [];
} this.soundsLoaded = [];
}
getNumAssetsLoaded() {
return this.numAssetsLoaded; getNumAssetsLoaded() {
} return this.numAssetsLoaded;
}
getNumAssetsTotal() {
return this.numAssetsToLoadTotal; getNumAssetsTotal() {
} return this.numAssetsToLoadTotal;
}
getPromiseForMainMenu() {
if (this.mainMenuReady) { getPromiseForMainMenu() {
return Promise.resolve(); if (this.mainMenuReady) {
} return Promise.resolve();
}
return new Promise(resolve => {
this.signalMainMenuLoaded.add(resolve); return new Promise(resolve => {
}); this.signalMainMenuLoaded.add(resolve);
} });
}
getPromiseForBareGame() {
if (this.bareGameReady) { getPromiseForBareGame() {
return Promise.resolve(); if (this.bareGameReady) {
} return Promise.resolve();
}
return new Promise(resolve => {
this.signalBareGameLoaded.add(resolve); return new Promise(resolve => {
}); this.signalBareGameLoaded.add(resolve);
} });
}
startLoading() {
this.internalStartLoadingEssentialsForMainMenu(); startLoading() {
} this.internalStartLoadingEssentialsForMainMenu();
}
internalStartLoadingEssentialsForMainMenu() {
logger.log("⏰ Start load: main menu"); internalStartLoadingEssentialsForMainMenu() {
this.internalLoadSpritesAndSounds(essentialMainMenuSprites, essentialMainMenuSounds) logger.log("⏰ Start load: main menu");
.catch(err => { this.internalLoadSpritesAndSounds(essentialMainMenuSprites, essentialMainMenuSounds)
logger.warn("⏰ Failed to load essentials for main menu:", err); .catch(err => {
}) logger.warn("⏰ Failed to load essentials for main menu:", err);
.then(() => { })
logger.log("⏰ Finish load: main menu"); .then(() => {
this.mainMenuReady = true; logger.log("⏰ Finish load: main menu");
this.signalMainMenuLoaded.dispatch(); this.mainMenuReady = true;
this.internalStartLoadingEssentialsForBareGame(); this.signalMainMenuLoaded.dispatch();
}); this.internalStartLoadingEssentialsForBareGame();
} });
}
internalStartLoadingEssentialsForBareGame() {
logger.log("⏰ Start load: bare game"); internalStartLoadingEssentialsForBareGame() {
this.internalLoadSpritesAndSounds( logger.log("⏰ Start load: bare game");
essentialBareGameSprites, this.internalLoadSpritesAndSounds(
essentialBareGameSounds, essentialBareGameSprites,
essentialBareGameAtlases essentialBareGameSounds,
) essentialBareGameAtlases
.catch(err => { )
logger.warn("⏰ Failed to load essentials for bare game:", err); .then(() => this.internalPreloadCss("async-resources.scss"))
}) .catch(err => {
.then(() => { logger.warn("⏰ Failed to load essentials for bare game:", err);
logger.log("⏰ Finish load: bare game"); })
this.bareGameReady = true; .then(() => {
initBuildingCodesAfterResourcesLoaded(); logger.log("⏰ Finish load: bare game");
this.signalBareGameLoaded.dispatch(); this.bareGameReady = true;
this.internalStartLoadingAdditionalGameAssets(); initBuildingCodesAfterResourcesLoaded();
}); this.signalBareGameLoaded.dispatch();
} this.internalStartLoadingAdditionalGameAssets();
});
internalStartLoadingAdditionalGameAssets() { }
const additionalAtlases = [];
logger.log("⏰ Start load: additional assets (", additionalAtlases.length, "images)"); internalStartLoadingAdditionalGameAssets() {
this.internalLoadSpritesAndSounds(additionalGameSprites, additionalGameSounds, additionalAtlases) const additionalAtlases = [];
.catch(err => { logger.log("⏰ Start load: additional assets (", additionalAtlases.length, "images)");
logger.warn("⏰ Failed to load additional assets:", err); this.internalLoadSpritesAndSounds(additionalGameSprites, additionalGameSounds, additionalAtlases)
}) .catch(err => {
.then(() => { logger.warn("⏰ Failed to load additional assets:", err);
logger.log("⏰ Finish load: additional assets"); })
this.additionalReady = true; .then(() => {
this.signalAdditionalLoaded.dispatch(); logger.log("⏰ Finish load: additional assets");
}); this.additionalReady = true;
} this.signalAdditionalLoaded.dispatch();
});
/** }
* @param {Array<string>} sprites
* @param {Array<string>} sounds internalPreloadCss(name) {
* @param {Array<AtlasDefinition>} atlases return new Promise((resolve, reject) => {
* @returns {Promise<void>} console.log("TODO");
*/
internalLoadSpritesAndSounds(sprites, sounds, atlases = []) { const link = document.createElement("link");
this.numAssetsToLoadTotal = sprites.length + sounds.length + atlases.length;
this.numAssetsLoaded = 0; link.onload = resolve;
link.onerror = reject;
let promises = [];
link.setAttribute("rel", "stylesheet");
for (let i = 0; i < sounds.length; ++i) { link.setAttribute("media", "all");
if (this.soundsLoaded.indexOf(sounds[i]) >= 0) { link.setAttribute("type", "text/css");
// Already loaded link.setAttribute("href", cachebust("async-resources.css"));
continue; document.head.appendChild(link);
} });
}
this.soundsLoaded.push(sounds[i]);
promises.push( /**
this.app.sound * @param {Array<string>} sprites
.loadSound(sounds[i]) * @param {Array<string>} sounds
.catch(err => { * @param {Array<AtlasDefinition>} atlases
logger.warn("Failed to load sound:", sounds[i]); * @returns {Promise<void>}
}) */
.then(() => { internalLoadSpritesAndSounds(sprites, sounds, atlases = []) {
this.numAssetsLoaded++; this.numAssetsToLoadTotal = sprites.length + sounds.length + atlases.length;
}) this.numAssetsLoaded = 0;
);
} let promises = [];
for (let i = 0; i < sprites.length; ++i) { for (let i = 0; i < sounds.length; ++i) {
if (this.spritesLoaded.indexOf(sprites[i]) >= 0) { if (this.soundsLoaded.indexOf(sounds[i]) >= 0) {
// Already loaded // Already loaded
continue; continue;
} }
this.spritesLoaded.push(sprites[i]);
promises.push( this.soundsLoaded.push(sounds[i]);
Loader.preloadCSSSprite(sprites[i]) promises.push(
.catch(err => { this.app.sound
logger.warn("Failed to load css sprite:", sprites[i]); .loadSound(sounds[i])
}) .catch(err => {
.then(() => { logger.warn("Failed to load sound:", sounds[i]);
this.numAssetsLoaded++; })
}) .then(() => {
); this.numAssetsLoaded++;
} })
);
for (let i = 0; i < atlases.length; ++i) { }
const atlas = atlases[i];
promises.push( for (let i = 0; i < sprites.length; ++i) {
Loader.preloadAtlas(atlas) if (this.spritesLoaded.indexOf(sprites[i]) >= 0) {
.catch(err => { // Already loaded
logger.warn("Failed to load atlas:", atlas.sourceFileName); continue;
}) }
.then(() => { this.spritesLoaded.push(sprites[i]);
this.numAssetsLoaded++; promises.push(
}) Loader.preloadCSSSprite(sprites[i])
); .catch(err => {
} logger.warn("Failed to load css sprite:", sprites[i]);
})
return ( .then(() => {
Promise.all(promises) this.numAssetsLoaded++;
})
// // Remove some pressure by waiting a bit );
// .then(() => { }
// return new Promise(resolve => {
// setTimeout(resolve, 200); for (let i = 0; i < atlases.length; ++i) {
// }); const atlas = atlases[i];
// }) promises.push(
.then(() => { Loader.preloadAtlas(atlas)
this.numAssetsToLoadTotal = 0; .catch(err => {
this.numAssetsLoaded = 0; logger.warn("Failed to load atlas:", atlas.sourceFileName);
}) })
); .then(() => {
} this.numAssetsLoaded++;
} })
);
}
return (
Promise.all(promises)
// // Remove some pressure by waiting a bit
// .then(() => {
// return new Promise(resolve => {
// setTimeout(resolve, 200);
// });
// })
.then(() => {
this.numAssetsToLoadTotal = 0;
this.numAssetsLoaded = 0;
})
);
}
}