Merge "ui: Move static initializers to their own file"
diff --git a/ui/src/common/immer_init.ts b/ui/src/common/immer_init.ts
deleted file mode 100644
index 9b8817c..0000000
--- a/ui/src/common/immer_init.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (C) 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use size file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-import {enableMapSet, enablePatches, setAutoFreeze} from 'immer';
-
-export function initializeImmerJs() {
- enablePatches();
-
- // TODO(primiano): re-enable this, requires fixing some bugs that this bubbles
- // up. This is a new feature of immer which freezes object after a produce().
- // Unfortunately we piled up a bunch of bugs where we shallow-copy objects
- // from the global state (which is frozen) and later try to update the copies.
- // By doing so, we accidentally the local copy of global state, which is
- // supposed to be immutable.
- setAutoFreeze(false);
-
- enableMapSet();
-}
diff --git a/ui/src/common/query_result.ts b/ui/src/common/query_result.ts
index ea84c0c..ad5e1ee 100644
--- a/ui/src/common/query_result.ts
+++ b/ui/src/common/query_result.ts
@@ -47,15 +47,10 @@
// the next batch (if any) within the QueryResultImpl.
// This object is part of the API exposed to tracks / controllers.
-import protobuf from 'protobufjs/minimal';
+// Ensure protobuf is initialized.
+import '../core/static_initializers';
-// Disable Long.js support in protobuf. This seems to be enabled only in tests
-// but not in production code. In any case, for now we want casting to number
-// accepting the 2**53 limitation. This is consistent with passing
-// --force-number in the protobuf.js codegen invocation in //ui/BUILD.gn .
-// See also https://github.com/protobufjs/protobuf.js/issues/1253 .
-protobuf.util.Long = undefined as any;
-protobuf.configure();
+import protobuf from 'protobufjs/minimal';
import {defer, Deferred} from '../base/deferred';
import {assertExists, assertFalse, assertTrue} from '../base/logging';
diff --git a/ui/src/core/static_initializers.ts b/ui/src/core/static_initializers.ts
new file mode 100644
index 0000000..4959d68
--- /dev/null
+++ b/ui/src/core/static_initializers.ts
@@ -0,0 +1,65 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Occasionally libraries require configuration code to be called
+// before that library is used. This can become troublesome when the
+// library is used in many places through out the code base. To ensure
+// a consistent initialization this file exists as a place such code
+// can live. It's the first import in the root file of the bundle.
+
+// We use 'static initializers' (e.g. first import causes
+// initialization) rather than allowing the importer control over when
+// it happens. This sounds worse on paper but it works a lot better in
+// tests where (in JS) there is no global main() you can edit to do the
+// initialization. Instead any test where this is a problem can easily
+// stick an import at the top of the file.
+
+import {enableMapSet, enablePatches, setAutoFreeze} from 'immer';
+import protobuf from 'protobufjs/minimal';
+
+function initializeImmer() {
+ enablePatches();
+ enableMapSet();
+
+ // TODO(primiano): re-enable this, requires fixing some bugs that this bubbles
+ // up. This is a new feature of immer which freezes object after a produce().
+ // Unfortunately we piled up a bunch of bugs where we shallow-copy objects
+ // from the global state (which is frozen) and later try to update the copies.
+ // By doing so, we accidentally the local copy of global state, which is
+ // supposed to be immutable.
+ setAutoFreeze(false);
+}
+
+function initializeProtobuf() {
+ // Disable Long.js support in protobuf. This seems to be enabled only in tests
+ // but not in production code. In any case, for now we want casting to number
+ // accepting the 2**53 limitation. This is consistent with passing
+ // --force-number in the protobuf.js codegen invocation in //ui/BUILD.gn .
+ // See also https://github.com/protobufjs/protobuf.js/issues/1253 .
+ protobuf.util.Long = undefined as any;
+ protobuf.configure();
+}
+
+let isInitialized = false;
+function initialize() {
+ if (isInitialized) {
+ throw new Error('initialize() should be called exactly once');
+ }
+ initializeImmer();
+ initializeProtobuf();
+ isInitialized = true;
+}
+
+// JS module semantics ensure this is happens only once.
+initialize();
diff --git a/ui/src/frontend/index.ts b/ui/src/frontend/index.ts
index b266f15..70bdedb 100644
--- a/ui/src/frontend/index.ts
+++ b/ui/src/frontend/index.ts
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// Need to turn off Long
-import '../common/query_result';
+// Keep this import first.
+import '../core/static_initializers';
import {Patch, produce} from 'immer';
import m from 'mithril';
@@ -23,7 +23,6 @@
import {Actions, DeferredAction, StateActions} from '../common/actions';
import {createEmptyState} from '../common/empty_state';
import {RECORDING_V2_FLAG} from '../common/feature_flags';
-import {initializeImmerJs} from '../common/immer_init';
import {pluginManager, pluginRegistry} from '../common/plugins';
import {State} from '../common/state';
import {initWasm} from '../common/wasm_engine_proxy';
@@ -214,7 +213,6 @@
const extensionLocalChannel = new MessageChannel();
initWasm(globals.root);
- initializeImmerJs();
initController(extensionLocalChannel.port1);
const dispatch = (action: DeferredAction) => {