FIX: CSP unsafe-eval errors when using graphviz on client side.

FIX: CSP unsafe-eval errors when using graphviz on client side.

diff --git a/assets/javascripts/initializers/discourse-graphviz.js.es6 b/assets/javascripts/initializers/discourse-graphviz.js.es6
index 4d03a09..ecaeba7 100644
--- a/assets/javascripts/initializers/discourse-graphviz.js.es6
+++ b/assets/javascripts/initializers/discourse-graphviz.js.es6
@@ -2,6 +2,7 @@ import loadScript from "discourse/lib/load-script";
 import { withPluginApi } from "discourse/lib/plugin-api";
 import { escape } from "pretty-text/sanitizer";
 const { run } = Ember;
+let worker = undefined;
 
 export default {
   name: "discourse-graphviz",
@@ -25,42 +26,43 @@ export default {
     const $spinner = $("<div class='spinner tiny'></div>");
     $container.html($spinner);
 
-    loadScript(
-      "/plugins/discourse-graphviz/javascripts/@hpcc-js/wasm@0.3.14/dist/index.min.js"
-    ).then(() => {
+    if (worker === undefined) {
+      worker = new Worker("/plugins/discourse-graphviz/javascripts/worker.js");
+    }
+
+    worker.addEventListener("message", event => {
+      const data = event.data;
       $container.removeClass("is-loading");
 
-      let hpccWasm = self["@hpcc-js/wasm"];
-      hpccWasm.graphviz
-        .layout(graphDefinition, "svg", engine)
-        .then(svgChart => {
-          $container.html(svgChart);
-        })
-        .catch(e => {
-          // graphviz errors are very helpful so we just show them as is
-          const $error = $(
-            "<div class='graph-error'>" + escape(e.message) + "</div>"
-          );
-          $container.html($error);
-        });
+      if (data.svgChart) {
+        $container.html(data.svgChart);
+      } else {
+        // graphviz errors are very helpful so we just show them as is
+        const $error = $(
+          "<div class='graph-error'>" + escape(data.errorMessage) + "</div>"
+        );
+        $container.html($error);
+      }
     });
+
+    worker.postMessage({ graphDefinition, engine });
   },
 
-  initialize() {
-    withPluginApi("0.8.22", api => {
-      api.decorateCooked(
-        $elem => {
-          if (!Discourse.SiteSettings.discourse_graphviz_enabled) {
-            return;
-          }
+  initialize(container) {
+    const siteSettings = container.lookup("site-settings:main");
 
-          const $graphviz = $elem.find(".graphviz");
-          if ($graphviz.length) {
-            run.debounce(this, this.renderGraphs, $graphviz, 200);
-          }
-        },
-        { id: "graphviz" }
-      );
-    });
+    if (siteSettings.discourse_graphviz_enabled) {
+      withPluginApi("0.8.22", api => {
+        api.decorateCooked(
+          $elem => {
+            const $graphviz = $elem.find(".graphviz");
+            if ($graphviz.length) {
+              run.debounce(this, this.renderGraphs, $graphviz, 200);
+            }
+          },
+          { id: "graphviz" }
+        );
+      });
+    }
   }
 };
diff --git a/public/javascripts/worker.js b/public/javascripts/worker.js
new file mode 100644
index 0000000..1280a1c
--- /dev/null
+++ b/public/javascripts/worker.js
@@ -0,0 +1,26 @@
+const scriptURL =
+  "/plugins/discourse-graphviz/javascripts/@hpcc-js/wasm@0.3.14/dist/index.min.js";
+
+// There is no document in a worker but @hpcc-js/wasm expects a document object
+// so we work around the problem by declaring the document here.
+const document = {
+  currentScript: {
+    src: scriptURL
+  }
+};
+
+importScripts(scriptURL);
+
+self.addEventListener("message", event => {
+  const data = event.data;
+  let hpccWasm = self["@hpcc-js/wasm"];
+
+  hpccWasm.graphviz
+    .layout(data.graphDefinition, "svg", data.engine)
+    .then(svgChart => {
+      self.postMessage({ svgChart });
+    })
+    .catch(e => {
+      self.postMessage({ errorMessage: e.message });
+    });
+});

GitHub sha: b52d4d68