Skip to content

Commit 16d2ce5

Browse files
author
Brian Vaughn
committed
Added hookNames entrypoint to react-devtools-inline
And changed dynamic import() code to be passed in rather than embedded in the package
1 parent 2b4b830 commit 16d2ce5

File tree

10 files changed

+153
-90
lines changed

10 files changed

+153
-90
lines changed

packages/react-devtools-extensions/src/main.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,9 @@ function createPanelIfReactLoaded() {
287287
};
288288
}
289289

290+
const hookNamesModuleLoaderFunction = () =>
291+
import('react-devtools-shared/src/hooks/parseHookNames');
292+
290293
root = createRoot(document.createElement('div'));
291294

292295
render = (overrideTab = mostRecentOverrideTab) => {
@@ -298,6 +301,7 @@ function createPanelIfReactLoaded() {
298301
componentsPortalContainer,
299302
enabledInspectedElementContextMenu: true,
300303
fetchFileWithCaching,
304+
hookNamesModuleLoaderFunction,
301305
overrideTab,
302306
profilerPortalContainer,
303307
showTabBar: false,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require('./dist/hookNames');
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/** @flow */
2+
3+
import {
4+
parseHookNames,
5+
parseSourceAndMetadata,
6+
prefetchSourceFiles,
7+
purgeCachedMetadata,
8+
} from 'react-devtools-shared/src/hooks/parseHookNames';
9+
10+
export {
11+
parseHookNames,
12+
parseSourceAndMetadata,
13+
prefetchSourceFiles,
14+
purgeCachedMetadata,
15+
};

packages/react-devtools-inline/webpack.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ module.exports = {
3737
entry: {
3838
backend: './src/backend.js',
3939
frontend: './src/frontend.js',
40+
hookNames: './src/hookNames.js',
4041
},
4142
output: {
4243
path: __dirname + '/dist',

packages/react-devtools-shared/src/devtools/views/Components/FetchFileWithCachingContext.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
// @flow
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow
8+
*/
29

310
import {createContext} from 'react';
411

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow
8+
*/
9+
10+
import type {Thenable} from 'shared/ReactTypes';
11+
12+
import {createContext} from 'react';
13+
import typeof * as ParseHookNamesModule from 'react-devtools-shared/src/hooks/parseHookNames';
14+
15+
export type HookNamesModuleLoaderFunction = () => Thenable<ParseHookNamesModule>;
16+
export type Context = HookNamesModuleLoaderFunction | null;
17+
18+
const HookNamesModuleLoaderContext = createContext<Context>(null);
19+
HookNamesModuleLoaderContext.displayName = 'HookNamesModuleLoaderContext';
20+
21+
export default HookNamesModuleLoaderContext;

packages/react-devtools-shared/src/devtools/views/Components/InspectedElementContext.js

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
} from 'react-devtools-shared/src/hookNamesCache';
3333
import {loadModule} from 'react-devtools-shared/src/dynamicImportCache';
3434
import FetchFileWithCachingContext from 'react-devtools-shared/src/devtools/views/Components/FetchFileWithCachingContext';
35+
import HookNamesModuleLoaderContext from 'react-devtools-shared/src/devtools/views/Components/HookNamesModuleLoaderContext';
3536
import {SettingsContext} from '../Settings/SettingsContext';
3637
import {enableNamedHooksFeature} from 'react-devtools-feature-flags';
3738

@@ -60,13 +61,6 @@ export const InspectedElementContext = createContext<Context>(
6061

6162
const POLL_INTERVAL = 1000;
6263

63-
// parseHookNames has a lot of code.
64-
// Embedding it into a build makes the build large.
65-
// This component uses Suspense to lazily import() it only if the feature will be used.
66-
function loadHookNamesModuleLoaderFunction() {
67-
return import('react-devtools-shared/src/hooks/parseHookNames');
68-
}
69-
7064
export type Props = {|
7165
children: ReactNodeList,
7266
|};
@@ -78,6 +72,11 @@ export function InspectedElementContextController({children}: Props) {
7872
const store = useContext(StoreContext);
7973
const {parseHookNames: parseHookNamesByDefault} = useContext(SettingsContext);
8074

75+
// parseHookNames has a lot of code.
76+
// Embedding it into a build makes the build large.
77+
// This function enables DevTools to make use of Suspense to lazily import() it only if the feature will be used.
78+
const hookNamesModuleLoader = useContext(HookNamesModuleLoaderContext);
79+
8180
const refresh = useCacheRefresh();
8281

8382
// Temporarily stores most recently-inspected (hydrated) path.
@@ -127,31 +126,31 @@ export function InspectedElementContextController({children}: Props) {
127126
inspectedElement = inspectElement(element, state.path, store, bridge);
128127

129128
if (enableNamedHooksFeature) {
130-
if (parseHookNames || alreadyLoadedHookNames) {
131-
const loadHookNamesModule = loadModule(
132-
loadHookNamesModuleLoaderFunction,
133-
);
134-
if (loadHookNamesModule !== null) {
135-
const {
136-
parseHookNames: loadHookNamesFunction,
137-
prefetchSourceFiles,
138-
purgeCachedMetadata,
139-
} = loadHookNamesModule;
129+
if (typeof hookNamesModuleLoader === 'function') {
130+
if (parseHookNames || alreadyLoadedHookNames) {
131+
const hookNamesModule = loadModule(hookNamesModuleLoader);
132+
if (hookNamesModule !== null) {
133+
const {
134+
parseHookNames: loadHookNamesFunction,
135+
prefetchSourceFiles,
136+
purgeCachedMetadata,
137+
} = hookNamesModule;
140138

141-
purgeCachedMetadataRef.current = purgeCachedMetadata;
142-
prefetchSourceFilesRef.current = prefetchSourceFiles;
139+
purgeCachedMetadataRef.current = purgeCachedMetadata;
140+
prefetchSourceFilesRef.current = prefetchSourceFiles;
143141

144-
if (
145-
inspectedElement !== null &&
146-
inspectedElement.hooks !== null &&
147-
loadHookNamesFunction !== null
148-
) {
149-
hookNames = loadHookNames(
150-
element,
151-
inspectedElement.hooks,
152-
loadHookNamesFunction,
153-
fetchFileWithCaching,
154-
);
142+
if (
143+
inspectedElement !== null &&
144+
inspectedElement.hooks !== null &&
145+
loadHookNamesFunction !== null
146+
) {
147+
hookNames = loadHookNames(
148+
element,
149+
inspectedElement.hooks,
150+
loadHookNamesFunction,
151+
fetchFileWithCaching,
152+
);
153+
}
155154
}
156155
}
157156
}

packages/react-devtools-shared/src/devtools/views/Components/InspectedElementHooksTree.js

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
enableNamedHooksFeature,
2727
enableProfilerChangedHookIndices,
2828
} from 'react-devtools-feature-flags';
29+
import HookNamesModuleLoaderContext from 'react-devtools-shared/src/devtools/views/Components/HookNamesModuleLoaderContext';
2930

3031
import type {InspectedElement} from './types';
3132
import type {HooksNode, HooksTree} from 'react-debug-tools/src/ReactDebugHooks';
@@ -65,6 +66,8 @@ export function InspectedElementHooksTree({
6566
toggleParseHookNames();
6667
};
6768

69+
const hookNamesModuleLoader = useContext(HookNamesModuleLoaderContext);
70+
6871
const hookParsingFailed = parseHookNames && hookNames === null;
6972

7073
let toggleTitle;
@@ -85,16 +88,18 @@ export function InspectedElementHooksTree({
8588
<div className={styles.HooksTreeView}>
8689
<div className={styles.HeaderRow}>
8790
<div className={styles.Header}>hooks</div>
88-
{enableNamedHooksFeature && (!parseHookNames || hookParsingFailed) && (
89-
<Toggle
90-
className={hookParsingFailed ? styles.ToggleError : null}
91-
isChecked={parseHookNamesOptimistic}
92-
isDisabled={parseHookNamesOptimistic || hookParsingFailed}
93-
onChange={handleChange}
94-
title={toggleTitle}>
95-
<ButtonIcon type="parse-hook-names" />
96-
</Toggle>
97-
)}
91+
{enableNamedHooksFeature &&
92+
typeof hookNamesModuleLoader === 'function' &&
93+
(!parseHookNames || hookParsingFailed) && (
94+
<Toggle
95+
className={hookParsingFailed ? styles.ToggleError : null}
96+
isChecked={parseHookNamesOptimistic}
97+
isDisabled={parseHookNamesOptimistic || hookParsingFailed}
98+
onChange={handleChange}
99+
title={toggleTitle}>
100+
<ButtonIcon type="parse-hook-names" />
101+
</Toggle>
102+
)}
98103
<Button onClick={handleCopy} title="Copy to clipboard">
99104
<ButtonIcon type="copy" />
100105
</Button>

packages/react-devtools-shared/src/devtools/views/DevTools.js

Lines changed: 50 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {SettingsContextController} from './Settings/SettingsContext';
2828
import {TreeContextController} from './Components/TreeContext';
2929
import ViewElementSourceContext from './Components/ViewElementSourceContext';
3030
import FetchFileWithCachingContext from './Components/FetchFileWithCachingContext';
31+
import HookNamesModuleLoaderContext from 'react-devtools-shared/src/devtools/views/Components/HookNamesModuleLoaderContext';
3132
import {ProfilerContextController} from './Profiler/ProfilerContext';
3233
import {SchedulingProfilerContextController} from 'react-devtools-scheduling-profiler/src/SchedulingProfilerContext';
3334
import {ModalDialogContextController} from './ModalDialog';
@@ -42,12 +43,10 @@ import styles from './DevTools.css';
4243

4344
import './root.css';
4445

45-
import type {HooksTree} from 'react-debug-tools/src/ReactDebugHooks';
4646
import type {InspectedElement} from 'react-devtools-shared/src/devtools/views/Components/types';
4747
import type {FetchFileWithCaching} from './Components/FetchFileWithCachingContext';
48+
import type {HookNamesModuleLoaderFunction} from 'react-devtools-shared/src/devtools/views/Components/HookNamesModuleLoaderContext';
4849
import type {FrontendBridge} from 'react-devtools-shared/src/bridge';
49-
import type {HookNames} from 'react-devtools-shared/src/types';
50-
import type {Thenable} from '../cache';
5150

5251
export type BrowserTheme = 'dark' | 'light';
5352
export type TabID = 'components' | 'profiler';
@@ -56,9 +55,6 @@ export type ViewElementSource = (
5655
id: number,
5756
inspectedElement: InspectedElement,
5857
) => void;
59-
export type LoadHookNamesFunction = (
60-
hooksTree: HooksTree,
61-
) => Thenable<HookNames>;
6258
export type ViewAttributeSource = (
6359
id: number,
6460
path: Array<string | number>,
@@ -102,6 +98,7 @@ export type Props = {|
10298
// and extracts hook "names" based on the variables the hook return values get assigned to.
10399
// Not every DevTools build can load source maps, so this property is optional.
104100
fetchFileWithCaching?: ?FetchFileWithCaching,
101+
hookNamesModuleLoaderFunction?: ?HookNamesModuleLoaderFunction,
105102
|};
106103

107104
const componentsTab = {
@@ -127,6 +124,7 @@ export default function DevTools({
127124
defaultTab = 'components',
128125
enabledInspectedElementContextMenu = false,
129126
fetchFileWithCaching,
127+
hookNamesModuleLoaderFunction,
130128
overrideTab,
131129
profilerPortalContainer,
132130
showTabBar = false,
@@ -244,52 +242,55 @@ export default function DevTools({
244242
componentsPortalContainer={componentsPortalContainer}
245243
profilerPortalContainer={profilerPortalContainer}>
246244
<ViewElementSourceContext.Provider value={viewElementSource}>
247-
<FetchFileWithCachingContext.Provider
248-
value={fetchFileWithCaching || null}>
249-
<TreeContextController>
250-
<ProfilerContextController>
251-
<SchedulingProfilerContextController>
252-
<ThemeProvider>
253-
<div
254-
className={styles.DevTools}
255-
ref={devToolsRef}
256-
data-react-devtools-portal-root={true}>
257-
{showTabBar && (
258-
<div className={styles.TabBar}>
259-
<ReactLogo />
260-
<span className={styles.DevToolsVersion}>
261-
{process.env.DEVTOOLS_VERSION}
262-
</span>
263-
<div className={styles.Spacer} />
264-
<TabBar
265-
currentTab={tab}
266-
id="DevTools"
267-
selectTab={setTab}
268-
tabs={tabs}
269-
type="navigation"
245+
<HookNamesModuleLoaderContext.Provider
246+
value={hookNamesModuleLoaderFunction || null}>
247+
<FetchFileWithCachingContext.Provider
248+
value={fetchFileWithCaching || null}>
249+
<TreeContextController>
250+
<ProfilerContextController>
251+
<SchedulingProfilerContextController>
252+
<ThemeProvider>
253+
<div
254+
className={styles.DevTools}
255+
ref={devToolsRef}
256+
data-react-devtools-portal-root={true}>
257+
{showTabBar && (
258+
<div className={styles.TabBar}>
259+
<ReactLogo />
260+
<span className={styles.DevToolsVersion}>
261+
{process.env.DEVTOOLS_VERSION}
262+
</span>
263+
<div className={styles.Spacer} />
264+
<TabBar
265+
currentTab={tab}
266+
id="DevTools"
267+
selectTab={setTab}
268+
tabs={tabs}
269+
type="navigation"
270+
/>
271+
</div>
272+
)}
273+
<div
274+
className={styles.TabContent}
275+
hidden={tab !== 'components'}>
276+
<Components
277+
portalContainer={componentsPortalContainer}
278+
/>
279+
</div>
280+
<div
281+
className={styles.TabContent}
282+
hidden={tab !== 'profiler'}>
283+
<Profiler
284+
portalContainer={profilerPortalContainer}
270285
/>
271286
</div>
272-
)}
273-
<div
274-
className={styles.TabContent}
275-
hidden={tab !== 'components'}>
276-
<Components
277-
portalContainer={componentsPortalContainer}
278-
/>
279-
</div>
280-
<div
281-
className={styles.TabContent}
282-
hidden={tab !== 'profiler'}>
283-
<Profiler
284-
portalContainer={profilerPortalContainer}
285-
/>
286287
</div>
287-
</div>
288-
</ThemeProvider>
289-
</SchedulingProfilerContextController>
290-
</ProfilerContextController>
291-
</TreeContextController>
292-
</FetchFileWithCachingContext.Provider>
288+
</ThemeProvider>
289+
</SchedulingProfilerContextController>
290+
</ProfilerContextController>
291+
</TreeContextController>
292+
</FetchFileWithCachingContext.Provider>
293+
</HookNamesModuleLoaderContext.Provider>
293294
</ViewElementSourceContext.Provider>
294295
</SettingsContextController>
295296
<UnsupportedBridgeProtocolDialog />

packages/react-devtools-shell/src/devtools.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ import {
1010
import {initialize as initializeFrontend} from 'react-devtools-inline/frontend';
1111
import {initDevTools} from 'react-devtools-shared/src/devtools';
1212

13+
// This is a pretty gross hack to make the runtime loaded named-hooks-code work.
14+
// $FlowFixMe
15+
__webpack_public_path__ = '/dist/'; // eslint-disable-line no-undef
16+
1317
const iframe = ((document.getElementById('target'): any): HTMLIFrameElement);
1418

1519
const {contentDocument, contentWindow} = iframe;
@@ -50,6 +54,10 @@ mountButton.addEventListener('click', function() {
5054
}
5155
});
5256

57+
function hookNamesModuleLoaderFunction() {
58+
return import('react-devtools-inline/hookNames');
59+
}
60+
5361
inject('dist/app.js', () => {
5462
initDevTools({
5563
connect(cb) {
@@ -58,6 +66,7 @@ inject('dist/app.js', () => {
5866
createElement(DevTools, {
5967
browserTheme: 'light',
6068
enabledInspectedElementContextMenu: true,
69+
hookNamesModuleLoaderFunction,
6170
showTabBar: true,
6271
warnIfLegacyBackendDetected: true,
6372
warnIfUnsupportedVersionDetected: true,

0 commit comments

Comments
 (0)