@shopify/react-async
Version:
Tools for creating powerful, asynchronously-loaded React components
59 lines (56 loc) • 1.9 kB
JavaScript
import React from 'react';
import { AssetTiming } from '../types.mjs';
const EFFECT_ID = Symbol('react-async');
class AsyncAssetManager {
constructor() {
this.effect = {
id: EFFECT_ID,
betweenEachPass: () => {
this.assets.clear();
}
};
this.assets = new Map();
}
used(timing = AssetTiming.Immediate) {
const timingArray = Array.isArray(timing) ? timing : [timing];
const assets = [];
for (const [asset, {
scripts,
styles
}] of this.assets) {
const scriptsMatch = timingArray.includes(scripts);
const stylesMatch = timingArray.includes(styles);
if (stylesMatch || scriptsMatch) {
assets.push({
id: asset,
scripts: scriptsMatch,
styles: stylesMatch
});
}
}
return assets;
}
markAsUsed(id, timing = AssetTiming.Immediate) {
const current = this.assets.get(id);
const scripts = typeof timing === 'object' ? timing.scripts : timing;
const styles = typeof timing === 'object' ? timing.styles : timing;
if (current == null) {
this.assets.set(id, {
scripts: scripts || AssetTiming.Immediate,
styles: styles || AssetTiming.Immediate
});
} else {
this.assets.set(id, {
// the AssetTiming enum has values where the smallest value is
// the lowest importance load, and the highest value is for assets
// needed immediately. So, when a new asset comes in that has
// already been recorded, we can take the maximum value to
// keep only the highest priority timing for the asset.
scripts: Math.max(scripts || current.scripts, current.styles),
styles: Math.max(styles || current.styles, current.styles)
});
}
}
}
const AsyncAssetContext = /*#__PURE__*/React.createContext(null);
export { AsyncAssetContext, AsyncAssetManager, EFFECT_ID };