@wordpress/interactivity-router
Version:
Package that exposes state and actions from the `core/router` store, part of the Interactivity API.
81 lines (72 loc) • 2.29 kB
text/typescript
/**
* Internal dependencies
*/
import {
initialImportMap,
importPreloadedModule,
preloadWithMap,
type ModuleLoad,
} from './dynamic-importmap';
/**
* IDs of modules that should be resolved by the browser rather than
* processed internally.
*/
const resolvedScriptModules = new Set< string >();
/**
* Marks the specified module as natively resolved.
* @param url Script module URL.
*/
export const markScriptModuleAsResolved = ( url: string ) => {
resolvedScriptModules.add( url );
};
/**
* Resolves and fetches modules present in the passed document, using the
* document's import map to resolve them.
*
* @param doc Document containing the modules to preload.
* @return Array of promises that resolve to a `ScriptModuleLoad` instance.
*/
export const preloadScriptModules = ( doc: Document ) => {
// Extract the import map from the document.
const importMapElement = doc.querySelector< HTMLScriptElement >(
'script#wp-importmap[type=importmap]'
);
const importMap = importMapElement
? JSON.parse( importMapElement.text )
: { imports: {}, scopes: {} };
// Remove imports also in the initial page's import map.
// Those should be handled natively.
for ( const key in initialImportMap.imports ) {
delete importMap.imports[ key ];
}
// Get the URL of all modules contained in the document.
const moduleUrls = [
...doc.querySelectorAll< HTMLScriptElement >(
'script[type=module][src][data-wp-router-options]'
),
]
.filter( ( script ) => {
try {
const parsed = JSON.parse(
script.getAttribute( 'data-wp-router-options' )
);
return parsed?.loadOnClientNavigation === true;
} catch {
return false;
}
} )
.map( ( script ) => script.src );
// Resolve and fetch those not resolved natively.
return moduleUrls
.filter( ( url ) => ! resolvedScriptModules.has( url ) )
.map( ( url ) => preloadWithMap( url, importMap ) );
};
/**
* Imports modules respresented by the passed `ScriptModuleLoad` instances.
*
* @param modules Array of `MoudleLoad` instances.
* @return Promise that resolves once all modules are imported.
*/
export const importScriptModules = ( modules: ScriptModuleLoad[] ) =>
Promise.all( modules.map( ( m ) => importPreloadedModule( m ) ) );
export type ScriptModuleLoad = ModuleLoad;