-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: more testing trying to get remote component moved over
- Loading branch information
Showing
9 changed files
with
1,927 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { useEffect, useState } from "react"; | ||
|
||
const urlCache = new Set(); | ||
|
||
export const useDynamicScript = (url: string) => { | ||
const [ready, setReady] = useState(false); | ||
const [errorLoading, setErrorLoading] = useState(false); | ||
|
||
useEffect(() => { | ||
if (!url) return; | ||
|
||
if (urlCache.has(url)) { | ||
setReady(true); | ||
setErrorLoading(false); | ||
return; | ||
} | ||
|
||
setReady(false); | ||
setErrorLoading(false); | ||
|
||
const element = document.createElement("script"); | ||
|
||
element.src = url; | ||
element.type = "text/javascript"; | ||
element.async = true; | ||
|
||
element.onload = () => { | ||
urlCache.add(url); | ||
setReady(true); | ||
}; | ||
|
||
element.onerror = () => { | ||
setReady(false); | ||
setErrorLoading(true); | ||
}; | ||
|
||
document.head.appendChild(element); | ||
|
||
return () => { | ||
urlCache.delete(url); | ||
document.head.removeChild(element); | ||
}; | ||
}, [url]); | ||
|
||
return { errorLoading, ready }; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import React, { lazy, useEffect, useState } from "react"; | ||
|
||
import { useDynamicScript } from "./useDynamicScript"; | ||
|
||
declare global { | ||
interface Window { | ||
[key: string]: any; | ||
} | ||
} | ||
|
||
declare const __webpack_init_sharing__: (scope: string) => Promise<void>; | ||
declare const __webpack_share_scopes__: any; | ||
|
||
function loadComponent(remoteUrl: string, scope: string, module: string) { | ||
return async () => { | ||
await __webpack_init_sharing__("default"); | ||
const container = await import(remoteUrl); | ||
|
||
await container.init(__webpack_share_scopes__.default); | ||
const factory = await container.get(module); | ||
const Module = factory(); | ||
return Module; | ||
}; | ||
} | ||
|
||
const componentCache = new Map(); | ||
|
||
export const useFederatedComponent = ( | ||
remoteUrl: string, | ||
scope: string, | ||
module?: string | ||
) => { | ||
if (!module) return { errorLoading: false, Component: null }; | ||
|
||
const key = `${remoteUrl}-${scope}-${module}`; | ||
const [Component, setComponent] = useState<React.ComponentType<any> | null>( | ||
null | ||
); | ||
|
||
const { ready, errorLoading } = useDynamicScript(remoteUrl); | ||
|
||
useEffect(() => { | ||
if (Component) setComponent(null); | ||
}, [key]); | ||
|
||
useEffect(() => { | ||
if (ready && !Component) { | ||
const Comp = lazy(loadComponent(remoteUrl, scope, module)); | ||
componentCache.set(key, Comp); | ||
setComponent(Comp); | ||
} | ||
}, [Component, ready, key]); | ||
|
||
return { errorLoading, Component }; | ||
}; |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// @ts-nocheck | ||
|
||
export const fetchRemote = (url, remoteName) => { | ||
return new Promise((resolve, reject) => { | ||
// We define a script tag to use the browser for fetching the remoteEntry.js file | ||
const script = document.createElement("script"); | ||
script.src = url; | ||
script.onerror = (err) => { | ||
console.error(err); | ||
reject(new Error(`Failed to fetch remote: ${remoteName}`)); | ||
}; | ||
// When the script is loaded we need to resolve the promise back to Module Federation | ||
script.onload = () => { | ||
// The script is now loaded on window using the name defined within the remote | ||
const proxy = { | ||
get: (request) => window[remoteName].get(request), | ||
init: (arg) => { | ||
try { | ||
return window[remoteName].init(arg); | ||
} catch (e) { | ||
console.error(e); | ||
console.error(`Failed to initialize remote: ${remoteName}`); | ||
reject(e); | ||
} | ||
}, | ||
}; | ||
resolve(proxy); | ||
}; | ||
// Lastly we inject the script tag into the document's head to trigger the script load | ||
document.head.appendChild(script); | ||
}); | ||
}; | ||
|
||
export const loadComponent = | ||
(remoteModule, url, remoteComponent, scope = "default") => | ||
async () => { | ||
if (!(remoteModule in window)) { | ||
// Need to load the remote first | ||
// Initializes the shared scope. Fills it with known provided modules from this build and all remotes | ||
|
||
await __webpack_init_sharing__(scope); // TODO when would you use a different scope? | ||
const fetchedContainer = await fetchRemote(url, remoteModule); | ||
|
||
await fetchedContainer.init(__webpack_share_scopes__[scope]); | ||
} | ||
const container = window[remoteModule]; // Assuming the remote has been loaded using the above function | ||
const factory = await container.get(remoteComponent); | ||
const Module = factory(); | ||
return Module; | ||
}; |
Oops, something went wrong.