diff --git a/src/App.tsx b/src/App.tsx
index 8b271e5..d07d03f 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -4,7 +4,9 @@ import { AliveScope } from "react-activation";
 import { shortcuts } from "@/global";
 import { Mode, RenderedFunction } from "@/types";
 import Utils from "@/utils/Utils";
-import { Axis } from "./renderer/Graphics";
+import { Axis } from "@/renderer/Graphics";
+
+import usePreloader from "@/hooks/usePreloader";
 
 // Layout
 import "katex/dist/katex.min.css";
@@ -28,6 +30,9 @@ const App: React.FC = () => {
 	const [functionList, setFunctionList] = useState<RenderedFunction[]>([]);
 	const [axis, setAxisType] = useState<Axis>(Axis.CARTESIAN);
 
+	usePreloader(new URL("@/workers/graphing.worker.ts", import.meta.url), "script");
+	usePreloader(new URL("@/workers/calculating.worker.ts", import.meta.url), "script");
+
 	useEffect(() => {
 		document.body.addEventListener("keydown", (e: KeyboardEvent) => {
 			shortcuts.forEach((shortcut, key) => {
diff --git a/src/hooks/usePreloader.ts b/src/hooks/usePreloader.ts
new file mode 100644
index 0000000..6a7ed1c
--- /dev/null
+++ b/src/hooks/usePreloader.ts
@@ -0,0 +1,16 @@
+/* eslint-disable react-hooks/exhaustive-deps */
+import { useEffect } from "react";
+
+type PreloadType = "fetch" | "font" | "image" | "script" | "style" | "track";
+
+export default function usePreloader(target: string | URL, as: PreloadType = "image") {
+    useEffect(() => {
+        var preloadElem = document.createElement("link");
+        preloadElem.rel = "preload";
+        typeof target === "string"
+        ? preloadElem.href = target
+        : preloadElem.href = target.href;
+        preloadElem.as = as;
+        document.head.appendChild(preloadElem);
+    }, []);
+}