diff --git a/.eslintrc b/.eslintrc
index ea0fc5bcb2..76e6f8c48d 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -5,7 +5,7 @@ extends:
   - eslint:recommended
 
 ignorePatterns:
- - /web_src/js/vendor
+  - /web_src/js/vendor
 
 parserOptions:
   ecmaVersion: 2020
@@ -26,19 +26,22 @@ globals:
 
 rules:
   arrow-body-style: [0]
+  arrow-parens: [2, always]
   camelcase: [0]
   comma-dangle: [2, only-multiline]
   consistent-return: [0]
   default-case: [0]
   func-names: [0]
-  import/extensions: [0]
+  import/extensions: [2, always, {ignorePackages: true}]
   import/prefer-default-export: [0]
   max-len: [0]
+  multiline-comment-style: [2, separate-lines]
   newline-per-chained-call: [0]
   no-alert: [0]
   no-cond-assign: [2, except-parens]
   no-console: [1, {allow: [info, warn, error]}]
   no-continue: [0]
+  no-eq-null: [2]
   no-mixed-operators: [0]
   no-multi-assign: [0]
   no-new: [0]
@@ -49,8 +52,12 @@ rules:
   no-unused-vars: [2, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, ignoreRestSiblings: true}]
   no-use-before-define: [0]
   no-var: [2]
+  object-curly-spacing: [2, never]
   one-var-declaration-per-line: [0]
   one-var: [0]
+  operator-linebreak: [2, after]
   prefer-const: [2, {destructuring: all}]
   prefer-destructuring: [0]
+  quotes: [2, single, {avoidEscape: true, allowTemplateLiterals: true}]
   radix: [2, as-needed]
+  semi: [2, always, {omitLastInOneLineBlock: true}]
diff --git a/web_src/js/features/clipboard.js b/web_src/js/features/clipboard.js
index bd4a664c7a..a3b6b26eb3 100644
--- a/web_src/js/features/clipboard.js
+++ b/web_src/js/features/clipboard.js
@@ -2,7 +2,7 @@ export default async function initClipboard() {
   const els = document.querySelectorAll('.clipboard');
   if (!els || !els.length) return;
 
-  const { default: ClipboardJS } = await import(/* webpackChunkName: "clipboard" */'clipboard');
+  const {default: ClipboardJS} = await import(/* webpackChunkName: "clipboard" */'clipboard');
 
   const clipboard = new ClipboardJS(els);
   clipboard.on('success', (e) => {
diff --git a/web_src/js/features/contextPopup.js b/web_src/js/features/contextpopup.js
similarity index 94%
rename from web_src/js/features/contextPopup.js
rename to web_src/js/features/contextpopup.js
index 5acfa9c293..6feaa768c0 100644
--- a/web_src/js/features/contextPopup.js
+++ b/web_src/js/features/contextpopup.js
@@ -1,6 +1,6 @@
-import { svg } from '../utils.js';
+import {svg} from '../utils.js';
 
-const { AppSubUrl } = window.config;
+const {AppSubUrl} = window.config;
 
 export default function initContextPopups() {
   const refIssues = $('.ref-issue');
@@ -14,7 +14,7 @@ export default function initContextPopups() {
 
 function issuePopup(owner, repo, index, $element) {
   $.get(`${AppSubUrl}/api/v1/repos/${owner}/${repo}/issues/${index}`, (issue) => {
-    const createdAt = new Date(issue.created_at).toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });
+    const createdAt = new Date(issue.created_at).toLocaleDateString(undefined, {year: 'numeric', month: 'short', day: 'numeric'});
 
     let body = issue.body.replace(/\n+/g, ' ');
     if (body.length > 85) {
diff --git a/web_src/js/features/dropzone.js b/web_src/js/features/dropzone.js
index f5d5b36a18..428f1d677a 100644
--- a/web_src/js/features/dropzone.js
+++ b/web_src/js/features/dropzone.js
@@ -1,5 +1,5 @@
 export default async function createDropzone(el, opts) {
-  const [{ default: Dropzone }] = await Promise.all([
+  const [{default: Dropzone}] = await Promise.all([
     import(/* webpackChunkName: "dropzone" */'dropzone'),
     import(/* webpackChunkName: "dropzone" */'dropzone/dist/dropzone.css'),
   ]);
diff --git a/web_src/js/features/gitGraph.js b/web_src/js/features/gitgraph.js
similarity index 74%
rename from web_src/js/features/gitGraph.js
rename to web_src/js/features/gitgraph.js
index a18c575163..c0006a2596 100644
--- a/web_src/js/features/gitGraph.js
+++ b/web_src/js/features/gitgraph.js
@@ -2,7 +2,7 @@ export default async function initGitGraph() {
   const graphCanvas = document.getElementById('graph-canvas');
   if (!graphCanvas) return;
 
-  const { default: gitGraph } = await import(/* webpackChunkName: "gitgraph" */'../vendor/gitGraph.js');
+  const {default: gitGraph} = await import(/* webpackChunkName: "gitgraph" */'../vendor/gitgraph.js');
 
   const graphList = [];
   $('#graph-raw-list li span.node-relation').each(function () {
diff --git a/web_src/js/features/userHeatmap.js b/web_src/js/features/userheatmap.js
similarity index 89%
rename from web_src/js/features/userHeatmap.js
rename to web_src/js/features/userheatmap.js
index 4862bc436c..9a8e606b1a 100644
--- a/web_src/js/features/userHeatmap.js
+++ b/web_src/js/features/userheatmap.js
@@ -1,12 +1,12 @@
 import Vue from 'vue';
 
-const { AppSubUrl, heatmapUser } = window.config;
+const {AppSubUrl, heatmapUser} = window.config;
 
 export default async function initHeatmap() {
   const el = document.getElementById('user-heatmap');
   if (!el) return;
 
-  const { CalendarHeatmap } = await import(/* webpackChunkName: "userheatmap" */'vue-calendar-heatmap');
+  const {CalendarHeatmap} = await import(/* webpackChunkName: "userheatmap" */'vue-calendar-heatmap');
   Vue.component('calendarHeatmap', CalendarHeatmap);
 
   const vueDelimeters = ['${', '}'];
@@ -59,7 +59,7 @@ export default async function initHeatmap() {
           const chartData = [];
           for (let i = 0; i < chartRawData.length; i++) {
             self.totalContributions += chartRawData[i].contributions;
-            chartData[i] = { date: new Date(chartRawData[i].timestamp * 1000), count: chartRawData[i].contributions };
+            chartData[i] = {date: new Date(chartRawData[i].timestamp * 1000), count: chartRawData[i].contributions};
           }
           self.values = chartData;
           self.isLoading = false;
diff --git a/web_src/js/index.js b/web_src/js/index.js
index 32ed72f139..cd13372b42 100644
--- a/web_src/js/index.js
+++ b/web_src/js/index.js
@@ -2,24 +2,23 @@
 /* exported timeAddManual, toggleStopwatch, cancelStopwatch */
 /* exported toggleDeadlineForm, setDeadline, updateDeadline, deleteDependencyModal, cancelCodeComment, onOAuthLoginClick */
 
-import './publicPath.js';
+import './publicpath.js';
 import './polyfills.js';
 
 import Vue from 'vue';
 import 'jquery.are-you-sure';
-import './vendor/semanticDropdown.js';
-import { svg } from './utils.js';
+import './vendor/semanticdropdown.js';
+import {svg} from './utils.js';
 
-import initContextPopups from './features/contextPopup.js';
+import initContextPopups from './features/contextpopup.js';
 import initHighlight from './features/highlight.js';
-import initGitGraph from './features/gitGraph.js';
+import initGitGraph from './features/gitgraph.js';
 import initClipboard from './features/clipboard.js';
-import initUserHeatmap from './features/userHeatmap.js';
+import initUserHeatmap from './features/userheatmap.js';
 import createDropzone from './features/dropzone.js';
-
 import ActivityTopAuthors from './components/ActivityTopAuthors.vue';
 
-const { AppSubUrl, StaticUrlPrefix, csrf } = window.config;
+const {AppSubUrl, StaticUrlPrefix, csrf} = window.config;
 
 function htmlEncode(text) {
   return jQuery('<div />').text(text).html();
@@ -99,7 +98,6 @@ function initEditDiffTab($form) {
   });
 }
 
-
 function initEditForm() {
   if ($('.edit.form').length === 0) {
     return;
@@ -184,7 +182,7 @@ function initReactionSelector(parent) {
     reactions = '.reactions > ';
   }
 
-  parent.find(`${reactions}a.label`).popup({ position: 'bottom left', metadata: { content: 'title', title: 'none' } });
+  parent.find(`${reactions}a.label`).popup({position: 'bottom left', metadata: {content: 'title', title: 'none'}});
 
   parent.find(`.select-reaction > .menu > .item, ${reactions}a.label`).on('click', function (e) {
     const vm = this;
@@ -192,9 +190,7 @@ function initReactionSelector(parent) {
 
     if ($(this).hasClass('disabled')) return;
 
-    const actionURL = $(this).hasClass('item')
-      ? $(this).closest('.select-reaction').data('action-url')
-      : $(this).data('action-url');
+    const actionURL = $(this).hasClass('item') ? $(this).closest('.select-reaction').data('action-url') : $(this).data('action-url');
     const url = `${actionURL}/${$(this).hasClass('blue') ? 'unreact' : 'react'}`;
     $.ajax({
       type: 'POST',
@@ -235,9 +231,7 @@ function insertAtCursor(field, value) {
   if (field.selectionStart || field.selectionStart === 0) {
     const startPos = field.selectionStart;
     const endPos = field.selectionEnd;
-    field.value = field.value.substring(0, startPos)
-            + value
-            + field.value.substring(endPos, field.value.length);
+    field.value = field.value.substring(0, startPos) + value + field.value.substring(endPos, field.value.length);
     field.selectionStart = startPos + value.length;
     field.selectionEnd = startPos + value.length;
   } else {
@@ -262,13 +256,13 @@ function retrieveImageFromClipboardAsBlob(pasteEvent, callback) {
     return;
   }
 
-  const { items } = pasteEvent.clipboardData;
+  const {items} = pasteEvent.clipboardData;
   if (typeof items === 'undefined') {
     return;
   }
 
   for (let i = 0; i < items.length; i++) {
-    if (items[i].type.indexOf('image') === -1) continue;
+    if (!items[i].type.includes('image')) continue;
     const blob = items[i].getAsFile();
 
     if (typeof (callback) === 'function') {
@@ -282,11 +276,11 @@ function retrieveImageFromClipboardAsBlob(pasteEvent, callback) {
 function uploadFile(file, callback) {
   const xhr = new XMLHttpRequest();
 
-  xhr.onload = function () {
+  xhr.addEventListener('load', () => {
     if (xhr.status === 200) {
       callback(xhr.responseText);
     }
-  };
+  });
 
   xhr.open('post', `${AppSubUrl}/attachments`, true);
   xhr.setRequestHeader('X-Csrf-Token', csrf);
@@ -493,8 +487,8 @@ function initCommentForm() {
             htmlEncode($(this).text())}</a>`);
           break;
         case '#assignee_id':
-          $list.find('.selected').html(`<a class="item" href=${$(this).data('href')}>`
-                        + `<img class="ui avatar image" src=${$(this).data('avatar')}>${
+          $list.find('.selected').html(`<a class="item" href=${$(this).data('href')}>` +
+                        `<img class="ui avatar image" src=${$(this).data('avatar')}>${
                           htmlEncode($(this).text())}</a>`);
       }
       $(`.ui${select_id}.list .no-select`).addClass('hide');
@@ -654,7 +648,7 @@ function initRepository() {
           window.location.href = $choice.data('url');
         }
       },
-      message: { noResults: $dropdown.data('no-results') }
+      message: {noResults: $dropdown.data('no-results')}
     });
   }
 
@@ -797,13 +791,11 @@ function initRepository() {
         $.post(update_url, {
           _csrf: csrf,
           target_branch: targetBranch
-        })
-          .success((data) => {
-            $branchTarget.text(data.base_branch);
-          })
-          .always(() => {
-            reload();
-          });
+        }).success((data) => {
+          $branchTarget.text(data.base_branch);
+        }).always(() => {
+          reload();
+        });
       };
 
       const pullrequest_target_update_url = $(this).data('target-update-url');
@@ -814,8 +806,7 @@ function initRepository() {
         $.post($(this).data('update-url'), {
           _csrf: csrf,
           title: $editInput.val()
-        },
-        (data) => {
+        }, (data) => {
           $editInput.val(data.title);
           $issueTitle.text(data.title);
           pullrequest_targetbranch_change(pullrequest_target_update_url);
@@ -887,7 +878,7 @@ function initRepository() {
           const filenameDict = {};
           dz = await createDropzone($dropzone[0], {
             url: $dropzone.data('upload-url'),
-            headers: { 'X-Csrf-Token': csrf },
+            headers: {'X-Csrf-Token': csrf},
             maxFiles: $dropzone.data('max-file'),
             maxFilesize: $dropzone.data('max-size'),
             acceptedFiles: ($dropzone.data('accepts') === '*/*') ? null : $dropzone.data('accepts'),
@@ -1142,8 +1133,8 @@ function initMigration() {
   const toggleMigrations = function () {
     const authUserName = $('#auth_username').val();
     const cloneAddr = $('#clone_addr').val();
-    if (!$('#mirror').is(':checked') && (authUserName && authUserName.length > 0)
-        && (cloneAddr !== undefined && (cloneAddr.startsWith('https://github.com') || cloneAddr.startsWith('http://github.com')))) {
+    if (!$('#mirror').is(':checked') && (authUserName && authUserName.length > 0) &&
+        (cloneAddr !== undefined && (cloneAddr.startsWith('https://github.com') || cloneAddr.startsWith('http://github.com')))) {
       $('#migrate_items').show();
     } else {
       $('#migrate_items').hide();
@@ -1203,8 +1194,7 @@ function initPullRequestReview() {
     .on('mouseenter', function () {
       const parent = $(this).closest('td');
       $(this).closest('tr').addClass(
-        parent.hasClass('lines-num-old') || parent.hasClass('lines-code-old')
-          ? 'focus-lines-old' : 'focus-lines-new'
+        parent.hasClass('lines-num-old') || parent.hasClass('lines-code-old') ? 'focus-lines-old' : 'focus-lines-new'
       );
     })
     .on('mouseleave', function () {
@@ -1225,8 +1215,8 @@ function initPullRequestReview() {
     let ntr = tr.next();
     if (!ntr.hasClass('add-comment')) {
       ntr = $(`<tr class="add-comment">${
-        isSplit ? '<td class="lines-num"></td><td class="lines-type-marker"></td><td class="add-comment-left"></td><td class="lines-num"></td><td class="lines-type-marker"></td><td class="add-comment-right"></td>'
-          : '<td class="lines-num"></td><td class="lines-num"></td><td class="lines-type-marker"></td><td class="add-comment-left add-comment-right"></td>'
+        isSplit ? '<td class="lines-num"></td><td class="lines-type-marker"></td><td class="add-comment-left"></td><td class="lines-num"></td><td class="lines-type-marker"></td><td class="add-comment-right"></td>' :
+          '<td class="lines-num"></td><td class="lines-num"></td><td class="lines-type-marker"></td><td class="add-comment-left add-comment-right"></td>'
       }</tr>`);
       tr.after(ntr);
     }
@@ -1297,7 +1287,7 @@ function initWikiForm() {
           // FIXME: still send render request when return back to edit mode
           const render = function () {
             sideBySideChanges = 0;
-            if (sideBySideTimeout != null) {
+            if (sideBySideTimeout !== null) {
               clearTimeout(sideBySideTimeout);
               sideBySideTimeout = null;
             }
@@ -1306,8 +1296,7 @@ function initWikiForm() {
               mode: 'gfm',
               context: $editArea.data('context'),
               text: plainText
-            },
-            (data) => {
+            }, (data) => {
               preview.innerHTML = `<div class="markdown ui segment">${data}</div>`;
               emojify.run($('.editor-preview')[0]);
               $(preview).find('pre code').each((_, e) => {
@@ -1324,7 +1313,7 @@ function initWikiForm() {
               render();
             }
             // or delay preview by timeout
-            if (sideBySideTimeout != null) {
+            if (sideBySideTimeout !== null) {
               clearTimeout(sideBySideTimeout);
               sideBySideTimeout = null;
             }
@@ -1479,8 +1468,7 @@ function setSimpleMDE($editArea) {
           mode: 'gfm',
           context: $editArea.data('context'),
           text: plainText
-        },
-        (data) => {
+        }, (data) => {
           preview.innerHTML = `<div class="markdown ui segment">${data}</div>`;
           emojify.run($('.editor-preview')[0]);
         });
@@ -1658,7 +1646,7 @@ function initEditor() {
       apiCall = extension;
     }
 
-    if (previewLink.length && apiCall && previewFileModes && previewFileModes.length && previewFileModes.indexOf(apiCall) >= 0) {
+    if (previewLink.length && apiCall && previewFileModes && previewFileModes.length && previewFileModes.includes(apiCall)) {
       dataUrl = previewLink.data('url');
       previewLink.data('url', dataUrl.replace(/(.*)\/.*/i, `$1/${mode}`));
       previewLink.show();
@@ -1667,7 +1655,7 @@ function initEditor() {
     }
 
     // If this file is a Markdown extensions, we will load that editor and return
-    if (markdownFileExts.indexOf(extWithDot) >= 0) {
+    if (markdownFileExts.includes(extWithDot)) {
       if (setSimpleMDE($editArea)) {
         return;
       }
@@ -1683,7 +1671,7 @@ function initEditor() {
       CodeMirror.autoLoadMode(codeMirrorEditor, mode);
     }
 
-    if (lineWrapExtensions.indexOf(extWithDot) >= 0) {
+    if (lineWrapExtensions.includes(extWithDot)) {
       codeMirrorEditor.setOption('lineWrapping', true);
     } else {
       codeMirrorEditor.setOption('lineWrapping', false);
@@ -1708,7 +1696,7 @@ function initEditor() {
         // - https://codemirror.net/doc/manual.html#keymaps
         codeMirrorEditor.setOption('extraKeys', {
           Tab(cm) {
-            const spaces = Array(parseInt(cm.getOption('indentUnit')) + 1).join(' ');
+            const spaces = new Array(parseInt(cm.getOption('indentUnit')) + 1).join(' ');
             cm.replaceSelection(spaces);
           }
         });
@@ -2071,7 +2059,7 @@ function searchUsers() {
           });
         });
 
-        return { results: items };
+        return {results: items};
       }
     },
     searchFields: ['login', 'full_name'],
@@ -2085,7 +2073,7 @@ function searchTeams() {
     minCharacters: 2,
     apiSettings: {
       url: `${AppSubUrl}/api/v1/orgs/${$searchTeamBox.data('org')}/teams/search?q={query}`,
-      headers: { 'X-Csrf-Token': csrf },
+      headers: {'X-Csrf-Token': csrf},
       onResponse(response) {
         const items = [];
         $.each(response.data, (_i, item) => {
@@ -2095,7 +2083,7 @@ function searchTeams() {
           });
         });
 
-        return { results: items };
+        return {results: items};
       }
     },
     searchFields: ['name', 'description'],
@@ -2118,7 +2106,7 @@ function searchRepositories() {
           });
         });
 
-        return { results: items };
+        return {results: items};
       }
     },
     searchFields: ['full_name'],
@@ -2153,7 +2141,7 @@ function initCodeView() {
       }
     }).trigger('hashchange');
   }
-  $('.fold-code').on('click', ({ target }) => {
+  $('.fold-code').on('click', ({target}) => {
     const box = target.closest('.file-content');
     const folded = box.dataset.folded !== 'true';
     target.classList.add(`fa-chevron-${folded ? 'right' : 'down'}`);
@@ -2165,11 +2153,11 @@ function initCodeView() {
     const $row = $blob.parent().parent();
     $.get(`${$blob.data('url')}?${$blob.data('query')}&anchor=${$blob.data('anchor')}`, (blob) => {
       $row.replaceWith(blob);
-      $(`[data-anchor="${$blob.data('anchor')}"]`).on('click', (e) => { insertBlobExcerpt(e); });
+      $(`[data-anchor="${$blob.data('anchor')}"]`).on('click', (e) => { insertBlobExcerpt(e) });
       $('.diff-detail-box.ui.sticky').sticky();
     });
   }
-  $('.ui.blob-excerpt').on('click', (e) => { insertBlobExcerpt(e); });
+  $('.ui.blob-excerpt').on('click', (e) => { insertBlobExcerpt(e) });
 }
 
 function initU2FAuth() {
@@ -2198,7 +2186,7 @@ function u2fSigned(resp) {
   $.ajax({
     url: `${AppSubUrl}/user/u2f/sign`,
     type: 'POST',
-    headers: { 'X-Csrf-Token': csrf },
+    headers: {'X-Csrf-Token': csrf},
     data: JSON.stringify(resp),
     contentType: 'application/json; charset=utf-8',
   }).done((res) => {
@@ -2215,7 +2203,7 @@ function u2fRegistered(resp) {
   $.ajax({
     url: `${AppSubUrl}/user/settings/security/u2f/register`,
     type: 'POST',
-    headers: { 'X-Csrf-Token': csrf },
+    headers: {'X-Csrf-Token': csrf},
     data: JSON.stringify(resp),
     contentType: 'application/json; charset=utf-8',
     success() {
@@ -2238,7 +2226,6 @@ function checkError(resp) {
   return true;
 }
 
-
 function u2fError(errorType) {
   const u2fErrors = {
     browser: $('#unsupported-browser'),
@@ -2259,8 +2246,8 @@ function u2fError(errorType) {
 }
 
 function initU2FRegister() {
-  $('#register-device').modal({ allowMultiple: false });
-  $('#u2f-error').modal({ allowMultiple: false });
+  $('#register-device').modal({allowMultiple: false});
+  $('#u2f-error').modal({allowMultiple: false});
   $('#register-security-key').on('click', (e) => {
     e.preventDefault();
     u2fApi.ensureSupport()
@@ -2337,7 +2324,7 @@ function initTemplateSearch() {
         apiSettings: {
           url: `${AppSubUrl}/api/v1/repos/search?q={query}&template=true&priority_owner_id=${$('#uid').val()}`,
           onResponse(response) {
-            const filteredResponse = { success: true, results: [] };
+            const filteredResponse = {success: true, results: []};
             filteredResponse.results.push({
               name: '',
               value: ''
@@ -2417,7 +2404,7 @@ $(document).ready(async () => {
 
     await createDropzone('#dropzone', {
       url: $dropzone.data('upload-url'),
-      headers: { 'X-Csrf-Token': csrf },
+      headers: {'X-Csrf-Token': csrf},
       maxFiles: $dropzone.data('max-file'),
       maxFilesize: $dropzone.data('max-size'),
       acceptedFiles: ($dropzone.data('accepts') === '*/*') ? null : $dropzone.data('accepts'),
@@ -2515,12 +2502,12 @@ $(document).ready(async () => {
   });
 
   $('.issue-action').click(function () {
-    let { action } = this.dataset;
-    let { elementId } = this.dataset;
+    let {action} = this.dataset;
+    let {elementId} = this.dataset;
     const issueIDs = $('.issue-checkbox').children('input:checked').map(function () {
       return this.dataset.issueId;
     }).get().join();
-    const { url } = this.dataset;
+    const {url} = this.dataset;
     if (elementId === '0' && url.substr(-9) === '/assignee') {
       elementId = '';
       action = 'clear';
@@ -2529,7 +2516,7 @@ $(document).ready(async () => {
       // NOTICE: This reset of checkbox state targets Firefox caching behaviour, as the checkboxes stay checked after reload
       if (action === 'close' || action === 'open') {
         // uncheck all checkboxes
-        $('.issue-checkbox input[type="checkbox"]').each((_, e) => { e.checked = false; });
+        $('.issue-checkbox input[type="checkbox"]').each((_, e) => { e.checked = false });
       }
       reload();
     });
@@ -3031,8 +3018,8 @@ function initFilterBranchTagDropdown(selector) {
           const vm = this;
 
           const items = vm.items.filter((item) => {
-            return ((vm.mode === 'branches' && item.branch) || (vm.mode === 'tags' && item.tag))
-              && (!vm.searchTerm || item.name.toLowerCase().indexOf(vm.searchTerm.toLowerCase()) >= 0);
+            return ((vm.mode === 'branches' && item.branch) || (vm.mode === 'tags' && item.tag)) &&
+              (!vm.searchTerm || item.name.toLowerCase().includes(vm.searchTerm.toLowerCase()));
           });
 
           vm.active = (items.length === 0 && vm.showCreateNewBranch ? 0 : -1);
@@ -3226,7 +3213,7 @@ function initTopicbar() {
         if (xhr.responseJSON.invalidTopics.length > 0) {
           topicPrompts.formatPrompt = xhr.responseJSON.message;
 
-          const { invalidTopics } = xhr.responseJSON;
+          const {invalidTopics} = xhr.responseJSON;
           const topicLables = topicDropdown.children('a.ui.label');
 
           topics.split(',').forEach((value, index) => {
@@ -3248,7 +3235,7 @@ function initTopicbar() {
   topicDropdown.dropdown({
     allowAdditions: true,
     forceSelection: false,
-    fields: { name: 'description', value: 'data-value' },
+    fields: {name: 'description', value: 'data-value'},
     saveRemoteData: false,
     label: {
       transition: 'horizontal flip',
@@ -3276,20 +3263,20 @@ function initTopicbar() {
         const query = stripTags(this.urlData.query.trim());
         let found_query = false;
         const current_topics = [];
-        topicDropdown.find('div.label.visible.topic,a.label.visible').each((_, e) => { current_topics.push(e.dataset.value); });
+        topicDropdown.find('div.label.visible.topic,a.label.visible').each((_, e) => { current_topics.push(e.dataset.value) });
 
         if (res.topics) {
           let found = false;
           for (let i = 0; i < res.topics.length; i++) {
             // skip currently added tags
-            if (current_topics.indexOf(res.topics[i].topic_name) !== -1) {
+            if (current_topics.includes(res.topics[i].topic_name)) {
               continue;
             }
 
             if (res.topics[i].topic_name.toLowerCase() === query.toLowerCase()) {
               found_query = true;
             }
-            formattedResponse.results.push({ description: res.topics[i].topic_name, 'data-value': res.topics[i].topic_name });
+            formattedResponse.results.push({description: res.topics[i].topic_name, 'data-value': res.topics[i].topic_name});
             found = true;
           }
           formattedResponse.success = found;
@@ -3297,7 +3284,7 @@ function initTopicbar() {
 
         if (query.length > 0 && !found_query) {
           formattedResponse.success = true;
-          formattedResponse.results.unshift({ description: query, 'data-value': query });
+          formattedResponse.results.unshift({description: query, 'data-value': query});
         } else if (query.length > 0 && found_query) {
           formattedResponse.results.sort((a, b) => {
             if (a.description.toLowerCase() === query.toLowerCase()) return -1;
@@ -3308,7 +3295,6 @@ function initTopicbar() {
           });
         }
 
-
         return formattedResponse;
       },
     },
@@ -3427,7 +3413,7 @@ function initIssueList() {
       apiSettings: {
         url: issueSearchUrl,
         onResponse(response) {
-          const filteredResponse = { success: true, results: [] };
+          const filteredResponse = {success: true, results: []};
           const currIssueId = $('#new-dependency-drop-list').data('issue-id');
           // Parse the response from the api to work with our dropdown
           $.each(response, (_i, issue) => {
diff --git a/web_src/js/publicPath.js b/web_src/js/publicpath.js
similarity index 71%
rename from web_src/js/publicPath.js
rename to web_src/js/publicpath.js
index 120740d708..392c03e700 100644
--- a/web_src/js/publicPath.js
+++ b/web_src/js/publicpath.js
@@ -1,5 +1,5 @@
-/* This sets up webpack's chunk loading to load resources from the 'public'
-  directory. This file must be imported before any lazy-loading is being attempted. */
+// This sets up webpack's chunk loading to load resources from the 'public'
+// directory. This file must be imported before any lazy-loading is being attempted.
 
 if (document.currentScript && document.currentScript.src) {
   const url = new URL(document.currentScript.src);
diff --git a/web_src/js/vendor/gitGraph.js b/web_src/js/vendor/gitgraph.js
similarity index 100%
rename from web_src/js/vendor/gitGraph.js
rename to web_src/js/vendor/gitgraph.js
diff --git a/web_src/js/vendor/semanticDropdown.js b/web_src/js/vendor/semanticdropdown.js
similarity index 100%
rename from web_src/js/vendor/semanticDropdown.js
rename to web_src/js/vendor/semanticdropdown.js
diff --git a/webpack.config.js b/webpack.config.js
index dd8688406e..4630710609 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -9,11 +9,11 @@ const PostCSSSafeParser = require('postcss-safe-parser');
 const SpriteLoaderPlugin = require('svg-sprite-loader/plugin');
 const TerserPlugin = require('terser-webpack-plugin');
 const VueLoaderPlugin = require('vue-loader/lib/plugin');
-const { statSync } = require('fs');
-const { resolve, parse } = require('path');
-const { SourceMapDevToolPlugin } = require('webpack');
+const {statSync} = require('fs');
+const {resolve, parse} = require('path');
+const {SourceMapDevToolPlugin} = require('webpack');
 
-const glob = (pattern) => fastGlob.sync(pattern, { cwd: __dirname, absolute: true });
+const glob = (pattern) => fastGlob.sync(pattern, {cwd: __dirname, absolute: true});
 
 const themes = {};
 for (const path of glob('web_src/less/themes/*.less')) {
@@ -157,7 +157,7 @@ module.exports = {
               extract: true,
               spriteFilename: 'img/svg/icons.svg',
               symbolId: (path) => {
-                const { name } = parse(path);
+                const {name} = parse(path);
                 if (/@primer[/\\]octicons/.test(path)) {
                   return `octicon-${name}`;
                 }
@@ -194,7 +194,7 @@ module.exports = {
     }),
     new CopyPlugin([
       // workaround for https://github.com/go-gitea/gitea/issues/10653
-      { from: 'node_modules/fomantic-ui/dist/semantic.min.css', to: 'fomantic/semantic.min.css' },
+      {from: 'node_modules/fomantic-ui/dist/semantic.min.css', to: 'fomantic/semantic.min.css'},
     ]),
   ],
   performance: {