diff --git a/lib/LANraragi/Utils/Routing.pm b/lib/LANraragi/Utils/Routing.pm
index ae9b8b9c1..8fe53bcd5 100644
--- a/lib/LANraragi/Utils/Routing.pm
+++ b/lib/LANraragi/Utils/Routing.pm
@@ -68,6 +68,18 @@ sub apply_routes {
# Routers used for all loginless routes
my $public_routes = $self->routes;
+ $public_routes->get( '/js/:version/*filepath' => [ version => qr/\d+\.\d+\.\d+/ ] )->to(
+ cb => sub {
+ my $c = shift;
+
+ my $relFilePath = Mojo::Path->new( "/js/" . $c->stash('filepath') )->canonicalize;
+ return $c->reply->exception('Bad Request') unless index( $relFilePath, ".." ) == -1;
+
+ $c->res->headers->cache_control('public, max-age=31536000, immutable');
+ $c->reply->static($relFilePath);
+ }
+ );
+
# Normal route to controller
$public_routes->get('/login')->to('login#index');
$public_routes->post('/login')->to('login#check');
diff --git a/public/js/backup.js b/public/js/backup.js
index 894dcd2ef..e2d6c08ba 100644
--- a/public/js/backup.js
+++ b/public/js/backup.js
@@ -1,8 +1,8 @@
/**
* Backup Operations
*/
-import * as Server from "mod/server";
-import * as LRR from "mod/common";
+import * as Server from "./mod/server.js";
+import * as LRR from "./mod/common.js";
import I18N from "i18n";
let currentJob = null;
diff --git a/public/js/batch.js b/public/js/batch.js
index 5dfdc1f93..8c6fd0cb4 100644
--- a/public/js/batch.js
+++ b/public/js/batch.js
@@ -1,8 +1,8 @@
/**
* Batch Operations
*/
-import * as LRR from "mod/common";
-import * as Server from "mod/server";
+import * as LRR from "./mod/common.js";
+import * as Server from "./mod/server.js";
import I18N from "i18n";
const Batch = {};
diff --git a/public/js/category.js b/public/js/category.js
index f8f1f6abb..666d6c7fb 100644
--- a/public/js/category.js
+++ b/public/js/category.js
@@ -2,8 +2,8 @@
* Category Operations
*/
-import * as LRR from "mod/common";
-import * as Server from "mod/server";
+import * as LRR from "./mod/common.js";
+import * as Server from "./mod/server.js";
import I18N from "i18n";
const Category = {};
diff --git a/public/js/config.js b/public/js/config.js
index d2c2dd7ac..fcf1eda3c 100644
--- a/public/js/config.js
+++ b/public/js/config.js
@@ -1,8 +1,8 @@
/**
* Config Operations
*/
-import * as Server from "mod/server";
-import * as LRR from "mod/common";
+import * as Server from "./mod/server.js";
+import * as LRR from "./mod/common.js";
import I18N from "i18n";
const Config = {};
diff --git a/public/js/duplicates.js b/public/js/duplicates.js
index bc712adc0..1473b7b34 100644
--- a/public/js/duplicates.js
+++ b/public/js/duplicates.js
@@ -1,8 +1,8 @@
/**
* Duplicate Operations
*/
-import * as LRR from "mod/common";
-import * as Server from "mod/server";
+import * as LRR from "./mod/common.js";
+import * as Server from "./mod/server.js";
import I18N from "i18n";
const Duplicates = {};
diff --git a/public/js/edit.js b/public/js/edit.js
index baae97179..d35c05417 100644
--- a/public/js/edit.js
+++ b/public/js/edit.js
@@ -2,8 +2,8 @@
* JS functions meant for use in the Edit page.
* Mostly dealing with plugins.
*/
-import * as Server from "mod/server";
-import * as LRR from "mod/common";
+import * as Server from "./mod/server.js";
+import * as LRR from "./mod/common.js";
import I18N from "i18n";
const Edit = {};
diff --git a/public/js/logs.js b/public/js/logs.js
index 4ec3061ae..9d044c245 100644
--- a/public/js/logs.js
+++ b/public/js/logs.js
@@ -1,7 +1,7 @@
/**
* Logs Operations
*/
-import * as LRR from "mod/common";
+import * as LRR from "./mod/common.js";
import I18N from "i18n";
const Logs = {};
diff --git a/public/js/mod/common.js b/public/js/mod/common.js
index 9550288c5..d81b92f10 100644
--- a/public/js/mod/common.js
+++ b/public/js/mod/common.js
@@ -5,9 +5,9 @@ import { createElement, render } from "preact";
import Swal from "sweetalert2";
import { ToastContainer, toast as emitToast } from "react-toastify";
-import * as Index from "mod/index";
-import * as Server from "mod/server";
-import * as IndexTable from "mod/index_datatables";
+import * as Index from "./index.js";
+import * as Server from "./server.js";
+import * as IndexTable from "./index_datatables.js";
import I18N from "i18n";
let toastsInitialized = false;
diff --git a/public/js/mod/index.js b/public/js/mod/index.js
index c4ef0a142..f166e7f76 100644
--- a/public/js/mod/index.js
+++ b/public/js/mod/index.js
@@ -2,9 +2,9 @@
* Non-DataTables Index functions.
* (The split is there to permit easier switch if we ever yeet datatables from the main UI)
*/
-import * as LRR from "mod/common";
-import * as Server from "mod/server";
-import * as IndexTable from "mod/index_datatables";
+import * as LRR from "./common.js";
+import * as Server from "./server.js";
+import * as IndexTable from "./index_datatables.js";
import I18N from "i18n";
import * as marked from "marked";
import DOMPurify from "dompurify";
diff --git a/public/js/mod/index_datatables.js b/public/js/mod/index_datatables.js
index 636b762d0..82d8ed2bd 100644
--- a/public/js/mod/index_datatables.js
+++ b/public/js/mod/index_datatables.js
@@ -1,8 +1,8 @@
/**
* All the Archive Index functions related to DataTables.
*/
-import * as LRR from "mod/common";
-import * as Index from "mod/index";
+import * as LRR from "./common.js";
+import * as Index from "./index.js";
import I18N from "i18n";
export let dataTable = {};
diff --git a/public/js/mod/server.js b/public/js/mod/server.js
index 0a16eab0a..b3c5299e5 100644
--- a/public/js/mod/server.js
+++ b/public/js/mod/server.js
@@ -1,7 +1,7 @@
/**
* Functions for Generic API calls.
*/
-import * as LRR from "mod/common";
+import * as LRR from "./common.js";
import I18N from "i18n";
let isScriptRunning = false;
diff --git a/public/js/plugins.js b/public/js/plugins.js
index 99efb5dfd..b127e49a1 100644
--- a/public/js/plugins.js
+++ b/public/js/plugins.js
@@ -1,8 +1,8 @@
/**
* Plugins Operations
*/
-import * as Server from "mod/server";
-import * as LRR from "mod/common";
+import * as Server from "./mod/server.js";
+import * as LRR from "./mod/common.js";
import I18N from "i18n";
const Plugins = {};
diff --git a/public/js/reader.js b/public/js/reader.js
index 21e0de9b0..e95c38207 100644
--- a/public/js/reader.js
+++ b/public/js/reader.js
@@ -2,8 +2,8 @@
* Functions to navigate in reader with the keyboard.
* Also handles the thumbnail archive explorer.
*/
-import * as Server from "mod/server";
-import * as LRR from "mod/common";
+import * as Server from "./mod/server.js";
+import * as LRR from "./mod/common.js";
import I18N from "i18n";
import fscreen from "fscreen";
diff --git a/public/js/stats.js b/public/js/stats.js
index 6428d4c29..4c65dc969 100644
--- a/public/js/stats.js
+++ b/public/js/stats.js
@@ -1,8 +1,8 @@
/**
* Stats Operations
*/
-import * as Server from "mod/server";
-import * as LRR from "mod/common";
+import * as Server from "./mod/server.js";
+import * as LRR from "./mod/common.js";
import I18N from "i18n";
const Stats = {};
diff --git a/public/js/upload.js b/public/js/upload.js
index f900082cd..1b5bb5563 100644
--- a/public/js/upload.js
+++ b/public/js/upload.js
@@ -2,8 +2,8 @@
* Scripting for the Upload page
*/
-import * as LRR from "mod/common";
-import * as Server from "mod/server";
+import * as LRR from "./mod/common.js";
+import * as Server from "./mod/server.js";
import I18N from "i18n";
let processingArchives = 0;
diff --git a/templates/common/importmap.html.tt2 b/templates/common/importmap.html.tt2
index d02bd5755..d469b95ca 100644
--- a/templates/common/importmap.html.tt2
+++ b/templates/common/importmap.html.tt2
@@ -1,26 +1,22 @@
diff --git a/templates/edit.html.tt2 b/templates/edit.html.tt2
index 7205ac413..76bebe7a1 100644
--- a/templates/edit.html.tt2
+++ b/templates/edit.html.tt2
@@ -32,7 +32,7 @@