Skip to content

Commit

Permalink
refactor: add generic way of exposing as esmodules
Browse files Browse the repository at this point in the history
  • Loading branch information
mariobuikhuizen committed Dec 19, 2023
1 parent 744cc40 commit 751f1c6
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 247 deletions.
246 changes: 14 additions & 232 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,239 +45,21 @@ export async function setUpMuiFixModule() {
return await importShim(url);
}

export function expose(module: any) {
const id = "_ipyreact_" + (Math.random()).toString(36);
// @ts-ignore
window[id] = module;
const names = Object.keys(module).filter(n => n !== "default").join(", ")
return toModuleUrl(`
const { ${names} } = window["${id}"];
export default window["${id}"].default;
delete window["${id}"];
export { ${names} };`)
}



export async function setUpReact16ESM() {
let urlReact = URL.createObjectURL(
new Blob([`
let r = window.React16FromIpyReact;
const Children = r.Children;
const Component = r.Component;
const Fragment = r.Fragment;
const Profiler = r.Profiler;
const PureComponent = r.PureComponent;
const StrictMode = r.StrictMode;
const Suspense = r.Suspense;
const cloneElement = r.cloneElement;
const createContext = r.createContext;
const createElement = r.createElement;
const createFactory = r.createFactory;
const createRef = r.createRef;
const forwardRef = r.forwardRef;
const isValidElement = r.isValidElement;
const lazy = r.lazy;
const memo = r.memo;
const startTransition = r.startTransition;
const unstable_act = r.unstable_act;
const useCallback = r.useCallback;
const useContext = r.useContext;
const useDebugValue = r.useDebugValue;
const useDeferredValue = r.useDeferredValue;
const useEffect = r.useEffect;
const useId = r.useId;
const useImperativeHandle = r.useImperativeHandle;
const useInsertionEffect = r.useInsertionEffect;
const useLayoutEffect = r.useLayoutEffect;
const useMemo = r.useMemo;
const useReducer = r.useReducer;
const useRef = r.useRef;
const useState = r.useState;
const useSyncExternalStore = r.useSyncExternalStore;
const useTransition = r.useTransition;
const version = r.version;
const __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
export default r.default;
export {
Children,
Component,
Fragment,
Profiler,
PureComponent,
StrictMode,
Suspense,
cloneElement,
createContext,
createElement,
createFactory,
createRef,
forwardRef,
isValidElement,
lazy,
memo,
startTransition,
unstable_act,
useCallback,
useContext,
useDebugValue,
useDeferredValue,
useEffect,
useId,
useImperativeHandle,
useInsertionEffect,
useLayoutEffect,
useMemo,
useReducer,
useRef,
useState,
useSyncExternalStore,
useTransition,
version,
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
};`
], { type: "text/javascript" }),
);
let urlReactDom = URL.createObjectURL(
new Blob([`
let r = window.ReactDOM16FromIpyReact;
const createPortal = r.createPortal;
const createRoot = r.createRoot;
const findDOMNode = r.findDOMNode;
const flushSync = r.flushSync;
const hydrate = r.hydrate;
const hydrateRoot = r.hydrateRoot;
const render = r.render;
const unmountComponentAtNode = r.unmountComponentAtNode;
const unstable_batchedUpdates = r.unstable_batchedUpdates;
const unstable_renderSubtreeIntoContainer = r.unstable_renderSubtreeIntoContainer;
const version = r.version;
const __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
export default r.default;
export {
createPortal,
createRoot,
findDOMNode,
flushSync,
hydrate,
hydrateRoot,
render,
unmountComponentAtNode,
unstable_batchedUpdates,
unstable_renderSubtreeIntoContainer,
version,
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
};`
], { type: "text/javascript" }),
);
return {urlReact, urlReactDom};
}


export async function setUpReact18ESM() {
let urlReact = URL.createObjectURL(
new Blob([`
let r = window.React18FromIpyReact;
const Children = r.Children;
const Component = r.Component;
const Fragment = r.Fragment;
const Profiler = r.Profiler;
const PureComponent = r.PureComponent;
const StrictMode = r.StrictMode;
const Suspense = r.Suspense;
const cloneElement = r.cloneElement;
const createContext = r.createContext;
const createElement = r.createElement;
const createFactory = r.createFactory;
const createRef = r.createRef;
const forwardRef = r.forwardRef;
const isValidElement = r.isValidElement;
const lazy = r.lazy;
const memo = r.memo;
const startTransition = r.startTransition;
const unstable_act = r.unstable_act;
const useCallback = r.useCallback;
const useContext = r.useContext;
const useDebugValue = r.useDebugValue;
const useDeferredValue = r.useDeferredValue;
const useEffect = r.useEffect;
const useId = r.useId;
const useImperativeHandle = r.useImperativeHandle;
const useInsertionEffect = r.useInsertionEffect;
const useLayoutEffect = r.useLayoutEffect;
const useMemo = r.useMemo;
const useReducer = r.useReducer;
const useRef = r.useRef;
const useState = r.useState;
const useSyncExternalStore = r.useSyncExternalStore;
const useTransition = r.useTransition;
const version = r.version;
const __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
export default r.default;
export {
Children,
Component,
Fragment,
Profiler,
PureComponent,
StrictMode,
Suspense,
cloneElement,
createContext,
createElement,
createFactory,
createRef,
forwardRef,
isValidElement,
lazy,
memo,
startTransition,
unstable_act,
useCallback,
useContext,
useDebugValue,
useDeferredValue,
useEffect,
useId,
useImperativeHandle,
useInsertionEffect,
useLayoutEffect,
useMemo,
useReducer,
useRef,
useState,
useSyncExternalStore,
useTransition,
version,
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
};`
], { type: "text/javascript" }),
);
let urlReactDom = URL.createObjectURL(
new Blob([`
let r = window.ReactDOM18FromIpyReact;
const createPortal = r.createPortal;
const createRoot = r.createRoot;
const findDOMNode = r.findDOMNode;
const flushSync = r.flushSync;
const hydrate = r.hydrate;
const hydrateRoot = r.hydrateRoot;
const render = r.render;
const unmountComponentAtNode = r.unmountComponentAtNode;
const unstable_batchedUpdates = r.unstable_batchedUpdates;
const unstable_renderSubtreeIntoContainer = r.unstable_renderSubtreeIntoContainer;
const version = r.version;
const __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
export default r.default;
export {
createPortal,
createRoot,
findDOMNode,
flushSync,
hydrate,
hydrateRoot,
render,
unmountComponentAtNode,
unstable_batchedUpdates,
unstable_renderSubtreeIntoContainer,
version,
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
};`
], { type: "text/javascript" }),
);
return {urlReact, urlReactDom};
}
export function toModuleUrl(code: string) {
return URL.createObjectURL(new Blob([code], { type: "text/javascript" }));
}

export async function loadScript(type: string, src: string) {
const script = document.createElement("script")
Expand Down
22 changes: 7 additions & 15 deletions src/widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import * as ReactDOM from 'react-dom';
import * as ReactDOMClient from 'react-dom/client';
// @ts-ignore
import '../css/widget.css';
import { loadScript, setUpMuiFixModule, setUpReact16ESM, setUpReact18ESM } from './utils';
import { expose, loadScript, setUpMuiFixModule } from './utils';
import { MODULE_NAME, MODULE_VERSION } from './version';
// import * as Babel from '@babel/standalone';
// TODO: find a way to ship es-module-shims with the widget
Expand Down Expand Up @@ -62,17 +62,17 @@ window.esmsInitOptions = { shimMode: true,
let react18ESMUrls : any = null;
let react16ESMUrls : any = null;

async function ensureReactSetup(version: number) {
function ensureReactSetup(version: number) {
if(version == 18) {
if(react18ESMUrls == null) {
react18ESMUrls = setUpReact18ESM();
react18ESMUrls = {urlReact: expose(React), urlReactDom: expose(ReactDOM)};
}
return await react18ESMUrls;
return react18ESMUrls;
} else if(version == 16) {
if(react16ESMUrls == null) {
react16ESMUrls = setUpReact16ESM();
// react16ESMUrls = {urlReact: expose(React16), urlReactDom: expose(ReactDOM16)};
}
return await react16ESMUrls;
return react16ESMUrls;
}
}

Expand Down Expand Up @@ -109,14 +109,6 @@ export class ReactModel extends DOMWidgetModel {

export class ReactView extends DOMWidgetView {
render() {
// @ts-ignore
window.React18FromIpyReact = React;
// @ts-ignore
// window.React16FromIpyReact = React16;
// @ts-ignore
window.ReactDOM18FromIpyReact = ReactDOM;
// @ts-ignore
// window.ReactDOM16FromIpyReact = ReactDOM16;
this.el.classList.add('jupyter-react-widget');
// using babel is a bit of an art, so leaving this code for if we
// want to switch back to babel. However, babel is very large compared
Expand Down Expand Up @@ -207,7 +199,7 @@ export class ReactView extends DOMWidgetView {
setScope(compiledCode);
return;
}
const {urlReact, urlReactDom} = await ensureReactSetup(this.model.get("react_version"));
const {urlReact, urlReactDom} = ensureReactSetup(this.model.get("react_version"));
await ensureImportShimLoaded();
let finalCode = compiledCode;
// @ts-ignore
Expand Down

0 comments on commit 751f1c6

Please sign in to comment.