diff --git a/package-lock.json b/package-lock.json
index fd008836a6..2fcc08904d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8145,6 +8145,14 @@
       "resolved": "https://registry.npmjs.org/jquery-migrate/-/jquery-migrate-3.1.0.tgz",
       "integrity": "sha512-u/MtE1ST2pCr3rCyouJG2xMiw/k3OzLNeRKprjKTeHUezCGr0DyEgeXFdqFLmQfxfR5EsVu+mGo/sCcYdiYcIQ=="
     },
+    "jquery.are-you-sure": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/jquery.are-you-sure/-/jquery.are-you-sure-1.9.0.tgz",
+      "integrity": "sha512-2r0uFx8CyAopjeHGOdvvwpFP921TnW1+v1uJXcAWQYHYGB1tryTDhQY+5u6HsVeMwbWiRTKVZFWnLaFpDvIqZQ==",
+      "requires": {
+        "jquery": ">=1.4.2"
+      }
+    },
     "js-beautify": {
       "version": "1.10.3",
       "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.10.3.tgz",
diff --git a/package.json b/package.json
index ae723a90a8..5158d1e27f 100644
--- a/package.json
+++ b/package.json
@@ -9,6 +9,7 @@
     "highlight.js": "9.18.0",
     "jquery": "3.4.1",
     "jquery-migrate": "3.1.0",
+    "jquery.are-you-sure": "1.9.0",
     "swagger-ui": "3.24.3",
     "vue-bar-graph": "1.2.0"
   },
diff --git a/public/vendor/VERSIONS b/public/vendor/VERSIONS
index c012339ed4..28148bdaac 100644
--- a/public/vendor/VERSIONS
+++ b/public/vendor/VERSIONS
@@ -2,9 +2,6 @@
 # To do: Choose a dependency management solution and use it to replace both files.
 # Notes:  Download and license information is available in librejs.html.
 
-File(s): /vendor/plugins/jquery.areyousure/jquery.are-you-sure.js
-Version: 1.9.0
-
 File(s): /vendor/plugins/jquery/jquery.min.js
 Version: 3.4.1
 
diff --git a/public/vendor/librejs.html b/public/vendor/librejs.html
index 0e9201094f..74f446f1a1 100644
--- a/public/vendor/librejs.html
+++ b/public/vendor/librejs.html
@@ -11,7 +11,7 @@
       </thead>
       <tbody>
         <tr>
-          <td><a href="./plugins/jquery.areyousure/jquery.are-you-sure.js">jquery.are-you-sure.js</a></td>
+          <td><a href="./js/index.js">jquery.are-you-sure.js</a></td>
           <td><a href="http://www.freebsd.org/copyright/freebsd-license.html">Expat</a></td>
           <td><a href="https://github.com/codedance/jquery.AreYouSure/archive/1.9.0.tar.gz">jquery.areyousure-1.9.0.tar.gz</a></td>
         </tr>
diff --git a/public/vendor/plugins/jquery.areyousure/LICENSE b/public/vendor/plugins/jquery.areyousure/LICENSE
deleted file mode 100644
index 0374ebc839..0000000000
--- a/public/vendor/plugins/jquery.areyousure/LICENSE
+++ /dev/null
@@ -1,18 +0,0 @@
-The MIT License
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the 'Software'), to deal in the
-Software without restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
-Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
-INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
-PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/public/vendor/plugins/jquery.areyousure/jquery.are-you-sure.js b/public/vendor/plugins/jquery.areyousure/jquery.are-you-sure.js
deleted file mode 100644
index 3c41e2fccb..0000000000
--- a/public/vendor/plugins/jquery.areyousure/jquery.are-you-sure.js
+++ /dev/null
@@ -1,192 +0,0 @@
-/*!
- * jQuery Plugin: Are-You-Sure (Dirty Form Detection)
- * https://github.com/codedance/jquery.AreYouSure/
- *
- * Copyright (c) 2012-2014, Chris Dance and PaperCut Software http://www.papercut.com/
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * Author:  chris.dance@papercut.com
- * Version: 1.9.0
- * Date:    13th August 2014
- */
-(function($) {
-  
-  $.fn.areYouSure = function(options) {
-      
-    var settings = $.extend(
-      {
-        'message' : 'You have unsaved changes!',
-        'dirtyClass' : 'dirty',
-        'change' : null,
-        'silent' : false,
-        'addRemoveFieldsMarksDirty' : false,
-        'fieldEvents' : 'change keyup propertychange input',
-        'fieldSelector': ":input:not(input[type=submit]):not(input[type=button])"
-      }, options);
-
-    var getValue = function($field) {
-      if ($field.hasClass('ays-ignore')
-          || $field.hasClass('aysIgnore')
-          || $field.attr('data-ays-ignore')
-          || $field.attr('name') === undefined) {
-        return null;
-      }
-
-      if ($field.is(':disabled')) {
-        return 'ays-disabled';
-      }
-
-      var val;
-      var type = $field.attr('type');
-      if ($field.is('select')) {
-        type = 'select';
-      }
-
-      switch (type) {
-        case 'checkbox':
-        case 'radio':
-          val = $field.is(':checked');
-          break;
-        case 'select':
-          val = '';
-          $field.find('option').each(function(o) {
-            var $option = $(this);
-            if ($option.is(':selected')) {
-              val += $option.val();
-            }
-          });
-          break;
-        default:
-          val = $field.val();
-      }
-
-      return val;
-    };
-
-    var storeOrigValue = function($field) {
-      $field.data('ays-orig', getValue($field));
-    };
-
-    var checkForm = function(evt) {
-
-      var isFieldDirty = function($field) {
-        var origValue = $field.data('ays-orig');
-        if (undefined === origValue) {
-          return false;
-        }
-        return (getValue($field) != origValue);
-      };
-
-      var $form = ($(this).is('form')) 
-                    ? $(this)
-                    : $(this).parents('form');
-
-      // Test on the target first as it's the most likely to be dirty
-      if (isFieldDirty($(evt.target))) {
-        setDirtyStatus($form, true);
-        return;
-      }
-
-      $fields = $form.find(settings.fieldSelector);
-
-      if (settings.addRemoveFieldsMarksDirty) {              
-        // Check if field count has changed
-        var origCount = $form.data("ays-orig-field-count");
-        if (origCount != $fields.length) {
-          setDirtyStatus($form, true);
-          return;
-        }
-      }
-
-      // Brute force - check each field
-      var isDirty = false;
-      $fields.each(function() {
-        $field = $(this);
-        if (isFieldDirty($field)) {
-          isDirty = true;
-          return false; // break
-        }
-      });
-      
-      setDirtyStatus($form, isDirty);
-    };
-
-    var initForm = function($form) {
-      var fields = $form.find(settings.fieldSelector);
-      $(fields).each(function() { storeOrigValue($(this)); });
-      $(fields).unbind(settings.fieldEvents, checkForm);
-      $(fields).bind(settings.fieldEvents, checkForm);
-      $form.data("ays-orig-field-count", $(fields).length);
-      setDirtyStatus($form, false);
-    };
-
-    var setDirtyStatus = function($form, isDirty) {
-      var changed = isDirty != $form.hasClass(settings.dirtyClass);
-      $form.toggleClass(settings.dirtyClass, isDirty);
-        
-      // Fire change event if required
-      if (changed) {
-        if (settings.change) settings.change.call($form, $form);
-
-        if (isDirty) $form.trigger('dirty.areYouSure', [$form]);
-        if (!isDirty) $form.trigger('clean.areYouSure', [$form]);
-        $form.trigger('change.areYouSure', [$form]);
-      }
-    };
-
-    var rescan = function() {
-      var $form = $(this);
-      var fields = $form.find(settings.fieldSelector);
-      $(fields).each(function() {
-        var $field = $(this);
-        if (!$field.data('ays-orig')) {
-          storeOrigValue($field);
-          $field.bind(settings.fieldEvents, checkForm);
-        }
-      });
-      // Check for changes while we're here
-      $form.trigger('checkform.areYouSure');
-    };
-
-    var reinitialize = function() {
-      initForm($(this));
-    }
-
-    if (!settings.silent && !window.aysUnloadSet) {
-      window.aysUnloadSet = true;
-      $(window).bind('beforeunload', function() {
-        $dirtyForms = $("form").filter('.' + settings.dirtyClass);
-        if ($dirtyForms.length == 0) {
-          return;
-        }
-        // Prevent multiple prompts - seen on Chrome and IE
-        if (navigator.userAgent.toLowerCase().match(/msie|chrome/)) {
-          if (window.aysHasPrompted) {
-            return;
-          }
-          window.aysHasPrompted = true;
-          window.setTimeout(function() {window.aysHasPrompted = false;}, 900);
-        }
-        return settings.message;
-      });
-    }
-
-    return this.each(function(elem) {
-      if (!$(this).is('form')) {
-        return;
-      }
-      var $form = $(this);
-        
-      $form.submit(function() {
-        $form.removeClass(settings.dirtyClass);
-      });
-      $form.bind('reset', function() { setDirtyStatus($form, false); });
-      // Add a custom events
-      $form.bind('rescan.areYouSure', rescan);
-      $form.bind('reinitialize.areYouSure', reinitialize);
-      $form.bind('checkform.areYouSure', checkForm);
-      initForm($form);
-    });
-  };
-})(jQuery);
diff --git a/templates/base/footer.tmpl b/templates/base/footer.tmpl
index db196c41a1..12da6fe796 100644
--- a/templates/base/footer.tmpl
+++ b/templates/base/footer.tmpl
@@ -13,7 +13,6 @@
 	{{template "base/footer_content" .}}
 
 	<script src="{{StaticUrlPrefix}}/js/jquery.js?v={{MD5 AppVer}}"></script>
-	<script src="{{StaticUrlPrefix}}/vendor/plugins/jquery.areyousure/jquery.are-you-sure.js"></script>
 {{if .RequireSimpleMDE}}
 	<script src="{{StaticUrlPrefix}}/vendor/plugins/simplemde/simplemde.min.js"></script>
 	<script src="{{StaticUrlPrefix}}/vendor/plugins/codemirror/addon/mode/loadmode.js"></script>
diff --git a/templates/pwa/serviceworker_js.tmpl b/templates/pwa/serviceworker_js.tmpl
index e4ff2fc07e..5140cd489b 100644
--- a/templates/pwa/serviceworker_js.tmpl
+++ b/templates/pwa/serviceworker_js.tmpl
@@ -12,7 +12,6 @@ var urlsToCache = [
   '{{StaticUrlPrefix}}/vendor/plugins/codemirror/mode/meta.js',
   '{{StaticUrlPrefix}}/vendor/plugins/dropzone/dropzone.js',
   '{{StaticUrlPrefix}}/vendor/plugins/emojify/emojify.custom.js',
-  '{{StaticUrlPrefix}}/vendor/plugins/jquery.areyousure/jquery.are-you-sure.js',
   '{{StaticUrlPrefix}}/vendor/plugins/jquery.datetimepicker/jquery.datetimepicker.js',
   '{{StaticUrlPrefix}}/vendor/plugins/jquery.minicolors/jquery.minicolors.min.js',
   '{{StaticUrlPrefix}}/vendor/plugins/simplemde/simplemde.min.js',
diff --git a/web_src/js/index.js b/web_src/js/index.js
index 75be2363a9..f634bb1135 100644
--- a/web_src/js/index.js
+++ b/web_src/js/index.js
@@ -2,6 +2,7 @@
 /* exported timeAddManual, toggleStopwatch, cancelStopwatch, initHeatmap */
 /* exported toggleDeadlineForm, setDeadline, updateDeadline, deleteDependencyModal, cancelCodeComment, onOAuthLoginClick */
 
+import 'jquery.are-you-sure';
 import './publicPath.js';
 import './polyfills.js';
 import './gitGraphLoader.js';