为不同的组件加载不同的JS库文件

Sof*_*mur 5 script-tag hamlet reactjs webpack react-scripts

我有一个用 ReactJS 制作的网站。在 中public/index.html,我有

<head>
  <script src="/lib/analyzejs-v1.js"></script>
  <script src="/lib/analyzejs-v2.js"></script>
</head>
<body>
  <div id="root"></div>
</body>
Run Code Online (Sandbox Code Playgroud)

其中analyzejs-v1.js有 6Mo,并且analyzejs-v2.js有 3Mo;它们都是固定文件,我无法对其进行太多修改。

这两个文件不是模块;它们的功能已声明(例如,declare function f1(address: string): string;在 中src/defines/analyzejs-v1.d.ts)。analyzejs-v1.js因此,某些组件通过使用函数名称直接调用函数f1(...),无需任何命名空间、导入或导出。其余组件analyzejs-v2.js通过使用函数名称f2(...)直接调用函数,无需任何命名空间、导入或导出。

加载这两个js库文件需要时间。所以我正在寻找一种方法来加载analyzejs-v1.jsanalyzejs-v2.js根据组件(或 URL)。

那么有谁知道为不同组件加载不同JS库文件的常规方法吗?

vip*_*cxj 3

如果不需要同时使用两个脚本,可以在需要时在运行时添加脚本标签。我可以为您提供一个钩子,我用它来动态加载脚本。

export function useScript(url: string, clean: boolean = false, cleanJob: () => void = () => undefined): boolean {
  const [loaded, setLoaded] = useState(false);
  useEffect(() => {
    let create = false;
    let script = document.querySelector(`script[src="${url}"]`) as HTMLScriptElement | null;
    if (!script) {
      script = document.createElement('script');
      script.src = url;
      script.async = true;
      if (type (document as any).attachEvent === 'object') {
        (script as any).onreadystatechange = () => {
          if ((script as any).readyState === 'loaded') {
            setLoaded(true);
          }
        }
      } else {
        script.onload = () => {
          setLoaded(true);
        }
      }
      document.body.appendChild(script);
      create = true;
    } else {
      setLoaded(true);
    }
    // For a special library, you can do the clean work by deleting the variable it exports.
    return () => {
      if (create && script && clean) {
        setLoaded(false);
        document.body.removeChild(script);
        cleanJob && cleanJob();
      }
    }
  }, [url]);
  return loaded;
}
Run Code Online (Sandbox Code Playgroud)

使用方法:

export const Comp = (props: ICompProps) => {
 const loaded = useScript('https://path/to/the/script.js');
 // if you want to do some clean work, Suppose the external script introduces the variable A, And A can be reasigned.
 // const loaded = useScript('https://path/to/the/script.js', true, () -> { A = undefined; });
 useEffect(() -> {
   if (loaded) {
     // Suppose the external script introduces the variable A. Now it is available.
     const a = new A();
     // do something with a.
   }
 }, [loaded]);
 if (loaded) {
   return XXX;  
 } else {
   return null;
 }
}
Run Code Online (Sandbox Code Playgroud)

如果脚本不是模块,只需添加一个不带 import 语句的 typescript 声明文件,并声明脚本导出的全局变量。例如:

declare interface XXX {
  YYY
}
declare const ScriptValue: XXX;
Run Code Online (Sandbox Code Playgroud)