Skip to content

Using Figwheel with Web Workers

Milton Reder edited this page Mar 1, 2018 · 5 revisions

NB: This workaround probably won't be needed soon, see https://github.com/bhauman/lein-figwheel/pull/659

The Web Workers API provides a way to spawn additional javascript processes in supported browsers. Because Web Workers don't have access to the DOM, much of the development tooling we are used to won't work, but Figwheel can do it with a little help:

Worker ClojureScript Compilation

First, we add a build to produce the Javascript for the worker. Use a distinct source path from the one in your main application.

;; Main app dev build
{:id "dev"
 :source-paths ["src"]
 :figwheel {:on-jsload "figwheel-worker-example.core/on-js-reload"}
            :compiler {:main figwheel-worker-example.core
                       :asset-path "js/compiled/out"
                       :output-to "resources/public/js/compiled/app.js"
                       :output-dir "resources/public/js/compiled/out"
                       :source-map-timestamp true
                       :preloads [devtools.preload]
                       :closure-defines {goog.DEBUG true}}}
;; Add one for the worker...
{:id "dev-worker"
 :source-paths ["src_worker"]
 :figwheel true
 :compiler {:output-to "resources/public/js/compiled/worker.js"
            :output-dir "resources/public/js/compiled/out_worker"
            :source-map-timestamp true
            :optimizations :none}}

Bootstrap

We didn't provide a :main compiler option in the preceding config, because the ClojureScript compiler expects a document to be present so it can inject Closure directives. In development we'll need to bootstrap Closure ourselves with a script like the following bootstrap_worker.js:

CLOSURE_BASE_PATH = "compiled/out_worker/goog/";
/**
 * Imports a script using the Web Worker importScript API.
 *
 * @param {string} src The script source.
 * @return {boolean} True if the script was imported, false otherwise.
 */
this.CLOSURE_IMPORT_SCRIPT = (function(global) {
    return function(src) {
        global['importScripts'](src);
        return true;
    };
})(this);

if(typeof goog == "undefined") importScripts(CLOSURE_BASE_PATH + "base.js");

importScripts("compiled/worker.js");
goog.require('figwheel_worker_example.worker');

Worker Launch

In development, we'll point to this file to load our worker:

(defonce worker (js/Worker. "js/bootstrap_worker.js"))

Get to Work!

With all that set up, launch Figwheel on both builds:

$ lein figwheel dev dev-worker

A full example application is available here.