diff --git a/.travis.yml b/.travis.yml
index bc3fce38..0099fcd0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,22 +11,11 @@ sudo: required
 language: node_js
 node_js:
     # make sure we work with a range of node versions.
-    # As of the time of writing:
-    #  - 4.x is still in LTS (until April 2018), but some of our deps (notably
-    #    extract-zip) don't work with it
-    #  - 5.x has been EOLed for nearly a year.
-    #  - 6.x is the active 'LTS' version
-    #  - 7.x is no longer supported
-    #  - 8.x is the current 'current' version (until October 2017)
     #
-    # see: https://github.com/nodejs/LTS/
-    #
-    # anything before 6.3 ships with npm 3.9 or earlier, which had problems
-    # with symlinks in node_modules (see
-    # https://github.com/npm/npm/releases/tag/v3.10.0 'FIXES AND REFACTORING').
-    - 6.3
+    # Current status of node versions: https://github.com/nodejs/LTS/
     - 6
-    - 7
+    - 8
+    - 10
 addons:
     chrome: stable
 install:
diff --git a/src/components/views/login/VectorCustomServerDialog.js b/src/components/views/login/VectorCustomServerDialog.js
index 8395f139..c60ff6da 100644
--- a/src/components/views/login/VectorCustomServerDialog.js
+++ b/src/components/views/login/VectorCustomServerDialog.js
@@ -15,8 +15,8 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-var React = require("react");
-var sanitizeHtml = require("sanitize-html");
+const React = require("react");
+const sanitizeHtml = require("sanitize-html");
 import { _t } from 'matrix-react-sdk/lib/languageHandler';
 
 module.exports = React.createClass({
@@ -47,5 +47,5 @@ module.exports = React.createClass({
                 </div>
             </div>
         );
-    }
+    },
 });
diff --git a/src/components/views/login/VectorLoginFooter.js b/src/components/views/login/VectorLoginFooter.js
index 26e01c06..5fa42360 100644
--- a/src/components/views/login/VectorLoginFooter.js
+++ b/src/components/views/login/VectorLoginFooter.js
@@ -16,7 +16,7 @@ limitations under the License.
 
 'use strict';
 
-var React = require('react');
+const React = require('react');
 import { _t } from 'matrix-react-sdk/lib/languageHandler';
 import SettingsStore from 'matrix-react-sdk/lib/settings/SettingsStore';
 
@@ -29,8 +29,8 @@ module.exports = React.createClass({
     render: function() {
         // FIXME: replace this with a proper Status skin
         // ...except then we wouldn't be able to switch to the Status theme at runtime.
-        if (SettingsStore.getValue("theme") === 'status') return <div/>;
-        
+        if (SettingsStore.getValue("theme") === 'status') return <div />;
+
         return (
             <div className="mx_Login_links">
                 <a href="https://medium.com/@RiotChat">blog</a>&nbsp;&nbsp;&middot;&nbsp;&nbsp;
@@ -39,5 +39,5 @@ module.exports = React.createClass({
                 <a href="https://matrix.org">{ _t('powered by Matrix') }</a>
             </div>
         );
-    }
+    },
 });
diff --git a/src/components/views/login/VectorLoginHeader.js b/src/components/views/login/VectorLoginHeader.js
index d0ee7934..babd90d6 100644
--- a/src/components/views/login/VectorLoginHeader.js
+++ b/src/components/views/login/VectorLoginHeader.js
@@ -35,9 +35,9 @@ module.exports = React.createClass({
         return (
             <div className="mx_Login_header">
                 <div className="mx_Login_logo">
-                    <img src={this.props.icon || DEFAULT_LOGO_URI} alt="Riot"/>
+                    <img src={this.props.icon || DEFAULT_LOGO_URI} alt="Riot" />
                 </div>
             </div>
         );
-    }
+    },
 });
diff --git a/src/vector/index.js b/src/vector/index.js
index 1d47491e..b3ad6fc6 100644
--- a/src/vector/index.js
+++ b/src/vector/index.js
@@ -87,12 +87,12 @@ function checkBrowserFeatures(featureList) {
         console.error("Cannot check features - Modernizr global is missing.");
         return false;
     }
-    var featureComplete = true;
-    for (var i = 0; i < featureList.length; i++) {
+    let featureComplete = true;
+    for (let i = 0; i < featureList.length; i++) {
         if (window.Modernizr[featureList[i]] === undefined) {
             console.error(
                 "Looked for feature '%s' but Modernizr has no results for this. " +
-                "Has it been configured correctly?", featureList[i]
+                "Has it been configured correctly?", featureList[i],
             );
             return false;
         }
@@ -113,7 +113,7 @@ function getScreenFromLocation(location) {
     return {
         screen: fragparts.location.substring(1),
         params: fragparts.params,
-    }
+    };
 }
 
 // Here, we do some crude URL analysis to allow
@@ -138,10 +138,10 @@ function onHashChange(ev) {
 // so a web page can update the URL bar appropriately.
 function onNewScreen(screen) {
     console.log("newscreen "+screen);
-    var hash = '#/' + screen;
+    const hash = '#/' + screen;
     lastLocationHashSet = hash;
     window.location.hash = hash;
-};
+}
 
 // We use this to work out what URL the SDK should
 // pass through when registering to allow the user to
@@ -214,9 +214,9 @@ function onTokenLoginCompleted() {
     // if we did a token login, we're now left with the token, hs and is
     // url as query params in the url; a little nasty but let's redirect to
     // clear them.
-    var parsedUrl = url.parse(window.location.href);
+    const parsedUrl = url.parse(window.location.href);
     parsedUrl.search = "";
-    var formatted = url.format(parsedUrl);
+    const formatted = url.format(parsedUrl);
     console.log("Redirecting to " + formatted + " to drop loginToken " +
                 "from queryparams");
     window.location.href = formatted;
@@ -293,7 +293,7 @@ async function loadApp() {
                 // in case it is the first time loading Riot.
                 // `InstallTrigger` is a Object which only exists on Firefox
                 // (it is used for their Plugins) and can be used as a
-                // feature check. 
+                // feature check.
                 // Firefox loads css always before js. This is why we dont use
                 // onload or it's EventListener as thoose will never trigger.
                 if (typeof InstallTrigger !== 'undefined') {
@@ -345,19 +345,19 @@ async function loadApp() {
                 initialScreenAfterLogin={getScreenFromLocation(window.location)}
                 defaultDeviceDisplayName={platform.getDefaultDeviceDisplayName()}
             />,
-            document.getElementById('matrixchat')
+            document.getElementById('matrixchat'),
         );
     } else {
         console.error("Browser is missing required features.");
         // take to a different landing page to AWOOOOOGA at the user
-        var CompatibilityPage = sdk.getComponent("structures.CompatibilityPage");
+        const CompatibilityPage = sdk.getComponent("structures.CompatibilityPage");
         window.matrixChat = ReactDOM.render(
             <CompatibilityPage onAccept={function() {
                 if (window.localStorage) window.localStorage.setItem('mx_accepts_unsupported_browser', true);
                 console.log("User accepts the compatibility risks.");
                 loadApp();
             }} />,
-            document.getElementById('matrixchat')
+            document.getElementById('matrixchat'),
         );
     }
 }
diff --git a/src/vector/platform/ElectronPlatform.js b/src/vector/platform/ElectronPlatform.js
index 5ced2a2a..8b384b20 100644
--- a/src/vector/platform/ElectronPlatform.js
+++ b/src/vector/platform/ElectronPlatform.js
@@ -27,7 +27,7 @@ import rageshake from 'matrix-react-sdk/lib/rageshake/rageshake';
 remote.autoUpdater.on('update-downloaded', onUpdateDownloaded);
 
 // try to flush the rageshake logs to indexeddb before quit.
-ipcRenderer.on('before-quit', function () {
+ipcRenderer.on('before-quit', function() {
     console.log('riot-desktop closing');
     rageshake.flush();
 });
diff --git a/src/vector/platform/VectorBasePlatform.js b/src/vector/platform/VectorBasePlatform.js
index 4bf300a5..746b5aaf 100644
--- a/src/vector/platform/VectorBasePlatform.js
+++ b/src/vector/platform/VectorBasePlatform.js
@@ -114,7 +114,7 @@ export default class VectorBasePlatform extends BasePlatform {
         dis.dispatch({
             action: 'check_updates',
             value: false,
-        })
+        });
     }
 
     getUpdateCheckStatusEnum() {
diff --git a/src/vector/platform/WebPlatform.js b/src/vector/platform/WebPlatform.js
index cfe51346..2955b84a 100644
--- a/src/vector/platform/WebPlatform.js
+++ b/src/vector/platform/WebPlatform.js
@@ -26,7 +26,7 @@ import Promise from 'bluebird';
 import url from 'url';
 import UAParser from 'ua-parser-js';
 
-var POKE_RATE_MS = 10 * 60 * 1000; // 10 min
+const POKE_RATE_MS = 10 * 60 * 1000; // 10 min
 
 export default class WebPlatform extends VectorBasePlatform {
     constructor() {
diff --git a/src/vector/url_utils.js b/src/vector/url_utils.js
index cfa8eae1..cbaefa0c 100644
--- a/src/vector/url_utils.js
+++ b/src/vector/url_utils.js
@@ -23,16 +23,16 @@ import qs from 'querystring';
 export function parseQsFromFragment(location) {
     // if we have a fragment, it will start with '#', which we need to drop.
     // (if we don't, this will return '').
-    var fragment = location.hash.substring(1);
+    const fragment = location.hash.substring(1);
 
     // our fragment may contain a query-param-like section. we need to fish
     // this out *before* URI-decoding because the params may contain ? and &
     // characters which are only URI-encoded once.
-    var hashparts = fragment.split('?');
+    const hashparts = fragment.split('?');
 
-    var result = {
+    const result = {
         location: decodeURIComponent(hashparts[0]),
-        params: {}
+        params: {},
     };
 
     if (hashparts.length > 1) {