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
This commit is contained in:
ZhenShuo Leo
2026-02-06 00:46:47 +08:00
parent 0e9a151ce5
commit 99d329c7b0
4 changed files with 170 additions and 246 deletions
+148 -202
View File
@@ -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);