Repository: oppia/oppia

Issue:
"Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience."
When I load the admin page in Chrome, I get the following in the console (see the warning sign next to `request.open`):

![admin-page](https://cloud.githubusercontent.com/assets/10575562/23887182/646a7b78-083d-11e7-95be-b6fee6d7f4eb.png)

Hovering over that shows a tooltip with the following message:

`Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.`

Can we avoid this? /cc @vojtechjelinek 


Discussion:
Unfortunately, I didn't find any solution how to prevent this, but in our case, the usage of the synchronous request is justified (we always need the constants). 
Yeah, I had trouble finding a solution too. It probably is not a big issue right this moment, but my concern is that this functionality will be removed and will not be available in the future. We should address that before it happens, otherwise everything will break.
Hi @vojtechjelinek, how is this issue progressing? thanks!
Hi, sorry I forgot I was assigned. 

I think one solution might be to use _.js_ file instead of _.json_, content of this _.js_ file would be `var constants = {"constant1": "xyz", ...}` and insted of using XMLHttpRequest we would use `<script>` for loading that file. Python script would change accordingly. /cc @seanlip 

It might be possible ... but how would Python interpret the file?
We could just slice that file from the first `{` and parse that as JSON.
OK. SGTM, but we need to ensure there are good tests to verify that the format of the file is as expected and that all invariants it needs to satisfy.are explained somewhere.

Resolving patch:
diff --git a/constants.py b/constants.py
--- a/constants.py
+++ b/constants.py
@@ -14,14 +14,23 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+#pylint: disable=invalid-name
+
 """Loads constants for backend use."""
 
 import json
 import os
 
+def parse_json(js_file):
+    text = js_file.read()
+    first_bracket_index = text.find('= {')
+    last_bracket_index = text.rfind('}')
+    json_text = text[first_bracket_index + 2:last_bracket_index + 1]
+    return json.loads(json_text)
+
 class Constants(dict):
     """Transforms dict to object, attributes can be accesed by dot notation"""
     __getattr__ = dict.__getitem__
 
-with open(os.path.join('assets', 'constants.json'), 'r') as f:
-    constants = Constants(json.load(f)) #pylint: disable=invalid-name
+with open(os.path.join('assets', 'constants.js'), 'r') as f:
+    constants = Constants(parse_json(f))


Test patch:
diff --git a/constants_test.py b/constants_test.py
--- a/constants_test.py
+++ b/constants_test.py
@@ -15,8 +15,8 @@
 """Tests for Constants object and cosntants.json file."""
 
 import os
-import json
 
+import constants #pylint: disable=relative-import
 from core.tests import test_utils #pylint: disable=relative-import
 
 class ConstantsTests(test_utils.GenericTestBase):
@@ -24,9 +24,11 @@ class ConstantsTests(test_utils.GenericTestBase):
     def test_constants_file_is_existing(self):
         """Test if the constants file is existing."""
         self.assertTrue(os.path.isfile(os.path.join(
-            'assets', 'constants.json')))
+            'assets', 'constants.js')))
 
-    def test_constants_file_is_valid_json(self):
+    def test_constants_file_contains_valid_json(self):
         """Test if the constants file is valid json file."""
-        with open(os.path.join('assets', 'constants.json'), 'r') as f:
-            self.assertTrue(isinstance(json.load(f), dict))
+        with open(os.path.join('assets', 'constants.js'), 'r') as f:
+            json = constants.parse_json(f)
+            self.assertTrue(isinstance(json, dict))
+            self.assertEqual(json['TESTING_CONSTANT'], 'test')
diff --git a/core/tests/karma-constants.js b/core/tests/karma-constants.js
deleted file mode 100644
--- a/core/tests/karma-constants.js
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2017 The Oppia Authors. All Rights Reserved.
-//
-// 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.
-
-/**
- * @fileoverview Loads constants for the Karma test environment.
- */
-
-/* This should be kept in parity with how CONSTANTS is set in base.html */
-var constants = (function() {
-  var request = new XMLHttpRequest();
-  /* The overrideMimeType method was not implemented in IE prior to IE11. */
-  if (request.overrideMimeType) {
-    request.overrideMimeType('application/json');
-  }
-  request.open(
-   'GET', GLOBALS.ASSET_DIR_PREFIX + '/assets/constants.json', false);
-  request.send(null);
-  return JSON.parse(request.responseText);
-})();
diff --git a/core/tests/karma.conf.js b/core/tests/karma.conf.js
--- a/core/tests/karma.conf.js
+++ b/core/tests/karma.conf.js
@@ -12,11 +12,7 @@ module.exports = function(config) {
     files: [
       'core/tests/karma-globals.js',
       // Constants must be loaded before everything else.
-      {
-        pattern: 'assets/constants.json',
-        included: false
-      },
-      'core/tests/karma-constants.js',
+      'assets/constants.js',
       // Since jquery,jquery-ui,angular,angular-mocks and math-expressions
       // are not bundled, they will be treated separately.
       'third_party/static/jquery-3.0.0/jquery.min.js',
diff --git a/core/tests/protractor/cacheSlugs.js b/core/tests/protractor/cacheSlugs.js
--- a/core/tests/protractor/cacheSlugs.js
+++ b/core/tests/protractor/cacheSlugs.js
@@ -56,11 +56,7 @@ describe('Cache Slugs', function() {
   it('should check that errors get logged for missing resources', function() {
     browser.get(ERROR_PAGE_URL_SUFFIX);
     var expectedErrors = [
-      'http://localhost:9001/build/fail/logo/288x128_logo_white.png',
-      // Warning fired by synchronous AJAX request in
-      // core/templates/dev/head/pages/header_js_libs.html.
-      // This warning is expected and it's needed for constants loading.
-      'Synchronous XMLHttpRequest on the main thread'
+      'http://localhost:9001/build/fail/logo/288x128_logo_white.png'
     ];
     checkConsoleErrorsExist(expectedErrors);
   });