import React from 'react'; import { imp } from './imp'; const preloadFactory = (base: string) => { const scriptRel = 'modulepreload'; const seen: { [key: string]: boolean } = {}; return (baseModule: () => any, deps: string[]) => { if (!deps || deps.length === 0) { // 没有依赖,正常不会这样 return baseModule(); } return Promise.all( deps.map((dep) => { dep = `${base}${dep}`; if (dep in seen) return; seen[dep] = true; const isCss = dep.endsWith('.css'); const cssSelector = isCss ? '[rel="stylesheet"]' : ''; if (document.querySelector(`link[href="${dep}"]${cssSelector}`)) { return; } const link = document.createElement('link'); link.rel = isCss ? 'stylesheet' : scriptRel; if (!isCss) { link.as = 'script'; link.crossOrigin = ''; } link.href = dep; document.head.appendChild(link); if (isCss) { return new Promise((res, rej) => { link.addEventListener('load', res); link.addEventListener('error', rej); }); } }), ).then(() => baseModule()); }; }; const perload = preloadFactory(''); type ComponentMeta = { data: { main: string; deps: string[] } }; export const genAsyncComponent = (opts: { devWss: string }) => { const wss = opts.devWss ? new WebSocket(opts.devWss) : null; return function asyncComponent( R: typeof React, opts: { loadMeta: () => Promise }, ) { if (!R) { alert('FEC ERROR: 必须注入 react') } const loadComp = (props: any) => { const [C, setC] = R.useState(null); const loadC = R.useCallback(() => { opts.loadMeta().then((cmeta) => { if (!cmeta?.data?.main) { alert('no meta'); } perload(() => imp(cmeta.data.main), cmeta.data.deps).then( (rs: any) => { setC(rs.default(props)); handelChange(); }, ); }); }, []); const handelChange = R.useCallback(() => { if (wss) { wss.onmessage = (msg) => { const data = JSON.parse(msg.data); console.log(data); loadC(); }; } }, []); R.useEffect(() => { loadC(); }, []); return C ? C : null; }; return loadComp; }; };