Fix require monkey-patching in electron build
Summary:
In D39311893 (094c5bdfdd) we started monkey-patching `require` to resolve global dependencies in the plugins. Apparently, patching `globalThis.require` did not work in the electron env. On my local machine it kept working because I had the experimental `flipper-server` feature enabled which embeds flipper-server into the electron build. In flipper-server we properly patch `require` via `Module.prototype.require` which affected the global require in electron.
With this fix we now properly patch require in electron via Module.prototype.require all the time
Changelog: Fix plugin loading with experimental flipper-server disabled
Reviewed By: nikoant
Differential Revision: D39633821
fbshipit-source-id: 9554f643c625620d116075ae87f573d8447850f6
This commit is contained in:
committed by
Facebook GitHub Bot
parent
d600203627
commit
8716761cb3
@@ -37,6 +37,7 @@ import {
|
|||||||
parseEnvironmentVariables,
|
parseEnvironmentVariables,
|
||||||
setLoggerInstance,
|
setLoggerInstance,
|
||||||
Settings,
|
Settings,
|
||||||
|
wrapRequire,
|
||||||
} from 'flipper-common';
|
} from 'flipper-common';
|
||||||
import constants from './fb-stubs/constants';
|
import constants from './fb-stubs/constants';
|
||||||
import {initializeElectron} from './electron/initializeElectron';
|
import {initializeElectron} from './electron/initializeElectron';
|
||||||
@@ -48,7 +49,9 @@ import {KeytarModule} from 'flipper-server-core/src/utils/keytar';
|
|||||||
import {initCompanionEnv} from 'flipper-server-companion';
|
import {initCompanionEnv} from 'flipper-server-companion';
|
||||||
import ReconnectingWebSocket from 'reconnecting-websocket';
|
import ReconnectingWebSocket from 'reconnecting-websocket';
|
||||||
import WS from 'ws';
|
import WS from 'ws';
|
||||||
|
import {Module} from 'module';
|
||||||
|
|
||||||
|
Module.prototype.require = wrapRequire(Module.prototype.require);
|
||||||
enableMapSet();
|
enableMapSet();
|
||||||
|
|
||||||
async function getKeytarModule(staticPath: string): Promise<KeytarModule> {
|
async function getKeytarModule(staticPath: string): Promise<KeytarModule> {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// This list should match `dispatcher/plugins.tsx` and `builtInModules` in `desktop/.eslintrc.js`
|
// This list should match `flipper-frontend-core/src/globalObject.tsx` and `builtInModules` in `desktop/.eslintrc.js`
|
||||||
export const pluginExternalModules = {
|
export const pluginExternalModules = {
|
||||||
flipper: 'Flipper',
|
flipper: 'Flipper',
|
||||||
'flipper-plugin': 'FlipperPlugin',
|
'flipper-plugin': 'FlipperPlugin',
|
||||||
@@ -19,6 +19,8 @@ export const pluginExternalModules = {
|
|||||||
immer: 'Immer',
|
immer: 'Immer',
|
||||||
'@emotion/styled': 'emotion_styled',
|
'@emotion/styled': 'emotion_styled',
|
||||||
'@ant-design/icons': 'antdesign_icons',
|
'@ant-design/icons': 'antdesign_icons',
|
||||||
|
// Used by "bloks-logger" (see its bundle's content)
|
||||||
|
'react/jsx-runtime': 'ReactJsxRuntime',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const wrapRequire = <T extends (path: string) => any>(require: T): T =>
|
export const wrapRequire = <T extends (path: string) => any>(require: T): T =>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export interface GlobalObject {
|
|||||||
antd: any;
|
antd: any;
|
||||||
emotion_styled: any;
|
emotion_styled: any;
|
||||||
antdesign_icons: any;
|
antdesign_icons: any;
|
||||||
|
ReactJsxRuntime: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module globalThis {
|
declare module globalThis {
|
||||||
@@ -32,6 +33,7 @@ declare module globalThis {
|
|||||||
let antd: any;
|
let antd: any;
|
||||||
let emotion_styled: any;
|
let emotion_styled: any;
|
||||||
let antdesign_icons: any;
|
let antdesign_icons: any;
|
||||||
|
let ReactJsxRuntime: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const setGlobalObject = (replacements: GlobalObject) => {
|
export const setGlobalObject = (replacements: GlobalObject) => {
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export const initCompanionEnv = async (
|
|||||||
antd: {},
|
antd: {},
|
||||||
emotion_styled: {default: styled},
|
emotion_styled: {default: styled},
|
||||||
antdesign_icons: {},
|
antdesign_icons: {},
|
||||||
|
ReactJsxRuntime: {},
|
||||||
});
|
});
|
||||||
Module.prototype.require = wrapRequire(Module.prototype.require);
|
Module.prototype.require = wrapRequire(Module.prototype.require);
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,29 @@
|
|||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {FlipperServer, FlipperServerConfig, isProduction} from 'flipper-common';
|
import {
|
||||||
|
FlipperServer,
|
||||||
|
FlipperServerConfig,
|
||||||
|
isProduction,
|
||||||
|
wrapRequire,
|
||||||
|
} from 'flipper-common';
|
||||||
import type {RenderHost} from 'flipper-ui-core';
|
import type {RenderHost} from 'flipper-ui-core';
|
||||||
|
|
||||||
|
declare module globalThis {
|
||||||
|
let require: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Whenever we bundle plugins, we assume that they are going to share some modules - React, React-DOM, ant design and etc.
|
||||||
|
// It allows us to decrease the bundle size and not to create separate React roots for every plugin
|
||||||
|
// To tell a plugin that a module is going to be provided externally, we add the module to the list of externals (see https://esbuild.github.io/api/#external).
|
||||||
|
// As a result, esbuild does not bundle hte contents of the module. Instead, it wraps the module name with `require(...)`.
|
||||||
|
// `require` does not exist ion the browser environment, so we substitute it here to feed the plugin our global module.
|
||||||
|
globalThis.require = wrapRequire((module: string) => {
|
||||||
|
throw new Error(
|
||||||
|
`Dynamic require is not supported in browser envs. Tried to require: ${module}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
export function initializeRenderHost(
|
export function initializeRenderHost(
|
||||||
flipperServer: FlipperServer,
|
flipperServer: FlipperServer,
|
||||||
flipperServerConfig: FlipperServerConfig,
|
flipperServerConfig: FlipperServerConfig,
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ import {
|
|||||||
InstalledPluginDetails,
|
InstalledPluginDetails,
|
||||||
Logger,
|
Logger,
|
||||||
MarketplacePluginDetails,
|
MarketplacePluginDetails,
|
||||||
wrapRequire,
|
|
||||||
} from 'flipper-common';
|
} from 'flipper-common';
|
||||||
import {PluginDefinition} from '../plugin';
|
import {PluginDefinition} from '../plugin';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import * as ReactJsxRuntime from 'react/jsx-runtime';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import ReactDOMClient from 'react-dom/client';
|
import ReactDOMClient from 'react-dom/client';
|
||||||
import ReactIs from 'react-is';
|
import ReactIs from 'react-is';
|
||||||
@@ -101,10 +101,6 @@ class UIPluginInitializer extends AbstractPluginInitializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module globalThis {
|
|
||||||
let require: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
let uiPluginInitializer: UIPluginInitializer;
|
let uiPluginInitializer: UIPluginInitializer;
|
||||||
export default async (store: Store, _logger: Logger) => {
|
export default async (store: Store, _logger: Logger) => {
|
||||||
setGlobalObject({
|
setGlobalObject({
|
||||||
@@ -118,21 +114,8 @@ export default async (store: Store, _logger: Logger) => {
|
|||||||
antd,
|
antd,
|
||||||
emotion_styled,
|
emotion_styled,
|
||||||
antdesign_icons,
|
antdesign_icons,
|
||||||
|
ReactJsxRuntime,
|
||||||
});
|
});
|
||||||
// Whenever we bundle plugins, we assume that they are going to share some modules - React, React-DOM, ant design and etc.
|
|
||||||
// It allows us to decrease the bundle size and not to create separate React roots for every plugin
|
|
||||||
// To tell a plugin that a module is going to be provided externally, we add the module to the list of externals (see https://esbuild.github.io/api/#external).
|
|
||||||
// As a result, esbuild does not bundle hte contents of the module. Instead, it wraps the module name with `require(...)`.
|
|
||||||
// `require` does not exist ion the browser environment, so we substitute it here to feed the plugin our global module.
|
|
||||||
globalThis.require = wrapRequire(
|
|
||||||
// globalThis.require might exist in the electron build
|
|
||||||
globalThis.require ??
|
|
||||||
((module: string) => {
|
|
||||||
throw new Error(
|
|
||||||
`Dynamic require is not supported in browser envs. Tried to require: ${module}`,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
uiPluginInitializer = new UIPluginInitializer(store);
|
uiPluginInitializer = new UIPluginInitializer(store);
|
||||||
await uiPluginInitializer.init();
|
await uiPluginInitializer.init();
|
||||||
|
|||||||
Reference in New Issue
Block a user