UNPKG

vite-plugin-react-pages

Version:

<p> <a href="https://www.npmjs.com/package/vite-plugin-react-pages" target="_blank" rel="noopener"><img src="https://img.shields.io/npm/v/vite-plugin-react-pages.svg" alt="npm package" /></a> </p>

103 lines (93 loc) 3.34 kB
import { File, VirtualModulesManager } from '.' /** * built upon VirtualModulesManager. * map each sourceFile into a proxyModule, which is a virtual module. * when the sourceFile is updated, it will emit update event for the proxyModule. */ export class ProxyModulesManager { private vmm = new VirtualModulesManager() private register: Map<string, { loaded: boolean; sourceFilePath: string }> = new Map() constructor(public readonly proxyModulePrefix: string) { if (!proxyModulePrefix) throw new Error(`invalid proxyModulePrefix: ${proxyModulePrefix}`) } /** * register a source file to watch, * map its data into a proxy module, * return the proxyModuleId * * to create multiple proxy modules for one sourceFilePath, * you can pass in keys to differentiate between them. */ registerProxyModule( sourceFilePath: string, getProxyModuleData: (sourceFile: File) => any, key?: string ) { const proxyModuleId = this.getProxyModuleId(sourceFilePath, key) if (this.register.has(proxyModuleId)) return proxyModuleId this.vmm.addFSWatcher('', [sourceFilePath], async (file, api) => { const proxyModuleData = await getProxyModuleData(file) api.addModuleData(proxyModuleId, proxyModuleData) }) this.register.set(proxyModuleId, { loaded: false, sourceFilePath }) return proxyModuleId } /** * get proxy module data by proxyModuleId */ async getProxyModuleData(proxyModuleId: string) { return new Promise<any>((res, rej) => { this.vmm.getModule(proxyModuleId, (moduleData) => { if (!Array.isArray(moduleData) || moduleData.length === 0) return rej( new Error(`assertion fail: proxy module is empty: ${proxyModuleId}`) ) if (moduleData.length !== 1) return rej( new Error( `assertion fail: proxy module has multiple data: ${proxyModuleId}` ) ) res(moduleData[0]) // set loaded flag after a timeout to avoid some race condition // (onProxyModuleUpdate cb is triggered before this load event) setTimeout(() => { const registerItem = this.register.get(proxyModuleId) if (registerItem && !registerItem.loaded) { this.register.set(proxyModuleId, { ...registerItem, loaded: true }) } }, 50) }) }) } /** * emit event when a proxyModule is updated since loaded */ onProxyModuleUpdate( cb: (proxyModuleId: string, data: any[], prevData: any[]) => void ) { this.vmm.addModuleListener((proxyModuleId, data, prevData) => { const registerItem = this.register.get(proxyModuleId) const notLoaded = registerItem && !registerItem.loaded // bail out if this is the first-load event if (notLoaded && prevData.length === 0) return cb(proxyModuleId, data, prevData) }) } close() { this.vmm.close() } private getProxyModuleId(sourceFilePath: string, key?: string) { let prefix = this.proxyModulePrefix if (key) prefix += `--${key}--` return prefix + sourceFilePath } isProxyModuleId(id: string) { return id.startsWith(this.proxyModulePrefix) && this.register.has(id) } getSourceFilePath(id: string) { return this.register.get(id)?.sourceFilePath } }