diff --git a/build/cache.js b/build/cache.js
index bde26e5..c3f6f41 100644
--- a/build/cache.js
+++ b/build/cache.js
@@ -7,6 +7,7 @@ const { resolve, readFile } = require('./resolve');
 const { hasOwn, isFunction } = require('./lib/util');
 const revHash = require('rev-hash');
 const revPath = require('rev-path');
+const log = require('fancy-log');
 
 const CACHE = 'if-cache';
 const MANIFEST = 'if-cache.json';
@@ -72,14 +73,12 @@ module.exports = exports = class Manifest {
 
   async get (task) {
     if (task === undefined || task === null) {
-      console.error(task);
+      log.error(task);
       throw new Error('Task action is undefined or null.');
-      return;
     }
     if (task.input === undefined || task.input === null) {
-      console.error(task);
+      log.error(task);
       throw new Error('Task action is missing input. (tip: remove `twitter-cache.json` and run `gulp` again)');
-      return;
     }
 
     const hash = this.hash(task);
diff --git a/build/engines.js b/build/engines.js
index fc5861f..921bc91 100644
--- a/build/engines.js
+++ b/build/engines.js
@@ -24,7 +24,7 @@ const str2locale = {
   'fr': dateFNSLocales.fr,
   'hu': dateFNSLocales.hu,
   'pl': dateFNSLocales.pl,
-  'es': dateFNSLocales.es
+  'es': dateFNSLocales.es,
 };
 
 const markdownEngines = {
@@ -294,13 +294,14 @@ class Injectables {
     };
   }
 
-  // Given a list of arguments, returns the firt that isn't undefined
+  // Given a list of arguments, returns the first that isn't undefined
   coalesce () {
     return function (...raw_args) {
       const { arguments: args } = raw_args.pop();
-      for (let arg in args) {
-        if (args[arg] !== undefined) {
-          return args[arg];
+
+      for (const value of Object.values(args)) {
+        if (value !== undefined) {
+          return value;
         }
       }
       return undefined;
@@ -308,25 +309,25 @@ class Injectables {
   }
 
   // Multi tool for printing dates
-  // 
+  //
   // {{date}} -> prints current date
   // {{date datestr}} -> prints date in datestr
   // {{date datestr datefmt}} -> prints date in datestr in format datefmt
-  // {{date datestr datefmt lang}} -> prints date in datestr in format datefmt according to conventions for language lang 
-  // 
+  // {{date datestr datefmt lang}} -> prints date in datestr in format datefmt according to conventions for language lang
+  //
   // Datestr can be the string "now", `undefined`, and anything parsable by `new Date()`.
-  // 
+  //
   // If lang is not specified, it will be extracted from the page metadata. If that is not available, English will be assumed.
   // In case of errors, the date will be returned as an ISO string if possible and its raw datestr input otherwise.
   // Datefmt format is available at https://date-fns.org/v2.25.0/docs/format
-  // 
+  //
   // Common formats:
   // - "h:mm aa - EEE, LLL do, yyyy"  = 12 hour clock, e.g. '1:28 PM - Sat, Feb 15th, 2020' (en) or '1:28 PM - sam., 15/févr./2020' (fr)
   // - "hh:mm - EEE, LLL do, yyyy"    = 24 hour clock, e.g. '13:28 - Sat, Feb 15th, 2020' (en) or '13:28 - sam., 15/févr./2020' (fr)
   // - "yyyy-MM-dd'T'HH:mm:ss.SSSXXX" or "iso" = ISO 8601 format, e.g. '2020-02-15T13:28:02.000Z'
   date () {
     return function (...args) {
-      let extra = args.pop();
+      const extra = args.pop();
       let datestr, dateobj, datefmt, lang;
 
       const { resolve: rval } = extra;
@@ -335,7 +336,7 @@ class Injectables {
 
       switch (args.length) {
       case 0:
-        datestr = "now";
+        datestr = 'now';
         break;
       case 1:
         datestr = args[0];
@@ -350,21 +351,21 @@ class Injectables {
         lang = args[2];
         break;
       default:
-        throw new Exception('wrong number of arguments for {{date}}, got '+args.length+' maximum is 3');
+        throw new Error('wrong number of arguments for {{date}}, got ' + args.length + ' maximum is 3');
       }
 
-      if (datestr === "now" || datestr === undefined) {
+      if (datestr === 'now' || datestr === undefined) {
         dateobj = new Date();
       } else {
         dateobj = new Date(datestr);
       }
 
       if (!dateFNS.isValid(dateobj)) {
-        console.trace('Invalid input for date: ', { datestr, filename, args, extra });
+        log.error('Invalid input for date: ', { datestr, filename, args, extra });
         return datestr.toString();
       }
 
-      if (datefmt == "iso") {
+      if (datefmt === 'iso') {
         return dateobj.toISOString();
       }
 
@@ -374,7 +375,7 @@ class Injectables {
 
       const locale = str2locale[lang];
       if (locale === undefined) {
-        console.warn('Locale not found: '+lang);
+        log.warn('Locale not found: ' + lang);
       }
       if (datefmt === undefined || locale === undefined) {
         const options = {
@@ -386,20 +387,20 @@ class Injectables {
           timeZoneName: 'short',
           hour: '2-digit',
           minute: '2-digit',
-          second: '2-digit'
+          second: '2-digit',
         };
         try {
           return dateobj.toLocaleString(lang, options);
         } catch (error) {
-          console.trace('Something went horribly wrong while formating dates.', { error, filename, args, extra });
+          log.error('Something went horribly wrong while formating dates.', { error, filename, args, extra });
           return dateobj.toISOString();
         }
       }
 
       try {
-        return dateFNS.format(dateobj, datefmt, {locale: locale});
+        return dateFNS.format(dateobj, datefmt, { locale });
       } catch (error) {
-        console.trace('Something went horribly wrong while formating dates.', { error, filename, args, extra });
+        log.error('Something went horribly wrong while formating dates.', { error, filename, args, extra });
         return dateobj.toISOString();
       }
     };
diff --git a/build/page-tweets.js b/build/page-tweets.js
index 593fb28..7608af6 100644
--- a/build/page-tweets.js
+++ b/build/page-tweets.js
@@ -5,21 +5,11 @@ const log = require('fancy-log');
 const tweetparse = require('./lib/tweetparse');
 const Twitter = require('twitter-lite');
 const { hasOwn } = require('./lib/util');
-var twemoji = require('twemoji' );
 
-function tweetText2Html(tweet_text) {
-  let answer = tweet_text.split(/(\r\n|\n\r|\r|\n)+/)
-      .map((s) => s.trim() && '<p>' + s + '</p>')
-      .filter(Boolean)
-      .join('');
-  answer = twemoji.parse(answer);
-  return answer;
-}
-
-function applyI18N(original_tweet, twitter_i18n) {
+function applyI18N (original_tweet, twitter_i18n) {
   const id = original_tweet.id_str;
   // Make a shallow copy
-  let tweet = Object.assign({}, original_tweet);
+  const tweet = Object.assign({}, original_tweet);
 
   // Do we have a trnslation for this tweet?
   if (twitter_i18n[id] === undefined) {
@@ -28,10 +18,10 @@ function applyI18N(original_tweet, twitter_i18n) {
     delete tweet.full_text_i18n;
   } else {
     // If yes, add the translations
-    const originalLang = tweet["lang"] || "x-original";
+    const originalLang = tweet.lang || 'x-original';
     tweet.full_text_i18n = twitter_i18n[id].full_text_i18n;
-    if (originalLang in tweet.full_text_i18n && tweet.full_text_i18n[originalLang] != tweet.full_text) {
-      log.warn("Original text not matching for tweet "+id, { expected: tweet.full_text, got: tweet.full_text_i18n[originalLang]});
+    if (originalLang in tweet.full_text_i18n && tweet.full_text_i18n[originalLang] !== tweet.full_text) {
+      log.warn('Original text not matching for tweet ' + id, { expected: tweet.full_text, got: tweet.full_text_i18n[originalLang] });
     } else {
       tweet.full_text_i18n[originalLang] = tweet.full_text;
     }
@@ -179,7 +169,7 @@ exports.attachTweets = function (tweetids, tweets) {
   }, {});
 };
 
-exports.i18n = async function() {
+exports.i18n = async function () {
   const [ twitterBackup, twitterCache, twitterI18N ] = await Promise.all([
     fs.readJson(resolve('twitter-backup.json')),
     fs.readJson(resolve('twitter-cache.json')).catch(() => ({})),
@@ -189,15 +179,15 @@ exports.i18n = async function() {
   const twitterCacheBkp  = JSON.stringify(twitterCache,  null, 2);
 
   // Make sure no translation is forgotten
-  for (const id in twitterI18N) {
-    if (id in twitterBackup) {
+  for (const id of Object.keys(twitterI18N)) {
+    if (twitterBackup[id]) {
       twitterCache[id] = applyI18N(twitterBackup[id], twitterI18N);
       twitterCache[id] = tweetparse(twitterCache[id]);
     }
   }
 
   const twitterCacheJson  = JSON.stringify(twitterCache,  null, 2);
-  if (twitterCacheBkp != twitterCacheJson) {
+  if (twitterCacheBkp !== twitterCacheJson) {
     await fs.writeFile(resolve('twitter-cache.json'),  twitterCacheJson);
   }
-}
+};
diff --git a/build/page.js b/build/page.js
index 2294fee..86f4516 100644
--- a/build/page.js
+++ b/build/page.js
@@ -107,7 +107,7 @@ module.exports = exports = class Page extends File {
     const { titlecard, webready } = this.files = PublicFiles.for(this.dir);
     this.ignore = this.meta.ignore;
     this.draft = this.meta.draft;
-    this.lang = this.lang || this.meta.lang || "en";
+    this.lang = this.lang || this.meta.lang || 'en';
     this.siblings = this.meta.siblings;
     this.images = webready;
     this.titlecard = titlecard;
diff --git a/js/_fixer.js b/js/_fixer.js
index 512e271..6822009 100644
--- a/js/_fixer.js
+++ b/js/_fixer.js
@@ -1,15 +1,15 @@
-function fixTweetMentions() {
-       document.querySelectorAll('div.tweet-text> p').forEach((p) => {
-               for (const node of p.childNodes) {
-                       if (node.nodeType == Node.ELEMENT_NODE && node.tagName == "A" && node.classList.contains("mention")) {
-                               node.classList.add("initial-mention");
-                       } else if (node.nodeType == Node.TEXT_NODE && node.textContent.trim() == '') {
-                               // nothing to do
-                       } else {
-                               // we got to the main text of the tweet and must stop
-                               return;
-                       }
-               }
-       });
-   };
+function fixTweetMentions () {
+  document.querySelectorAll('div.tweet-text> p').forEach((p) => {
+    for (const node of p.childNodes) {
+      if (node.nodeType === Node.ELEMENT_NODE && node.tagName === 'A' && node.classList.contains('mention')) {
+        node.classList.add('initial-mention');
+      } else if (node.nodeType === Node.TEXT_NODE && node.textContent.trim() === '') {
+        // nothing to do
+      } else {
+        // we got to the main text of the tweet and must stop
+        return;
+      }
+    }
+  });
+}
 document.addEventListener('DOMContentLoaded', fixTweetMentions, false);