Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import React from 'react';
- type Scope = unknown;
- type Factory = () => any;
- type Container = {
- init(shareScope: Scope): void;
- get(module: string): Factory;
- };
- declare const __webpack_init_sharing__: (shareScope: string) => Promise<void>;
- declare const __webpack_share_scopes__: { default: Scope };
- // @NOTE: Cache for <script> promises
- const dynamicScriptPromises = new Map<string, Promise<any>>();
- /**
- * Creates <script src="url"> and returns promise (!!! uses cache, won't create duplicated elements)
- * @param url - https://example.org/remoteEntry.js
- * @param removeElement - should it remove <script> element after onLoad/onError event. Default - false
- */
- export function loadDynamicScript(url: string, removeElement = false) {
- const promiseKey = url.trim();
- // @NOTE: Take Promise from cache if script is already loading/loaded (otherwise it will reload and reload all contexts)
- if (dynamicScriptPromises.has(promiseKey)) return dynamicScriptPromises.get(promiseKey)!;
- const scriptPromise = new Promise((resolve, reject) => {
- const element = document.createElement('script');
- element.src = url;
- element.type = 'text/javascript';
- element.async = true;
- element.onload = () => {
- resolve(element);
- if (removeElement) document.head.removeChild(element);
- };
- element.onerror = (event, source, lineno, colno, error) => {
- reject(event);
- if (removeElement) document.head.removeChild(element);
- dynamicScriptPromises.delete(promiseKey);
- };
- document.head.appendChild(element);
- });
- dynamicScriptPromises.set(promiseKey, scriptPromise);
- return scriptPromise;
- }
- /**
- * Dynamically load remote module
- * @param scope - appName
- * @param module - './AppComponent'
- * @see https://github.com/webpack/webpack/issues/11033#issuecomment-644349386
- */
- export function loadRemoteModule(scope: string, module: string) {
- return async () => {
- // Initializes the share scope. This fills it with known provided modules from this build and all remotes
- await __webpack_init_sharing__('default');
- // @ts-expect-error // @ERROR: TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'.
- const container = window[scope] as Container; // or get the container somewhere else
- // Initialize the container, it may provide shared modules
- await container.init(__webpack_share_scopes__.default);
- const factory = await container.get(module);
- const Module = factory();
- return Module;
- };
- }
- /**
- * Creates React.lazy component for provided `scope@url` and `module`
- * @description equivalent to
- *
- * `const App = React.lazy(() => import('appName/AppComponent'))`
- * @param url - https://example.org/remoteEntry.js
- * @param scope - appName
- * @param module - './AppComponent'
- */
- export function loadDynamicComponent<T extends React.ComponentType<any>>(
- url: string,
- scope: string,
- module: string,
- ): React.LazyExoticComponent<T> {
- const Component: React.LazyExoticComponent<T> = React.lazy(() => {
- return loadDynamicScript(url).then(loadRemoteModule(scope, module));
- });
- return Component;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement