From 99d329c7b08b1bd1ca6c393cd5553280bce40793 Mon Sep 17 00:00:00 2001
From: ZhenShuo Leo <98386542+ZhenShuo2021@users.noreply.github.com>
Date: Fri, 6 Feb 2026 00:46:47 +0800
Subject: [PATCH] feat: reduce firebase blocking time
- use esm format
- defer loading with type="module"
- upgrade from v8.10.0 to v9.23.0
- allow homepage/taxonomy/term log
---
assets/js/button-likes.js | 4 -
assets/js/firebase.js | 350 +++++++++++++++--------------------
layouts/partials/head.html | 1 -
layouts/partials/vendor.html | 61 +++---
4 files changed, 170 insertions(+), 246 deletions(-)
delete mode 100644 assets/js/button-likes.js
diff --git a/assets/js/button-likes.js b/assets/js/button-likes.js
deleted file mode 100644
index 2ffc71be..00000000
--- a/assets/js/button-likes.js
+++ /dev/null
@@ -1,4 +0,0 @@
-document.getElementById("button_likes") &&
- document.getElementById("button_likes").addEventListener("click", () => {
- process_article();
- });
diff --git a/assets/js/firebase.js b/assets/js/firebase.js
index fb97bdd3..82550aa5 100644
--- a/assets/js/firebase.js
+++ b/assets/js/firebase.js
@@ -1,208 +1,154 @@
-const pageScriptElement = document.currentScript;
-const configEl = document.getElementById("firebase-config");
+import { initializeApp } from "https://www.gstatic.com/firebasejs/9.23.0/firebase-app.js";
+import {
+ getFirestore,
+ doc,
+ getDoc,
+ setDoc,
+ updateDoc,
+ increment,
+ onSnapshot,
+} from "https://www.gstatic.com/firebasejs/9.23.0/firebase-firestore.js";
+import { getAuth, signInAnonymously } from "https://www.gstatic.com/firebasejs/9.23.0/firebase-auth.js";
+
+let app, db, auth, oids;
+try {
+ const configEl = document.getElementById("firebase-config");
+ if (!configEl?.textContent) {
+ throw new Error("Firebase config element not found");
+ }
-if (!configEl?.textContent) {
- console.error("Firebase config element not found");
- document
- .querySelectorAll(
- '[id^="views_"], [id^="likes_"], #button_likes_heart, #button_likes_emtpty_heart, #button_likes_text',
- )
- .forEach((el) => el.remove());
-} else {
const data = JSON.parse(configEl.textContent);
- const oid = data.oids?.views;
- const oid_likes = data.oids?.likes;
+ app = initializeApp(data.config);
- let liked_page = false;
- const id = oid ? oid.replaceAll("/", "-") : oid;
- const id_likes = oid_likes ? oid_likes.replaceAll("/", "-") : oid_likes;
-
- function numberWithCommas(x) {
- return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
- }
-
- function toggleLoaders(node) {
- var classesString = node.className;
- if (classesString == "") return;
- var classes = classesString.split(" ");
- for (var i in classes) {
- node.classList.toggle(classes[i]);
- }
- }
-
- var update_views = function (node, id) {
- db.collection("views")
- .doc(id)
- .onSnapshot((doc) => {
- var data = doc.data();
- if (data) {
- node.innerText = numberWithCommas(data.views);
- } else {
- node.innerText = 0;
- }
- toggleLoaders(node);
- });
+ oids = {
+ views: configEl.getAttribute("data-views"),
+ likes: configEl.getAttribute("data-likes"),
};
- var update_likes = function (node, id) {
- db.collection("likes")
- .doc(id)
- .onSnapshot((doc) => {
- var data = doc.data();
- if (data) {
- node.innerText = numberWithCommas(data.likes);
- } else {
- node.innerText = 0;
- }
- toggleLoaders(node);
- });
- };
-
- if (typeof auth !== "undefined") {
- const viewed = localStorage.getItem(id);
-
- if (!viewed && id) {
- auth
- .signInAnonymously()
- .then(() => {
- const docRef = db.collection("views").doc(id);
- localStorage.setItem(id, true);
- docRef
- .get()
- .then((doc) => {
- if (doc.exists) {
- db.collection("views")
- .doc(id)
- .update({
- views: firebase.firestore.FieldValue.increment(1),
- });
- } else {
- db.collection("views").doc(id).set({ views: 1 });
- }
- })
- .catch((error) => {
- console.log("Error getting document:", error);
- });
- })
- .catch((error) => {
- const errorCode = error.code;
- const errorMessage = error.message;
- console.error(errorCode, errorMessage);
- });
- }
-
- const liked = localStorage.getItem(id_likes);
-
- if (liked) {
- liked_page = true;
- document.querySelectorAll("span[id='button_likes_heart']")[0].style.display = "";
- document.querySelectorAll("span[id='button_likes_emtpty_heart']")[0].style.display = "none";
- document.querySelectorAll("span[id='button_likes_text']")[0].innerText = "";
- }
-
- auth
- .signInAnonymously()
- .then(() => {
- var views_nodes = document.querySelectorAll("span[id^='views_']");
-
- for (var i in views_nodes) {
- var node = views_nodes[i];
- var id = node.id ? node.id.replaceAll("/", "-") : node.id;
- if (id) {
- update_views(node, id);
- }
- }
-
- var likes_nodes = document.querySelectorAll("span[id^='likes_']");
-
- for (var i in likes_nodes) {
- var node = likes_nodes[i];
- var id = node.id ? node.id.replaceAll("/", "-") : node.id;
- if (id) {
- update_likes(node, id);
- }
- }
- })
- .catch((error) => {
- var errorCode = error.code;
- var errorMessage = error.message;
- console.error(errorCode, errorMessage);
- });
- }
-
- function like_article(id_likes) {
- auth
- .signInAnonymously()
- .then(() => {
- const docRef = db.collection("likes").doc(id_likes);
- docRef
- .get()
- .then((doc) => {
- liked_page = true;
- localStorage.setItem(id_likes, true);
- document.querySelectorAll("span[id='button_likes_heart']")[0].style.display = "";
- document.querySelectorAll("span[id='button_likes_emtpty_heart']")[0].style.display = "none";
- document.querySelectorAll("span[id='button_likes_text']")[0].innerText = "";
- if (doc.exists) {
- db.collection("likes")
- .doc(id_likes)
- .update({
- likes: firebase.firestore.FieldValue.increment(1),
- });
- } else {
- db.collection("likes").doc(id_likes).set({ likes: 1 });
- }
- })
- .catch((error) => {
- console.log("Error getting document:", error);
- });
- })
- .catch((error) => {
- const errorCode = error.code;
- const errorMessage = error.message;
- console.error(errorCode, errorMessage);
- });
- }
-
- function remove_like_article(id_likes) {
- auth
- .signInAnonymously()
- .then(() => {
- const docRef = db.collection("likes").doc(id_likes);
- docRef
- .get()
- .then((doc) => {
- liked_page = false;
- localStorage.removeItem(id_likes);
- document.querySelectorAll("span[id='button_likes_heart']")[0].style.display = "none";
- document.querySelectorAll("span[id='button_likes_emtpty_heart']")[0].style.display = "";
- document.querySelectorAll("span[id='button_likes_text']")[0].innerText = "\xa0Like";
- if (doc.exists) {
- db.collection("likes")
- .doc(id_likes)
- .update({
- likes: firebase.firestore.FieldValue.increment(-1),
- });
- } else {
- db.collection("likes").doc(id_likes).set({ likes: 0 });
- }
- })
- .catch((error) => {
- console.log("Error getting document:", error);
- });
- })
- .catch((error) => {
- const errorCode = error.code;
- const errorMessage = error.message;
- console.error(errorCode, errorMessage);
- });
- }
-
- window.process_article = function () {
- if (!liked_page) {
- like_article(id_likes);
- } else {
- remove_like_article(id_likes);
- }
- };
+ db = getFirestore(app);
+ auth = getAuth(app);
+} catch (e) {
+ console.error("Firebase initialization failed:", e.message);
+ throw e;
}
+
+const id = oids?.views?.replaceAll("/", "-");
+const id_likes = oids?.likes?.replaceAll("/", "-");
+let liked = false;
+let authReady = false;
+
+function formatNumber(n) {
+ return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
+}
+
+function toggleLoaders(node) {
+ var classesString = node.className;
+ if (classesString == "") return;
+ var classes = classesString.split(" ");
+ for (var i in classes) {
+ node.classList.toggle(classes[i]);
+ }
+}
+
+function updateDisplay(collection, nodeId) {
+ const node = document.getElementById(nodeId);
+ if (!node) return;
+
+ const docId = nodeId.replaceAll("/", "-");
+ onSnapshot(
+ doc(db, collection, docId),
+ (snapshot) => {
+ node.innerText = snapshot.exists() ? formatNumber(snapshot.data()[collection]) : 0;
+ toggleLoaders(node);
+ },
+ (error) => {
+ console.error("Firebase snapshot update failed:", error);
+ },
+ );
+}
+
+async function recordView(id) {
+ if (!id || localStorage.getItem(id)) return;
+
+ try {
+ const ref = doc(db, "views", id);
+ const snap = await getDoc(ref);
+
+ snap.exists() ? await updateDoc(ref, { views: increment(1) }) : await setDoc(ref, { views: 1 });
+
+ localStorage.setItem(id, true);
+ } catch (e) {
+ console.error("Record view operation failed:", e.message);
+ }
+}
+
+function updateButton(isLiked) {
+ const hearts = document.querySelectorAll("span[id='button_likes_heart']");
+ const empties = document.querySelectorAll("span[id='button_likes_emtpty_heart']");
+ const texts = document.querySelectorAll("span[id='button_likes_text']");
+
+ hearts.forEach((el) => {
+ el.style.display = isLiked ? "" : "none";
+ });
+ empties.forEach((el) => {
+ el.style.display = isLiked ? "none" : "";
+ });
+ texts.forEach((el) => {
+ el.innerText = isLiked ? "" : "\xa0Like";
+ });
+}
+
+async function toggleLike(add) {
+ if (!id_likes || !authReady) return;
+
+ try {
+ const ref = doc(db, "likes", id_likes);
+ const snap = await getDoc(ref);
+
+ liked = add;
+ add ? localStorage.setItem(id_likes, true) : localStorage.removeItem(id_likes);
+ updateButton(add);
+
+ snap.exists()
+ ? await updateDoc(ref, { likes: increment(add ? 1 : -1) })
+ : await setDoc(ref, { likes: add ? 1 : 0 });
+ } catch (e) {
+ console.error("Like operation failed:", e.message);
+ liked = !add;
+ add ? localStorage.removeItem(id_likes) : localStorage.setItem(id_likes, true);
+ updateButton(!add);
+ }
+}
+
+signInAnonymously(auth)
+ .then(() => {
+ authReady = true;
+
+ document.querySelectorAll("span[id^='views_']").forEach((node) => {
+ if (node.id) updateDisplay("views", node.id);
+ });
+
+ document.querySelectorAll("span[id^='likes_']").forEach((node) => {
+ if (node.id) updateDisplay("likes", node.id);
+ });
+
+ recordView(id);
+
+ if (id_likes && localStorage.getItem(id_likes)) {
+ liked = true;
+ updateButton(true);
+ }
+
+ const likeButton = document.getElementById("button_likes");
+ if (likeButton) {
+ likeButton.addEventListener("click", () => {
+ toggleLike(!liked);
+ });
+ }
+ })
+ .catch((error) => {
+ console.error("Firebase anonymous sign-in failed:", error.message);
+ authReady = false;
+ });
+
+window.process_article = () => toggleLike(!liked);
diff --git a/layouts/partials/head.html b/layouts/partials/head.html
index c7d4ccc0..0652e82c 100644
--- a/layouts/partials/head.html
+++ b/layouts/partials/head.html
@@ -154,7 +154,6 @@
{{ if .Site.Params.rtl | default false }}
{{ $jsResources = $jsResources | append (resources.Get "js/rtl.js") }}
{{ end }}
- {{ $jsResources = $jsResources | append (resources.Get "js/button-likes.js") }}
{{ $jsResources = $jsResources | append (resources.Get "js/katex-render.js") }}
{{ $jsResources = $jsResources | append (resources.Get "js/print-support.js") }}
{{ if $jsResources }}
diff --git a/layouts/partials/vendor.html b/layouts/partials/vendor.html
index 7c4e9601..bb929306 100644
--- a/layouts/partials/vendor.html
+++ b/layouts/partials/vendor.html
@@ -154,7 +154,12 @@
{{ end }}
{{ end }}
+{{/* Firebase */}}
{{ if site.Params.firebase.apiKey }}
+ {{ $firebase := resources.Get "js/firebase.js" }}
+ {{ $firebase = $firebase | resources.Minify | resources.Fingerprint (site.Params.fingerprintAlgorithm | default "sha512") }}
+
+
{{ if in (slice "page" "section") .Kind }}
{{ $translations := .AllTranslations }}
{{ with .File }}
@@ -169,48 +174,26 @@
{{ else if eq .Kind "taxonomy" }}
{{ partial "inline/firebase-config.html" (dict "views" (printf "views_taxonomy_%s" .Data.Plural) "likes" (printf "likes_taxonomy_%s" .Data.Plural)) }}
{{ else if eq .Kind "home" }}
- {{ partial "inline/firebase-config.html" (dict "views" (printf "views_home") "likes" (printf "likes_home")) }}
+ {{ partial "inline/firebase-config.html" (dict "views" "views_home" "likes" "likes_home") }}
{{ end }}
-
-
-
-
- {{/* */}}
- {{ $firebase := resources.Get "js/firebase.js" }}
- {{ $firebase = $firebase | resources.Minify | resources.Fingerprint (site.Params.fingerprintAlgorithm | default "sha512") }}
-
{{ end }}
-{{ define "partials/inline/firebase-config.html" }}
-
+ }
+
{{ end }}