diff --git a/package.json b/package.json
index da3846f9..22753224 100644
--- a/package.json
+++ b/package.json
@@ -69,6 +69,7 @@
     "istanbul": "^0.4.5",
     "mocha": "^5.0.0",
     "sinon": "^4.3.0",
+    "text-encoder-lite": "^1.0.1",
     "whatwg-fetch": "^2.0.3"
   },
   "dependencies": {
diff --git a/src/openpgp.js b/src/openpgp.js
index 39b48dc7..e6bddc00 100644
--- a/src/openpgp.js
+++ b/src/openpgp.js
@@ -44,15 +44,11 @@ import { CleartextMessage } from './cleartext';
 import { generate, reformat } from './key';
 import config from './config/config';
 import enums from './enums';
+import './polyfills';
 import stream from './stream';
 import util from './util';
 import AsyncProxy from './worker/async_proxy';
 
-// Old browser polyfills
-if (typeof window !== 'undefined') {
-  require('./polyfills');
-}
-
 //////////////////////////
 //                      //
 //   Web Worker setup   //
diff --git a/src/polyfills.js b/src/polyfills.js
index 43ef100e..502482ed 100644
--- a/src/polyfills.js
+++ b/src/polyfills.js
@@ -1,33 +1,52 @@
+/**
+ * @fileoverview Old browser polyfills
+ * All are listed as dev dependencies because Node does not need them
+ * and for browser babel will take care of it
+ * @requires util
+ * @module polyfills
+ */
+
+import util from './util';
+
 /* eslint-disable import/no-extraneous-dependencies */
-// Old browser polyfills
-// All are listed as dev dependencies because Node does not need them
-// and for browser babel will take care of it
 
-if (typeof window.fetch === 'undefined') {
-  require('whatwg-fetch');
-}
-if (typeof Array.prototype.fill === 'undefined') {
-  require('core-js/fn/array/fill');
-}
-if (typeof Array.prototype.find === 'undefined') {
-  require('core-js/fn/array/find');
-}
-if (typeof Array.from === 'undefined') {
-  require('core-js/fn/array/from');
+if (typeof window !== 'undefined') {
+  if (typeof window.fetch === 'undefined') {
+    require('whatwg-fetch');
+  }
+  if (typeof Array.prototype.fill === 'undefined') {
+    require('core-js/fn/array/fill');
+  }
+  if (typeof Array.prototype.find === 'undefined') {
+    require('core-js/fn/array/find');
+  }
+  if (typeof Array.from === 'undefined') {
+    require('core-js/fn/array/from');
+  }
+
+  // No if-statement on Promise because of IE11. Otherwise Promise is undefined in the service worker.
+  require('core-js/fn/promise');
+
+  if (typeof Uint8Array.from === 'undefined') {
+    require('core-js/fn/typed/uint8-array');
+  }
+  if (typeof String.prototype.repeat === 'undefined') {
+    require('core-js/fn/string/repeat');
+  }
+  if (typeof Symbol === 'undefined') {
+    require('core-js/fn/symbol');
+  }
+  if (typeof Object.assign === 'undefined') {
+    require('core-js/fn/object/assign');
+  }
 }
 
-// No if-statement on Promise because of IE11. Otherwise Promise is undefined in the service worker.
-require('core-js/fn/promise');
-
-if (typeof Uint8Array.from === 'undefined') {
-  require('core-js/fn/typed/uint8-array');
+if (typeof TransformStream === 'undefined') {
+  require('@mattiasbuelens/web-streams-polyfill');
 }
-if (typeof String.prototype.repeat === 'undefined') {
-  require('core-js/fn/string/repeat');
+if (typeof TextDecoder === 'undefined') {
+  global.TextDecoder = util.getNodeTextDecoder();
 }
-if (typeof Symbol === 'undefined') {
-  require('core-js/fn/symbol');
-}
-if (typeof Object.assign === 'undefined') {
-  require('core-js/fn/object/assign');
+if (typeof TextDecoder === 'undefined') {
+  global.TextDecoder = require('text-encoder-lite');
 }
diff --git a/src/stream.js b/src/stream.js
index c6177768..1ecaed4a 100644
--- a/src/stream.js
+++ b/src/stream.js
@@ -1,9 +1,5 @@
 import util from './util';
 
-if (typeof TransformStream === 'undefined') {
-  require('@mattiasbuelens/web-streams-polyfill');
-}
-
 const nodeStream = util.getNodeStream();
 
 function toStream(input) {
diff --git a/src/util.js b/src/util.js
index 08171753..f4355e7c 100644
--- a/src/util.js
+++ b/src/util.js
@@ -664,12 +664,19 @@ export default {
       return;
     }
 
-    // This "hack" allows us to access the native node buffer module.
-    // otherwise, it gets replaced with the browserified version
     // eslint-disable-next-line no-useless-concat, import/no-dynamic-require
     return require('stream'+'');
   },
 
+  getNodeTextDecoder: function() {
+    if (!util.detectNode()) {
+      return;
+    }
+
+    // eslint-disable-next-line no-useless-concat, import/no-dynamic-require
+    return require('util'+'').TextDecoder;
+  },
+
   isEmailAddress: function(data) {
     if (!util.isString(data)) {
       return false;