fetchComponent.ts 2.42 KB
import type { ReactNode } from 'react';

const cache = {};
/**
 *
 * @param url 组件地址
 * @param packages 依赖
 * @param name 组件名称
 * @param fileServer
 * @returns
 */
export async function fetchComponent(
  url: string,
  name: string,
  packages: Record<string, any>,
  fileServer: boolean,
  request?: any,
) {
  if (cache[url]) {
    const cacheModule = await cache[url];

    if (name && !cacheModule[name]) {
      throw new Error('component not found');
    }

    return {
      default: cacheModule[name || 'default'],
    };
  }

  let resolve;
  let reject;

  cache[url] = new Promise((_resolve, _reject) => {
    resolve = _resolve;
    reject = _reject;
  });

  try {
    let _url = url;
    if (fileServer && !url.startsWith('http')) {
      const data = await getFileServerPath(request);
      if (data) {
        _url = data?.endpoint + url;
      }
    }

    const text = await fetch(_url).then((a) => {
      if (!a.ok) {
        throw new Error('Network response was not ok');
      }
      return a.text();
    });

    const module = getParsedModule(text, packages);

    const result = { default: {} };

    if (module.exports?.$$typeof || typeof module.exports === 'function') {
      module.exports.default = module.exports as ReactNode;
    }

    if (!module.exports?.default && !name) {
      throw new Error('module default is undefined');
    }

    result.default = module.exports[name || 'default'];

    if (!result.default) {
      throw new Error('component not found');
    }

    resolve(module.exports);

    return result;
  } catch (error) {
    reject(error);
    throw new Error(error);
  }
}

function getParsedModule(code: string, packages: Record<string, any>) {
  const module: {
    exports: {
      default?: React.ReactNode;
      $$typeof?: any;
    };
  } = {
    exports: {},
  };

  const require = (name: string) => {
    return packages[name];
  };

  try {
    Function('require, exports, module, process', code)(
      require,
      module.exports,
      module,
      window.process || process,
    );
  } catch (error) {
    throw new Error(error.message);
  }

  return module;
}

function getFileServerPath(request?) {
  return ((window as any)?.qx?.sdk?.request || request)?.get?.(
    '/qgyun-service-fs-manager/fileSetting/get',
    {
      headers: {
        businessCode: 'design',
      },
    },
  );
}

export function isMobile() {
  return 'ontouchstart' in document.documentElement;
}