UNPKG

@shopify/react-async

Version:

Tools for creating powerful, asynchronously-loaded React components

59 lines (56 loc) 1.9 kB
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 };