Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core: add support for iframe loading #2318

Merged
merged 6 commits into from
Jun 5, 2019
Merged

Conversation

wchargin
Copy link
Contributor

@wchargin wchargin commented Jun 5, 2019

Summary:
We create a same-origin iframe and add to it a <script> element that
dynamically imports the plugin entry point and invokes its renderer.

For now, the plugin frame has no way to communicate with the host. In
the future, we’d like to be able to (e.g.) send “reload” signals from
host to plugin, and enable the plugin to query the host for global state
like the run selection.

Test Plan:
Cannibalize an existing plugin to provide an ES module entry point:

diff --git a/tensorboard/plugins/scalar/scalars_plugin.py b/tensorboard/plugins/scalar/scalars_plugin.py
index 1b864a74..6ba2b98b 100644
--- a/tensorboard/plugins/scalar/scalars_plugin.py
+++ b/tensorboard/plugins/scalar/scalars_plugin.py
@@ -24,6 +24,7 @@ from __future__ import print_function

 import collections
 import csv
+import textwrap

 import six
 from six import StringIO
@@ -62,6 +63,7 @@ class ScalarsPlugin(base_plugin.TBPlugin):
     return {
         '/scalars': self.scalars_route,
         '/tags': self.tags_route,
+        '/scalars.js': self._serve_module,
     }

   def is_active(self):
@@ -85,10 +87,28 @@ class ScalarsPlugin(base_plugin.TBPlugin):

   def frontend_metadata(self):
     return super(ScalarsPlugin, self).frontend_metadata()._replace(
-        element_name='tf-scalar-dashboard',
+        es_module_path='/scalars.js',  # DO NOT SUBMIT, obviously
         use_data_selector=True,
     )

+  @wrappers.Request.application
+  def _serve_module(self, request):
+    module = textwrap.dedent("""
+        console.log("scalars.js: loaded module under origin:", window.origin);
+        export function render() {
+          console.log("scalars.js: rendering");
+          document.body.innerHTML = `
+            <h1>meet the new scalars dashboard</h1>
+            <ul>
+              <li>loss: &#x1F4C9;</li>
+              <li>accuracy: &#x1F4C8;</li>
+            </ul>
+            <p>nice job, keep it up</p>
+          `;
+        }
+    """).strip()
+    return http_util.Respond(request, module, 'application/javascript')
+
   def index_impl(self):
     """Return {runName: {tagName: {displayName: ..., description: ...}}}."""
     if self._db_connection_provider:

Then verify that the plugin renders properly:

Screenshot of hacked up scalars plugin

Also check that the reload button does not affect it (nor raise a
console error), and that switching among dashboards does not restamp the
iframe.

wchargin-branch: iframe-loading

Summary:
The two loading mechanisms are now specified in the same data object, so
switching from one to the other requires only a single change.

The HTTP API and the frontend are unchanged.

Test Plan:
Modify the scalar plugin’s `frontend_metadata` to use an ES module path:

```diff
diff --git a/tensorboard/plugins/scalar/scalars_plugin.py b/tensorboard/plugins/scalar/scalars_plugin.py
index 1b864a74..2e06c86a 100644
--- a/tensorboard/plugins/scalar/scalars_plugin.py
+++ b/tensorboard/plugins/scalar/scalars_plugin.py
@@ -85,7 +85,8 @@ class ScalarsPlugin(base_plugin.TBPlugin):

   def frontend_metadata(self):
     return super(ScalarsPlugin, self).frontend_metadata()._replace(
-        element_name='tf-scalar-dashboard',
+        #element_name='tf-scalar-dashboard',
+        es_module_path='/magic.js',
         use_data_selector=True,
     )
```

Then, launch TensorBoard and note that the `plugins_listing` response
contains the right values for both the scalar and image plugins.

wchargin-branch: es-module-metadata
wchargin-source: 0a7e48329acba4b58ab9223e6b9ad7dbea98aff8
wchargin-branch: es-module-metadata
Summary:
We create a same-origin iframe and add to it a `<script>` element that
dynamically imports the plugin entry point and invokes its `render`er.

For now, the plugin frame has no way to communicate with the host. In
the future, we’d like to be able to (e.g.) send “reload” signals from
host to plugin, and enable the plugin to query the host for global state
like the run selection.

Test Plan:
![Screenshot of hacked up scalars plugin](https://user-images.githubusercontent.com/4317806/58985670-c1531a00-8790-11e9-9b10-3fbe293c3c2d.png)

wchargin-source: c0e843435b5ea0ac3bf8740fc3f6eaa2a28f12dc
wchargin-branch: iframe-loading
@wchargin
Copy link
Contributor Author

wchargin commented Jun 5, 2019

@stephanwlee: Does this approach seem reasonable to you?

wchargin-source: 68b0d5da9260743d18c6ac80ef9144b1fb927fd8
wchargin-branch: iframe-loading
@wchargin wchargin changed the base branch from wchargin-es-module-metadata to master June 5, 2019 20:31
@stephanwlee
Copy link
Contributor

This is what I had in mind.

@wchargin
Copy link
Contributor Author

wchargin commented Jun 5, 2019

Lovely. I’ll fix it up, then.

wchargin-source: e4b77d9ea58d999f62d8f36a36e8987c69a5f6ed
wchargin-branch: iframe-loading
@wchargin wchargin changed the title DO NOT SUBMIT: iframe loading proof of concept core: add support for iframe loading Jun 5, 2019
@wchargin wchargin marked this pull request as ready for review June 5, 2019 21:38
wchargin-source: e4b77d9ea58d999f62d8f36a36e8987c69a5f6ed
wchargin-branch: iframe-loading
@wchargin wchargin requested a review from stephanwlee June 5, 2019 21:41
@wchargin wchargin merged commit b549bfd into master Jun 5, 2019
@wchargin wchargin deleted the wchargin-iframe-loading branch June 5, 2019 22:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants