UNPKG

@jmodule/client

Version:
80 lines (76 loc) 3.18 kB
import { resolveUrlByFetch } from './fetchCode'; import { ResourceType } from '../config'; function fakeCreateElement(sourceUrl: string, currentUrl: string, originalCreateElement: typeof document.createElement) { return new Proxy(originalCreateElement, { apply(target, context, args) { const originRes = originalCreateElement(args[0], args[1]); if (!['script', 'link', 'style'].includes(args[0])) { return originRes; } originRes.dataset.jmoduleFrom = sourceUrl; originRes.dataset.loadedBy = currentUrl; if (args[0] === 'style') { return originRes; } const prop = args[0] === 'script' ? 'src' : 'href'; const resourceType = args[0] === 'script' ? ResourceType.Script : ResourceType.Style; Object.defineProperty(originRes, prop, { get() { return originRes.dataset.srcRaw; }, set(val) { const resource = window.JModuleManager.resource(sourceUrl); // 理论上不会执行 || 后面的代码 const url = resource?.resolveUrl(val) || new URL(val, currentUrl || sourceUrl).href; originRes.dataset.srcRaw = url; resolveUrlByFetch(url, sourceUrl, resourceType).then((targetUrl) => { originRes.setAttribute(prop, targetUrl); }); return true; }, }); return originRes; }, }); } function fakeCurrentScript(sourceUrl: string, currentUrl: string, originalCurrentScript: HTMLScriptElement) { return new Proxy(originalCurrentScript, { get(_, prop) { if (prop === 'src') { return currentUrl; } const val = Reflect.get(originalCurrentScript, prop); return val instanceof Function ? val.bind(originalCurrentScript) : val; }, }); } export function createDocument( originDocument: Document, originalCreateElement: typeof document.createElement, { sourceUrl, currentUrl }: { sourceUrl: string, currentUrl: string }, ) { return new Proxy(originDocument, { get(target, prop) { if (prop === '__origin__') { return originDocument; } if (prop === 'createElement') { return fakeCreateElement(sourceUrl, currentUrl, originalCreateElement); } const val = Reflect.get(target, prop, originDocument); if (prop === 'currentScript') { return fakeCurrentScript(sourceUrl, currentUrl, val); } if (prop === 'createTreeWalker') { return (a: { [x: string]: any; }, ...args: any) => { val.bind(originDocument)(a['__origin__'] || a, ...args); }; } return val instanceof Function ? val.bind(target) : val; }, set(target, prop, value) { Reflect.set(target, prop, value); return true; }, }); }