I have a website made in ReactJS. In public/index.html
, I have
<head>
<script src="/lib/analyzejs-v1.js"></script>
<script src="/lib/analyzejs-v2.js"></script>
</head>
<body>
<div id="root"></div>
</body>
where analyzejs-v1.js
has 6Mo, and analyzejs-v2.js
has 3Mo; they are all fixed files that I could not much modify.
These two files are not modules; their functions are declared (e.g., declare function f1(address: string): string;
in src/defines/analyzejs-v1.d.ts
). So some components call functions of analyzejs-v1.js
by using a function name like f1(...)
directly without any namespace, import, or export. And the rest of the components call functions of analyzejs-v2.js
by using a function name like f2(...)
directly without any namespace, import, or export.
It takes time to load these two js library files. So I'm looking for a way to load either analyzejs-v1.js
or analyzejs-v2.js
according to the component (or URL).
So does anyone know a conventional way to load different JS library files for different components?
If you don't need two script at the same time, you can add the script tag in the runtime when necessary. I can provide you a hook which I have used to load the script on the fly.
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;
}
To use it:
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;
}
}
If the script is not a module, just add a typescript declare file without import statements, and declare the global variable the script export. Such as:
declare interface XXX {
YYY
}
declare const ScriptValue: XXX;