bootstrap.js (4731B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ 4 5 import React from "devtools/client/shared/vendor/react"; 6 import { 7 bindActionCreators, 8 combineReducers, 9 } from "devtools/client/shared/vendor/redux"; 10 import ReactDOM from "devtools/client/shared/vendor/react-dom"; 11 const { 12 Provider, 13 } = require("resource://devtools/client/shared/vendor/react-redux.js"); 14 15 import ToolboxProvider from "devtools/client/framework/store-provider"; 16 import flags from "devtools/shared/flags"; 17 const { 18 registerStoreObserver, 19 } = require("resource://devtools/client/shared/redux/subscriber.js"); 20 21 const { AppConstants } = ChromeUtils.importESModule( 22 "resource://gre/modules/AppConstants.sys.mjs" 23 ); 24 25 import { SearchDispatcher } from "../workers/search/index"; 26 import { PrettyPrintDispatcher } from "../workers/pretty-print/index"; 27 28 import configureStore from "../actions/utils/create-store"; 29 import reducers from "../reducers/index"; 30 import * as selectors from "../selectors/index"; 31 import App from "../components/App"; 32 import { asyncStore, prefs } from "./prefs"; 33 const { 34 sanitizeBreakpoints, 35 } = require("resource://devtools/client/shared/thread-utils.js"); 36 const { 37 visibilityHandlerStore, 38 } = require("resource://devtools/client/shared/redux/visibilityHandlerStore.js"); 39 40 let gWorkers; 41 42 export function bootstrapStore(client, workers, panel, initialState) { 43 const debugJsModules = AppConstants.DEBUG_JS_MODULES == "1"; 44 const createStore = configureStore({ 45 log: prefs.logging || flags.testing, 46 timing: debugJsModules, 47 thunkArgs: { client, ...workers, panel }, 48 }); 49 50 let store = createStore(combineReducers(reducers), initialState); 51 52 // Also wrap the store in order to pause store update notifications while the panel is hidden. 53 store = visibilityHandlerStore(store); 54 55 registerStoreObserver(store, updatePrefs); 56 57 const actions = bindActionCreators( 58 // eslint-disable-next-line mozilla/reject-relative-requires 59 require("../actions/index").default, 60 store.dispatch 61 ); 62 63 return { store, actions, selectors }; 64 } 65 66 export function bootstrapWorkers(panelWorkers) { 67 // The panel worker will typically be the source map and parser workers. 68 // Both will be managed by the toolbox. 69 gWorkers = { 70 prettyPrintWorker: new PrettyPrintDispatcher(), 71 searchWorker: new SearchDispatcher(), 72 }; 73 return { ...panelWorkers, ...gWorkers }; 74 } 75 76 export function teardownWorkers() { 77 gWorkers.prettyPrintWorker.stop(); 78 gWorkers.searchWorker.stop(); 79 } 80 81 /** 82 * Create and mount the root App component. 83 * 84 * @param {ReduxStore} store 85 * @param {ReduxStore} toolboxStore 86 * @param {object} appComponentAttributes 87 * @param {Array} appComponentAttributes.fluentBundles 88 * @param {Document} appComponentAttributes.toolboxDoc 89 */ 90 export function bootstrapApp(store, toolboxStore, appComponentAttributes = {}) { 91 const mount = getMountElement(); 92 if (!mount) { 93 return; 94 } 95 96 ReactDOM.render( 97 React.createElement( 98 Provider, 99 { store }, 100 React.createElement( 101 ToolboxProvider, 102 { store: toolboxStore }, 103 React.createElement(App, appComponentAttributes) 104 ) 105 ), 106 mount 107 ); 108 } 109 110 function getMountElement() { 111 return document.querySelector("#mount"); 112 } 113 114 // This is the opposite of bootstrapApp 115 export function unmountRoot() { 116 ReactDOM.unmountComponentAtNode(getMountElement()); 117 } 118 119 function updatePrefs(state, oldState) { 120 const hasChanged = selector => 121 selector(oldState) && selector(oldState) !== selector(state); 122 123 if (hasChanged(selectors.getPendingBreakpoints)) { 124 asyncStore.pendingBreakpoints = sanitizeBreakpoints( 125 selectors.getPendingBreakpoints(state) 126 ); 127 } 128 129 if ( 130 oldState.eventListenerBreakpoints && 131 oldState.eventListenerBreakpoints !== state.eventListenerBreakpoints 132 ) { 133 asyncStore.eventListenerBreakpoints = state.eventListenerBreakpoints; 134 } 135 136 if (hasChanged(selectors.getOpenedURLs)) { 137 asyncStore.openedURLs = selectors.getOpenedURLs(state); 138 } 139 if (hasChanged(selectors.getPrettyPrintedURLs)) { 140 // Convert the Set into an Array 141 asyncStore.prettyPrintedURLs = Array.from( 142 selectors.getPrettyPrintedURLs(state) 143 ); 144 } 145 146 if (hasChanged(selectors.getXHRBreakpoints)) { 147 asyncStore.xhrBreakpoints = selectors.getXHRBreakpoints(state); 148 } 149 150 if (hasChanged(selectors.getBlackBoxRanges)) { 151 asyncStore.blackboxedRanges = selectors.getBlackBoxRanges(state); 152 } 153 154 if (hasChanged(selectors.getMainThreadProjectDirectoryRoots)) { 155 asyncStore.directoryRoots = 156 selectors.getMainThreadProjectDirectoryRoots(state); 157 } 158 }