require('./loader.css');
const Bootloader = () => {
this.progressMap = {};
this.tagMap = {};
this.assets = {};
this.totalSize = 0;
this.networkSpeed = 0;
this.attachAssets = (assets) => {
this.assets = assets;
this.totalSize = this.getTotalSize(assets);
return this;
};
this.getTotalSize = (assets) => {
const cssAssets = assets.css || [];
const jsAssets = assets.js || [];
const sum = (acc, asset) => {
return acc + (asset.size || 0);
};
return cssAssets.reduce(sum, 0) + jsAssets.reduce(sum, 0);
return this;
};
this.updateProgress = (src, size) => {
if (size >= 0) {
const currentValue = this.progressMap[src] || 0;
if (size > currentValue) {
this.progressMap[src] = size;
return true;
}
}
return false;
};
this.getProgress = () => {
const _this = this;
return Object.keys(this.progressMap).reduce((acc, src) => {
return acc + _this.progressMap[src];
}, 0);
};
this.createScriptTag = (src, id) => {
const tag = document.createElement('script');
tag.id = id;
tag.type = 'text/javascript';
tag.src = src;
return tag;
};
this.createCssTag = (href, id) => {
const tag = document.createElement('link');
tag.id = id;
tag.rel = 'stylesheet';
tag.href = href;
return tag;
};
this.getBlob = (asset, cb) => {
const _this = this;
return new Promise((resolve, reject) => {
let endTime;
let fileSize;
const startTime = new Date().getTime();
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
endTime = new Date().getTime();
fileSize = xhr.response.size;
_this.networkSpeed = fileSize / ((endTime - startTime) / 1000) / 1024;
}
};
xhr.open('GET', asset.file, true);
xhr.responseType = 'blob';
xhr.addEventListener(
'error',
(err) => {
return reject(err);
},
false
);
xhr.addEventListener(
'progress',
(event) => {
if (event.lengthComputable) {
_this.updateProgress(asset.file, event.loaded) &&
cb({
totalSize: _this.totalSize,
networkSpeed: _this.networkSpeed,
loaded: _this.getProgress(),
});
}
},
false
);
xhr.addEventListener(
'load',
(event) => {
const { status } = xhr;
if (status === 200 || (status === 0 && xhr.response)) {
_this.updateProgress(asset.file, asset.size) &&
cb({
totalSize: _this.totalSize,
networkSpeed: _this.networkSpeed,
loaded: _this.getProgress(),
});
resolve(xhr.response);
} else {
reject('status: '.concat(xhr.status, ' - ').concat(xhr.statusText));
}
},
false
);
xhr.send();
});
};
this.loadAsset = (asset, js, cb) => {
const _this = this;
return this.getBlob(asset, cb).then((blob) => {
let _a;
const assetId = 'asset_'.concat(asset.file);
const oldAsset = document.getElementById(assetId);
oldAsset &&
((_a = document.head) === null || _a === void 0
? void 0
: _a.removeChild(oldAsset));
const objectURL = URL.createObjectURL(blob);
const tag = js
? _this.createScriptTag(objectURL, assetId)
: _this.createCssTag(objectURL, assetId);
tag.onload = tag.onerror = () => {
tag.onload = tag.onerror = null;
URL.revokeObjectURL(objectURL);
};
_this.tagMap[asset.file] = tag;
return asset;
});
};
this.loadAssets = (assets, js, cb) => {
const _this = this;
const report = {
succeeded: [],
failed: [],
};
const tasks = assets.map((asset) => {
return _this
.loadAsset(asset, js, cb)
.then((done) => {
report.succeeded.push(done);
})
.catch((error) => {
report.failed.push({ asset, error });
});
});
return Promise.all(tasks).then(() => {
return report;
});
};
this.mergeReport = (lr1, lr2) => {
lr2.succeeded.forEach((i) => {
return lr1.succeeded.push(i);
});
lr2.failed.forEach((i) => {
return lr1.failed.push(i);
});
};
this.appendHtmlElements = (assets) => {
let _a;
for (let i = 0, assets_1 = assets; i < assets_1.length; i++) {
const asset = assets_1[i];
const tag = this.tagMap[asset.file];
if (tag) {
(_a = document.head) === null || _a === void 0
? void 0
: _a.appendChild(tag);
}
}
};
this.load = (cb) => {
const _this = this;
const cssAssets = this.assets.css || [];
const jsAssets = this.assets.js || [];
const fullReport = {
succeeded: [],
failed: [],
};
return this.loadAssets(cssAssets, false, cb)
.then((report) => {
_this.mergeReport(fullReport, report);
_this.appendHtmlElements(cssAssets);
return _this.loadAssets(jsAssets, true, cb);
})
.then((report) => {
_this.mergeReport(fullReport, report);
_this.appendHtmlElements(jsAssets);
return fullReport;
});
};
return this;
};
function bootstrap() {
let _a;
const assets =
((_a =
window === null || window === void 0 ? void 0 : window.$bootloader) ===
null || _a === void 0
? void 0
: _a.assets) || {};
Bootloader()
.attachAssets(assets)
.load((e) => {
const progress = e.loaded / e.totalSize;
const progressBar = document.getElementById('progressbar');
const progressData = document.getElementById('progress-data');
progressBar === null || progressBar === void 0
? void 0
: progressBar.setAttribute('value', progress.toString());
progressData.innerHTML = `Loading: <span>${Math.round(
progress * 100
)}%</span>. <br/> Network speed: <span>${
Math.round(e.networkSpeed * 100) / 100
} kbps</span>`;
})
.then((report) => {
if (window !== null) {
let pageloader = null;
pageloader = setInterval(function () {
if (typeof window.onload === 'function') {
clearInterval(pageloader);
window.onload();
}
}, 300);
} else {
console.error('No window');
}
});
}
exports.bootstrap = bootstrap;
document.addEventListener('DOMContentLoaded', bootstrap);