diff --git a/Makefile b/Makefile
index d99c8fc4f9760f0f477c98396a7d981928afa2dd..888717277893dd95b43623060de73aec1241b69f 100644
--- a/Makefile
+++ b/Makefile
@@ -14,10 +14,21 @@ AFL_CC = afl-gcc
 AFL_CXX = afl-g++
 AR = ar
 
-RELEASE_TARGET := $(BUILD_DIR)/libolm.so.$(VERSION)
+UNAME := $(shell uname)
+ifeq ($(UNAME),Darwin)
+	SO := dylib
+	OLM_LDFLAGS :=
+else
+	SO := so
+	OLM_LDFLAGS := -Wl,-soname,libolm.so.$(MAJOR) \
+                       -Wl,--version-script,version_script.ver
+endif
+
+RELEASE_TARGET := $(BUILD_DIR)/libolm.$(SO).$(VERSION)
 STATIC_RELEASE_TARGET := $(BUILD_DIR)/libolm.a
-DEBUG_TARGET := $(BUILD_DIR)/libolm_debug.so.$(VERSION)
-JS_TARGET := javascript/olm.js
+DEBUG_TARGET := $(BUILD_DIR)/libolm_debug.$(SO).$(VERSION)
+JS_WASM_TARGET := javascript/olm.js
+JS_ASMJS_TARGET := javascript/olm_legacy.js
 
 JS_EXPORTED_FUNCTIONS := javascript/exported_functions.json
 JS_EXTRA_EXPORTED_RUNTIME_METHODS := ALLOC_STACK
@@ -84,8 +95,11 @@ EMCCFLAGS += -s NO_BROWSER=1
 # mind that the plaintext can only be 48K because base64). We also have about
 # 36K of statics. So let's have 256K of memory.
 # (This can't be changed by the app with wasm since it's baked into the wasm).
-EMCCFLAGS += -s TOTAL_STACK=65536 -s TOTAL_MEMORY=262144
+# (emscripten also mandates at least 16MB of memory for asm.js now, so
+# we don't use this for the legacy build.)
+EMCCFLAGS_WASM += -s TOTAL_STACK=65536 -s TOTAL_MEMORY=262144
 
+EMCCFLAGS_ASMJS += -s WASM=0
 
 EMCC.c = $(EMCC) $(CFLAGS) $(CPPFLAGS) -c
 EMCC.cc = $(EMCC) $(CXXFLAGS) $(CPPFLAGS) -c
@@ -121,7 +135,8 @@ $(FUZZER_DEBUG_BINARIES): LDFLAGS += $(DEBUG_OPTIMIZE_FLAGS)
 
 $(JS_OBJECTS): CFLAGS += $(JS_OPTIMIZE_FLAGS)
 $(JS_OBJECTS): CXXFLAGS += $(JS_OPTIMIZE_FLAGS)
-$(JS_TARGET): LDFLAGS += $(JS_OPTIMIZE_FLAGS)
+$(JS_WASM_TARGET): LDFLAGS += $(JS_OPTIMIZE_FLAGS)
+$(JS_ASMJS_TARGET): LDFLAGS += $(JS_OPTIMIZE_FLAGS)
 
 ### Fix to make mkdir work on windows and linux
 ifeq ($(shell echo "check_quotes"),"check_quotes")
@@ -143,20 +158,18 @@ lib: $(RELEASE_TARGET)
 
 $(RELEASE_TARGET): $(RELEASE_OBJECTS)
 	$(CXX) $(LDFLAGS) --shared -fPIC \
-            -Wl,-soname,libolm.so.$(MAJOR) \
-            -Wl,--version-script,version_script.ver \
+            $(OLM_LDFLAGS) \
             $(OUTPUT_OPTION) $(RELEASE_OBJECTS)
-	ln -sf libolm.so.$(VERSION) $(BUILD_DIR)/libolm.so.$(MAJOR)
+	ln -sf libolm.$(SO).$(VERSION) $(BUILD_DIR)/libolm.$(SO).$(MAJOR)
 
 debug: $(DEBUG_TARGET)
 .PHONY: debug
 
 $(DEBUG_TARGET): $(DEBUG_OBJECTS)
 	$(CXX) $(LDFLAGS) --shared -fPIC \
-            -Wl,-soname,libolm_debug.so.$(MAJOR) \
-            -Wl,--version-script,version_script.ver \
+            $(OLM_LDFLAGS) \
             $(OUTPUT_OPTION) $(DEBUG_OBJECTS)
-	ln -sf libolm_debug.so.$(VERSION) $(BUILD_DIR)/libolm_debug.so.$(MAJOR)
+	ln -sf libolm_debug.$(SO).$(VERSION) $(BUILD_DIR)/libolm_debug.$(SO).$(MAJOR)
 
 static: $(STATIC_RELEASE_TARGET)
 .PHONY: static
@@ -164,14 +177,27 @@ static: $(STATIC_RELEASE_TARGET)
 $(STATIC_RELEASE_TARGET): $(RELEASE_OBJECTS)
 	$(AR) rcs $@ $^
 
-js: $(JS_TARGET)
+js: $(JS_WASM_TARGET) $(JS_ASMJS_TARGET)
 .PHONY: js
 
 # Note that the output file we give to emcc determines the name of the
 # wasm file baked into the js, hence messing around outputting to olm.js
 # and then renaming it.
-$(JS_TARGET): $(JS_OBJECTS) $(JS_PRE) $(JS_POST) $(JS_EXPORTED_FUNCTIONS) $(JS_PREFIX) $(JS_SUFFIX)
+$(JS_WASM_TARGET): $(JS_OBJECTS) $(JS_PRE) $(JS_POST) $(JS_EXPORTED_FUNCTIONS) $(JS_PREFIX) $(JS_SUFFIX)
+	EMCC_CLOSURE_ARGS="--externs $(JS_EXTERNS)" $(EMCC_LINK) \
+	       $(EMCCFLAGS_WASM) \
+               $(foreach f,$(JS_PRE),--pre-js $(f)) \
+               $(foreach f,$(JS_POST),--post-js $(f)) \
+               -s "EXPORTED_FUNCTIONS=@$(JS_EXPORTED_FUNCTIONS)" \
+               -s "EXTRA_EXPORTED_RUNTIME_METHODS=$(JS_EXTRA_EXPORTED_RUNTIME_METHODS)" \
+               $(JS_OBJECTS) -o $@
+	       mv $@ javascript/olmtmp.js
+	       cat $(JS_PREFIX) javascript/olmtmp.js $(JS_SUFFIX) > $@
+	       rm javascript/olmtmp.js
+
+$(JS_ASMJS_TARGET): $(JS_OBJECTS) $(JS_PRE) $(JS_POST) $(JS_EXPORTED_FUNCTIONS) $(JS_PREFIX) $(JS_SUFFIX)
 	EMCC_CLOSURE_ARGS="--externs $(JS_EXTERNS)" $(EMCC_LINK) \
+	       $(EMCCFLAGS_ASMJS) \
                $(foreach f,$(JS_PRE),--pre-js $(f)) \
                $(foreach f,$(JS_POST),--post-js $(f)) \
                -s "EXPORTED_FUNCTIONS=@$(JS_EXPORTED_FUNCTIONS)" \
@@ -206,16 +232,16 @@ install-headers: $(PUBLIC_HEADERS)
 
 install-debug: debug install-headers
 	test -d $(DESTDIR)$(PREFIX)/lib || $(call mkdir,$(DESTDIR)$(PREFIX)/lib)
-	install -Dm755 $(DEBUG_TARGET) $(DESTDIR)$(PREFIX)/lib/libolm_debug.so.$(VERSION)
-	ln -s libolm_debug.so.$(VERSION) $(DESTDIR)$(PREFIX)/lib/libolm_debug.so.$(MAJOR)
-	ln -s libolm_debug.so.$(VERSION) $(DESTDIR)$(PREFIX)/lib/libolm_debug.so
+	install -Dm755 $(DEBUG_TARGET) $(DESTDIR)$(PREFIX)/lib/libolm_debug.$(SO).$(VERSION)
+	ln -s libolm_debug.$(SO).$(VERSION) $(DESTDIR)$(PREFIX)/lib/libolm_debug.$(SO).$(MAJOR)
+	ln -s libolm_debug.$(SO).$(VERSION) $(DESTDIR)$(PREFIX)/lib/libolm_debug.$(SO)
 .PHONY: install-debug
 
 install: lib install-headers
 	test -d $(DESTDIR)$(PREFIX)/lib || $(call mkdir,$(DESTDIR)$(PREFIX)/lib)
-	install -Dm755 $(RELEASE_TARGET) $(DESTDIR)$(PREFIX)/lib/libolm.so.$(VERSION)
-	ln -s libolm.so.$(VERSION) $(DESTDIR)$(PREFIX)/lib/libolm.so.$(MAJOR)
-	ln -s libolm.so.$(VERSION) $(DESTDIR)$(PREFIX)/lib/libolm.so
+	install -Dm755 $(RELEASE_TARGET) $(DESTDIR)$(PREFIX)/lib/libolm.$(SO).$(VERSION)
+	ln -s libolm.$(SO).$(VERSION) $(DESTDIR)$(PREFIX)/lib/libolm.$(SO).$(MAJOR)
+	ln -s libolm.$(SO).$(VERSION) $(DESTDIR)$(PREFIX)/lib/libolm.$(SO)
 .PHONY: install
 
 clean:;
diff --git a/README.rst b/README.rst
index 4f33c00af2c197ae3c76db810447624d1db42c3d..5a5413e583a9f311a406781429e08f0d2aaaebcb 100644
--- a/README.rst
+++ b/README.rst
@@ -31,6 +31,9 @@ To build the javascript bindings, install emscripten from http://kripken.github.
 
     make js
 
+Note that if you run emscripten in a docker container, you need to pass through
+the EMCC_CLOSURE_ARGS environment variable.
+
 To build the android project for Android bindings, run:
 
 .. code:: bash
diff --git a/javascript/olm_post.js b/javascript/olm_post.js
index fffffadd186d6883ce80054eba708e2a445297ad..21ea8905fdd367d6fc4ea946701897ed1715c4b4 100644
--- a/javascript/olm_post.js
+++ b/javascript/olm_post.js
@@ -463,13 +463,3 @@ olm_exports["get_library_version"] = restore_stack(function() {
         getValue(buf+2, 'i8'),
     ];
 });
-
-Module['onRuntimeInitialized'] = function() {
-    OLM_ERROR = Module['_olm_error']();
-    olm_exports["PRIVATE_KEY_LENGTH"] = Module['_olm_pk_private_key_length']();
-    if (onInitSuccess) onInitSuccess();
-};
-
-Module['onAbort'] = function(err) {
-    if (onInitFail) onInitFail(err);
-};
diff --git a/javascript/olm_pre.js b/javascript/olm_pre.js
index 4feff9764c381f27824695c91977dd980abae4df..314d7da7e5cda3ebbf328fd92e1453328de2c2cd 100644
--- a/javascript/olm_pre.js
+++ b/javascript/olm_pre.js
@@ -37,3 +37,13 @@ if (typeof(OLM_OPTIONS) !== 'undefined') {
  * use UTF8ToString.
  */
 var NULL_BYTE_PADDING_LENGTH = 1;
+
+Module['onRuntimeInitialized'] = function() {
+    OLM_ERROR = Module['_olm_error']();
+    olm_exports["PRIVATE_KEY_LENGTH"] = Module['_olm_pk_private_key_length']();
+    if (onInitSuccess) onInitSuccess();
+};
+
+Module['onAbort'] = function(err) {
+    if (onInitFail) onInitFail(err);
+};
diff --git a/javascript/olm_suffix.js b/javascript/olm_suffix.js
index 7f19953acb934da00e8ce2b5d6905a77f0f91c20..3e2f6643bf7d20560cb02ddfe474cf3006619429 100644
--- a/javascript/olm_suffix.js
+++ b/javascript/olm_suffix.js
@@ -24,7 +24,9 @@ if (typeof(window) !== 'undefined') {
     window["Olm"] = olm_exports;
 }
 
-// Emscripten sets the module exports to be its module
-// with wrapped c functions. Clobber it with our higher
-// level wrapper class.
-module.exports = olm_exports;
+if (typeof module === 'object') {
+    // Emscripten sets the module exports to be its module
+    // with wrapped c functions. Clobber it with our higher
+    // level wrapper class.
+    module.exports = olm_exports;
+}