remove window dependency
Summary: Fixes required to be able to run Flipper in node.js: * Adds checks if the `window`-object exists before using it, to allow running in node. * Imports from within Flipper should directly reference the file they are requiring instead of `import from 'flipper'`. This was done in most of the places. Fixed a few occurrences where this wasn't the case. This is to prevent cyclic dependencies in node. * shared packages (React, ReactDOM and Flipper) were exposed on the `window` before, changed this to `global` as this works in browser and node. * Adds some missing methods to our electron stubs (used for testing and headless Flipper) Reviewed By: passy Differential Revision: D13786577 fbshipit-source-id: 145d560f1446e7d0bdec2acd8dd54dae983d7b36
This commit is contained in:
committed by
Facebook Github Bot
parent
7ac6a09af1
commit
771be72b3f
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import {Sidebar} from 'flipper';
|
import Sidebar from '../ui/components/Sidebar';
|
||||||
import {connect} from 'react-redux';
|
import {connect} from 'react-redux';
|
||||||
import {toggleRightSidebarAvailable} from '../reducers/application.js';
|
import {toggleRightSidebarAvailable} from '../reducers/application.js';
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ type Props = {
|
|||||||
children: any,
|
children: any,
|
||||||
rightSidebarVisible: boolean,
|
rightSidebarVisible: boolean,
|
||||||
rightSidebarAvailable: boolean,
|
rightSidebarAvailable: boolean,
|
||||||
toggleRightSidebarAvailable: (visible: boolean) => void,
|
toggleRightSidebarAvailable: (visible?: boolean) => any,
|
||||||
width?: number,
|
width?: number,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,14 @@ import type {
|
|||||||
TableColumnSizes,
|
TableColumnSizes,
|
||||||
TableColumns,
|
TableColumns,
|
||||||
} from 'flipper';
|
} from 'flipper';
|
||||||
import {FlexColumn, Button, DetailSidebar} from 'flipper';
|
|
||||||
|
import FlexColumn from './ui/components/FlexColumn';
|
||||||
|
import Button from './ui/components/Button';
|
||||||
|
import DetailSidebar from './chrome/DetailSidebar';
|
||||||
|
import {FlipperPlugin} from './plugin';
|
||||||
|
import SearchableTable from './ui/components/searchable/SearchableTable';
|
||||||
import textContent from './utils/textContent.js';
|
import textContent from './utils/textContent.js';
|
||||||
import createPaste from './utils/createPaste.js';
|
import createPaste from './utils/createPaste.js';
|
||||||
import {FlipperPlugin, SearchableTable} from 'flipper';
|
|
||||||
|
|
||||||
type ID = string;
|
type ID = string;
|
||||||
|
|
||||||
|
|||||||
@@ -46,9 +46,12 @@ function forwardPort(port: number, multiplexChannelPort: number) {
|
|||||||
const portForwarders: Array<ChildProcess> = GK.get('flipper_ios_device_support')
|
const portForwarders: Array<ChildProcess> = GK.get('flipper_ios_device_support')
|
||||||
? [forwardPort(8089, 8079), forwardPort(8088, 8078)]
|
? [forwardPort(8089, 8079), forwardPort(8088, 8078)]
|
||||||
: [];
|
: [];
|
||||||
window.addEventListener('beforeunload', () => {
|
|
||||||
portForwarders.forEach(process => process.kill());
|
if (typeof window !== 'undefined') {
|
||||||
});
|
window.addEventListener('beforeunload', () => {
|
||||||
|
portForwarders.forEach(process => process.kill());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function queryDevices(store: Store, logger: Logger): Promise<void> {
|
function queryDevices(store: Store, logger: Logger): Promise<void> {
|
||||||
const {connections} = store.getState();
|
const {connections} = store.getState();
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import type {State} from '../reducers/plugins';
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import * as Flipper from 'flipper';
|
import * as Flipper from '../index.js';
|
||||||
import {
|
import {
|
||||||
registerPlugins,
|
registerPlugins,
|
||||||
addGatekeepedPlugins,
|
addGatekeepedPlugins,
|
||||||
@@ -20,11 +20,9 @@ import {
|
|||||||
addFailedPlugins,
|
addFailedPlugins,
|
||||||
} from '../reducers/plugins';
|
} from '../reducers/plugins';
|
||||||
import {remote} from 'electron';
|
import {remote} from 'electron';
|
||||||
import {GK} from 'flipper';
|
import GK from '../fb-stubs/GK';
|
||||||
import {FlipperBasePlugin} from '../plugin.js';
|
import {FlipperBasePlugin} from '../plugin.js';
|
||||||
import {setupMenuBar} from '../MenuBar.js';
|
import {setupMenuBar} from '../MenuBar.js';
|
||||||
import {setPluginState} from '../reducers/pluginStates.js';
|
|
||||||
import {getPersistedState} from '../utils/pluginUtils.js';
|
|
||||||
|
|
||||||
export type PluginDefinition = {
|
export type PluginDefinition = {
|
||||||
name: string,
|
name: string,
|
||||||
@@ -35,9 +33,10 @@ export type PluginDefinition = {
|
|||||||
|
|
||||||
export default (store: Store, logger: Logger) => {
|
export default (store: Store, logger: Logger) => {
|
||||||
// expose Flipper and exact globally for dynamically loaded plugins
|
// expose Flipper and exact globally for dynamically loaded plugins
|
||||||
window.React = React;
|
const globalObject = typeof window === 'undefined' ? global : window;
|
||||||
window.ReactDOM = ReactDOM;
|
globalObject.React = React;
|
||||||
window.Flipper = Flipper;
|
globalObject.ReactDOM = ReactDOM;
|
||||||
|
globalObject.Flipper = Flipper;
|
||||||
|
|
||||||
const gatekeepedPlugins: Array<PluginDefinition> = [];
|
const gatekeepedPlugins: Array<PluginDefinition> = [];
|
||||||
const disabledPlugins: Array<PluginDefinition> = [];
|
const disabledPlugins: Array<PluginDefinition> = [];
|
||||||
@@ -74,7 +73,7 @@ function getBundledPlugins(): Array<PluginDefinition> {
|
|||||||
// List of defaultPlugins is written at build time
|
// List of defaultPlugins is written at build time
|
||||||
let bundledPlugins: Array<PluginDefinition> = [];
|
let bundledPlugins: Array<PluginDefinition> = [];
|
||||||
try {
|
try {
|
||||||
bundledPlugins = window.electronRequire('./defaultPlugins/index.json');
|
bundledPlugins = global.electronRequire('./defaultPlugins/index.json');
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
return bundledPlugins.map(plugin => ({
|
return bundledPlugins.map(plugin => ({
|
||||||
@@ -86,8 +85,10 @@ function getBundledPlugins(): Array<PluginDefinition> {
|
|||||||
export function getDynamicPlugins() {
|
export function getDynamicPlugins() {
|
||||||
let dynamicPlugins: Array<PluginDefinition> = [];
|
let dynamicPlugins: Array<PluginDefinition> = [];
|
||||||
try {
|
try {
|
||||||
// $FlowFixMe process.env not defined in electron API spec
|
dynamicPlugins = JSON.parse(
|
||||||
dynamicPlugins = JSON.parse(remote?.process.env.PLUGINS || '[]');
|
// $FlowFixMe process.env not defined in electron API spec
|
||||||
|
remote?.process.env.PLUGINS || process.env.PLUGINS || '[]',
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
@@ -119,7 +120,8 @@ export const checkDisabled = (disabledPlugins: Array<PluginDefinition>) => (
|
|||||||
try {
|
try {
|
||||||
disabledList = new Set(
|
disabledList = new Set(
|
||||||
// $FlowFixMe process.env not defined in electron API spec
|
// $FlowFixMe process.env not defined in electron API spec
|
||||||
JSON.parse(remote?.process.env.CONFIG || '{}').disabledPlugins || [],
|
JSON.parse(remote?.process.env.CONFIG || process.env.CONFIG || '{}')
|
||||||
|
.disabledPlugins || [],
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
@@ -134,13 +136,13 @@ export const checkDisabled = (disabledPlugins: Array<PluginDefinition>) => (
|
|||||||
|
|
||||||
export const requirePlugin = (
|
export const requirePlugin = (
|
||||||
failedPlugins: Array<[PluginDefinition, string]>,
|
failedPlugins: Array<[PluginDefinition, string]>,
|
||||||
requireFunction: Function = window.electronRequire,
|
reqFn: Function = global.electronRequire,
|
||||||
) => {
|
) => {
|
||||||
return (
|
return (
|
||||||
pluginDefinition: PluginDefinition,
|
pluginDefinition: PluginDefinition,
|
||||||
): ?Class<FlipperPlugin<> | FlipperDevicePlugin<>> => {
|
): ?Class<FlipperPlugin<> | FlipperDevicePlugin<>> => {
|
||||||
try {
|
try {
|
||||||
let plugin = requireFunction(pluginDefinition.out);
|
let plugin = reqFn(pluginDefinition.out);
|
||||||
if (plugin.default) {
|
if (plugin.default) {
|
||||||
plugin = plugin.default;
|
plugin = plugin.default;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,9 @@ export default (store: Store, logger: Logger) => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
window.addEventListener('beforeunload', () => {
|
if (typeof window !== 'undefined') {
|
||||||
server.close();
|
window.addEventListener('beforeunload', () => {
|
||||||
});
|
server.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -29,10 +29,12 @@ export default (store: Store, logger: Logger) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
droppedFrameDetection(
|
if (typeof window !== 'undefined') {
|
||||||
performance.now(),
|
droppedFrameDetection(
|
||||||
() => store.getState().application.windowIsFocused,
|
performance.now(),
|
||||||
);
|
() => store.getState().application.windowIsFocused,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
ipcRenderer.on('trackUsage', () => {
|
ipcRenderer.on('trackUsage', () => {
|
||||||
const {
|
const {
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ import type {Store} from './reducers/index.js';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import type {Node} from 'react';
|
import type {Node} from 'react';
|
||||||
import BaseDevice from './devices/BaseDevice.js';
|
import BaseDevice from './devices/BaseDevice.js';
|
||||||
import {AndroidDevice, IOSDevice} from 'flipper';
|
import AndroidDevice from './devices/AndroidDevice';
|
||||||
|
import IOSDevice from './devices/IOSDevice';
|
||||||
|
|
||||||
const invariant = require('invariant');
|
const invariant = require('invariant');
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
maybeSnapTop,
|
maybeSnapTop,
|
||||||
SNAP_SIZE,
|
SNAP_SIZE,
|
||||||
} from '../../utils/snap.js';
|
} from '../../utils/snap.js';
|
||||||
import {styled} from '../../ui';
|
import styled from '../styled/index.js';
|
||||||
|
|
||||||
const invariant = require('invariant');
|
const invariant = require('invariant');
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
import {Link} from 'flipper';
|
import Link from '../Link';
|
||||||
import type {DataInspectorSetValue} from './DataInspector.js';
|
import type {DataInspectorSetValue} from './DataInspector.js';
|
||||||
import {PureComponent} from 'react';
|
import {PureComponent} from 'react';
|
||||||
import styled from '../../styled/index.js';
|
import styled from '../../styled/index.js';
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import Panel from '../Panel.js';
|
|||||||
import ManagedDataInspector from '../data-inspector/ManagedDataInspector.js';
|
import ManagedDataInspector from '../data-inspector/ManagedDataInspector.js';
|
||||||
import {Component} from 'react';
|
import {Component} from 'react';
|
||||||
import {Console} from '../console';
|
import {Console} from '../console';
|
||||||
import {GK} from 'flipper';
|
import GK from '../../../fb-stubs/GK';
|
||||||
|
|
||||||
const deepEqual = require('deep-equal');
|
const deepEqual = require('deep-equal');
|
||||||
|
|
||||||
|
|||||||
@@ -96,7 +96,9 @@ export function getIconUrl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let requestedScale: number = window.devicePixelRatio;
|
let requestedScale: number =
|
||||||
|
typeof window !== 'undefined' ? window.devicePixelRatio : 1;
|
||||||
|
|
||||||
if (!SCALE.includes(requestedScale)) {
|
if (!SCALE.includes(requestedScale)) {
|
||||||
// find the next largest size
|
// find the next largest size
|
||||||
const possibleScale: ?number = SCALE.find(scale => {
|
const possibleScale: ?number = SCALE.find(scale => {
|
||||||
|
|||||||
@@ -5,11 +5,25 @@
|
|||||||
},
|
},
|
||||||
getCurrentWindow: function() {
|
getCurrentWindow: function() {
|
||||||
return {
|
return {
|
||||||
isFocused: function() {return true;}
|
isFocused: function() {return true;},
|
||||||
|
on: function() {return true;}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
app: {
|
app: {
|
||||||
getVersion: function() {return '1';}
|
getVersion: function() {return '1';},
|
||||||
|
getName: function() {return '';}
|
||||||
|
},
|
||||||
|
shell: {
|
||||||
|
openExternal: function() {}
|
||||||
|
},
|
||||||
|
Menu: {
|
||||||
|
buildFromTemplate: function() {
|
||||||
|
return {items: []}
|
||||||
|
},
|
||||||
|
setApplicationMenu: function() {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
ipcRenderer: {
|
||||||
|
on: function() {return true;}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,36 +17,36 @@ const babelOptions = {
|
|||||||
filename: 'index.js',
|
filename: 'index.js',
|
||||||
};
|
};
|
||||||
|
|
||||||
test('transform react requires to global window', () => {
|
test('transform react requires to global object', () => {
|
||||||
const src = 'require("react")';
|
const src = 'require("react")';
|
||||||
const ast = parse(src);
|
const ast = parse(src);
|
||||||
const transformed = transformFromAstSync(ast, src, babelOptions).ast;
|
const transformed = transformFromAstSync(ast, src, babelOptions).ast;
|
||||||
const {code} = generate(transformed);
|
const {code} = generate(transformed);
|
||||||
expect(code).toBe('window.React;');
|
expect(code).toBe('global.React;');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('transform react-dom requires to global window', () => {
|
test('transform react-dom requires to global object', () => {
|
||||||
const src = 'require("react-dom")';
|
const src = 'require("react-dom")';
|
||||||
const ast = parse(src);
|
const ast = parse(src);
|
||||||
const transformed = transformFromAstSync(ast, src, babelOptions).ast;
|
const transformed = transformFromAstSync(ast, src, babelOptions).ast;
|
||||||
const {code} = generate(transformed);
|
const {code} = generate(transformed);
|
||||||
expect(code).toBe('window.ReactDOM;');
|
expect(code).toBe('global.ReactDOM;');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('transform flipper requires to global window', () => {
|
test('transform flipper requires to global object', () => {
|
||||||
const src = 'require("flipper")';
|
const src = 'require("flipper")';
|
||||||
const ast = parse(src);
|
const ast = parse(src);
|
||||||
const transformed = transformFromAstSync(ast, src, babelOptions).ast;
|
const transformed = transformFromAstSync(ast, src, babelOptions).ast;
|
||||||
const {code} = generate(transformed);
|
const {code} = generate(transformed);
|
||||||
expect(code).toBe('window.Flipper;');
|
expect(code).toBe('global.Flipper;');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('transform React identifier to window.React', () => {
|
test('transform React identifier to global.React', () => {
|
||||||
const src = 'React;';
|
const src = 'React;';
|
||||||
const ast = parse(src);
|
const ast = parse(src);
|
||||||
const transformed = transformFromAstSync(ast, src, babelOptions).ast;
|
const transformed = transformFromAstSync(ast, src, babelOptions).ast;
|
||||||
const {code} = generate(transformed);
|
const {code} = generate(transformed);
|
||||||
expect(code).toBe('window.React;');
|
expect(code).toBe('global.React;');
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('throw error when requiring outside the plugin', () => {
|
test.skip('throw error when requiring outside the plugin', () => {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ const BUILTINS = [
|
|||||||
'assert',
|
'assert',
|
||||||
'util',
|
'util',
|
||||||
'path',
|
'path',
|
||||||
|
'perf_hooks',
|
||||||
'punycode',
|
'punycode',
|
||||||
'querystring',
|
'querystring',
|
||||||
'cluster',
|
'cluster',
|
||||||
|
|||||||
@@ -37,11 +37,11 @@ module.exports = ({types: t}) => ({
|
|||||||
t.isStringLiteral(args[0])
|
t.isStringLiteral(args[0])
|
||||||
) {
|
) {
|
||||||
if (args[0].value === 'flipper') {
|
if (args[0].value === 'flipper') {
|
||||||
path.replaceWith(t.identifier('window.Flipper'));
|
path.replaceWith(t.identifier('global.Flipper'));
|
||||||
} else if (args[0].value === 'react') {
|
} else if (args[0].value === 'react') {
|
||||||
path.replaceWith(t.identifier('window.React'));
|
path.replaceWith(t.identifier('global.React'));
|
||||||
} else if (args[0].value === 'react-dom') {
|
} else if (args[0].value === 'react-dom') {
|
||||||
path.replaceWith(t.identifier('window.ReactDOM'));
|
path.replaceWith(t.identifier('global.ReactDOM'));
|
||||||
} else if (
|
} else if (
|
||||||
// require a file not a pacakge
|
// require a file not a pacakge
|
||||||
args[0].value.indexOf('/') > -1 &&
|
args[0].value.indexOf('/') > -1 &&
|
||||||
@@ -70,7 +70,7 @@ module.exports = ({types: t}) => ({
|
|||||||
path.parentPath.node.id !== path.node &&
|
path.parentPath.node.id !== path.node &&
|
||||||
!isExcludedPath(state.file.opts.filename)
|
!isExcludedPath(state.file.opts.filename)
|
||||||
) {
|
) {
|
||||||
path.replaceWith(t.identifier('window.React'));
|
path.replaceWith(t.identifier('global.React'));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user